diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..4c233250ae --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +* @ahadas +mucommander-viewer-binary/ @ahadas @hajdam +mucommander-viewer-text/ @ahadas @pskowronek diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 0000000000..34612ec40d --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,207 @@ +name: Nightly Build + +on: + schedule: + - cron: '0 0 * * *' + workflow_dispatch: + +jobs: + create-release: + + runs-on: ubuntu-latest + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + release_id: ${{ steps.create_release.outputs.id }} + version: ${{ steps.mucommander_version.outputs.VERSION }} + full_version: ${{ steps.mucommander_version.outputs.FULL_VERSION }} + + steps: + - name: Remove previous tag and release + uses: dev-drprasad/delete-tag-and-release@v0.2.0 + with: + delete_release: true + tag_name: nightly + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/checkout@v3 + + - name : Get version + id: mucommander_version + run: | + echo "FULL_VERSION=$(${{github.workspace}}/gradlew -q printFullVersionName)" >> $GITHUB_OUTPUT + echo "VERSION=$(${{github.workspace}}/gradlew -q printVersionName)" >> $GITHUB_OUTPUT + + - name: Create a new release + uses: softprops/action-gh-release@v1 + id: create_release + with: + name: Nightly + tag_name: nightly + prerelease: true + draft: true + body: "Snapshot of v${{ steps.mucommander_version.outputs.VERSION }}" + + upload-macos-artifacts: + + runs-on: macos-latest + needs: create-release + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Checkout 'release' + uses: actions/checkout@v3 + with: + repository: mucommander/release + path: release + token: ${{ secrets.RELEASE_REPO_TOKEN }} + + - name: Apply 'release' patches + run: | + git config --global user.name gh-action + git config --global user.email gh-action + git am release/0001-set-credentials-to-Google-Drive.patch + git am release/0002-set-credentials-to-Dropbox.patch + + - uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' + + - name: Build dmg + uses: gradle/gradle-build-action@v2 + with: + arguments: dmg + + - name: Upload dmg + uses: shogo82148/actions-upload-release-asset@v1 + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: "./build/distributions/mucommander-${{ needs.create-release.outputs.full_version }}.dmg" + asset_name: mucommander-snapshot.dmg + asset_content_type: application/octet-stream + + upload-linux-artifacts: + + runs-on: ubuntu-latest + needs: create-release + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' + + - name: Checkout 'release' + uses: actions/checkout@v3 + with: + repository: mucommander/release + path: release + token: ${{ secrets.RELEASE_REPO_TOKEN }} + + - name: Apply 'release' patches + run: | + git config --global user.name gh-action + git config --global user.email gh-action + git am release/0001-set-credentials-to-Google-Drive.patch + git am release/0002-set-credentials-to-Dropbox.patch + + - name: Build portable, tgz, deb, and rpm + uses: gradle/gradle-build-action@v2 + with: + arguments: tgz portable deb rpm + + - name: Upload portable + uses: shogo82148/actions-upload-release-asset@v1 + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: "./build/distributions/mucommander-${{ needs.create-release.outputs.full_version }}-portable.zip" + asset_name: mucommander-snapshot-portable.zip + asset_content_type: application/zip + + - name: Upload tgz + uses: shogo82148/actions-upload-release-asset@v1 + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: "./build/distributions/mucommander-${{ needs.create-release.outputs.full_version }}.tgz" + asset_name: mucommander-snapshot.tgz + asset_content_type: application/gzip + + - name: Upload deb + uses: shogo82148/actions-upload-release-asset@v1 + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: "./build/distributions/mucommander_${{ needs.create-release.outputs.version }}-1_amd64.deb" + asset_name: mucommander-snapshot_amd64.deb + asset_content_type: application/octet-stream + + - name: Upload rpm + uses: shogo82148/actions-upload-release-asset@v1 + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: "./build/distributions/mucommander-${{ needs.create-release.outputs.version }}-1.x86_64.rpm" + asset_name: mucommander-snapshot.x86_64.rpm + asset_content_type: application/octet-stream + + + upload-windows-artifacts: + + runs-on: windows-latest + needs: create-release + + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' + + - name: Checkout 'release' + uses: actions/checkout@v3 + with: + repository: mucommander/release + path: release + token: ${{ secrets.RELEASE_REPO_TOKEN }} + + - name: Apply 'release' patches + run: | + git config --global user.name gh-action + git config --global user.email gh-action + git am release/0001-set-credentials-to-Google-Drive.patch + git am release/0002-set-credentials-to-Dropbox.patch + + - name: Build msi + uses: gradle/gradle-build-action@v2 + with: + arguments: msi + + - name: Upload msi + uses: shogo82148/actions-upload-release-asset@v1 + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: "./build/distributions/mucommander-${{ needs.create-release.outputs.version }}.msi" + asset_name: mucommander-snapshot.msi + asset_content_type: application/octet-stream + + publish-release: + + runs-on: ubuntu-latest + needs: [ create-release, upload-linux-artifacts, upload-macos-artifacts, upload-windows-artifacts ] + + steps: + - name: Publish the new release + uses: eregon/publish-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + release_id: ${{ needs.create-release.outputs.release_id }} diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000000..c9cb0f0978 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,19 @@ +name: Tests + +on: [pull_request, workflow_dispatch] + +jobs: + unit-tests: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'adopt' + - uses: gradle/wrapper-validation-action@v1 + - uses: gradle/gradle-build-action@v2 + with: + arguments: test diff --git a/LICENSE b/LICENSE index f3ac4097a9..1ee30bea2a 100644 --- a/LICENSE +++ b/LICENSE @@ -19,9 +19,11 @@ Additionally, muCommander uses the following third party works: - the J7Zip library under the terms of the GNU Lesser General Public License - the jCIFS library under the terms of the GNU Lesser General Public License - the JetS3t library under the terms of the Apache License +- the JediTerm library under the terms of dual GNU Lesser General Public License and Apache License - the JmDNS library under the terms of the GNU Lesser General Public License - the JNA library under the terms of the GNU Lesser General Public License - the JUnRar library under the terms of the GNU Lesser General Public License +- the RSyntaxTextArea library under the terms of BSD 3-Clause "New" or "Revised" License - the Yanfs library under the terms of the Berkeley Software Distribution License - the JCommander library under the terms of the Apache License - the ICEpdf library under the terms of the Apache License diff --git a/README.md b/README.md index 49a576e1cf..5367c4e036 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # muCommander -[![Version](http://img.shields.io/badge/version-1.1.0-blue.svg?style=flat)](https://github.com/mucommander/mucommander/releases/tag/nightly) +[![Version](http://img.shields.io/badge/version-1.2.0-blue.svg?style=flat)](https://github.com/mucommander/mucommander/releases/tag/nightly) [![License](http://img.shields.io/badge/License-GPL-blue.svg)](http://www.gnu.org/copyleft/gpl.html) [![Build Status](https://travis-ci.org/mucommander/mucommander.svg)](https://travis-ci.org/mucommander/mucommander) [![Coverity Scan](https://scan.coverity.com/projects/3642/badge.svg)](https://scan.coverity.com/projects/3642) diff --git a/apache-bzip2/build.gradle b/apache-bzip2/build.gradle index ed02d76674..b6697b70b9 100644 --- a/apache-bzip2/build.gradle +++ b/apache-bzip2/build.gradle @@ -14,6 +14,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/build.gradle b/build.gradle index 6ef16bcf69..ea1b925df2 100644 --- a/build.gradle +++ b/build.gradle @@ -3,15 +3,15 @@ buildscript { mavenCentral() } dependencies { - classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:6.1.0' + classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:6.4.0' } } plugins { id 'com.athaydes.osgi-run' version '1.6.0' id 'java' - id 'org.ajoberstar.grgit' version '3.1.1' - id 'edu.sc.seis.launch4j' version '2.5.3' + id 'org.ajoberstar.grgit' version '5.0.0' + id 'edu.sc.seis.launch4j' version '2.5.4' } allprojects { @@ -20,13 +20,21 @@ allprojects { } group = 'org.mucommander' - version = '1.1.0' - ext.release = 'snapshot' + version = '1.2.0' + ext.release = '1' configurations { compileOnly.extendsFrom comprise } } +task printFullVersionName { + doLast { println project.version + '-' + project.ext.release } +} + +task printVersionName { + doLast { println project.version } +} + repositories.mavenCentral() subprojects { @@ -37,7 +45,7 @@ subprojects { compileTestJava.options.encoding = 'UTF-8' dependencies { implementation 'org.slf4j:slf4j-api:1.7.36' - implementation 'org.osgi:osgi.core:7.0.0' + implementation 'org.osgi:osgi.core:8.0.0' } } @@ -46,9 +54,9 @@ compileTestJava.options.encoding = 'UTF-8' compileJava.options.compilerArgs += ['--release', '11'] dependencies { - comprise 'org.apache.felix:org.apache.felix.main:7.0.3' - comprise 'com.beust:jcommander:1.78' - comprise 'com.formdev:flatlaf:2.2' + comprise 'org.apache.felix:org.apache.felix.main:7.0.5' + comprise 'com.beust:jcommander:1.82' + comprise 'com.formdev:flatlaf:2.6' comprise 'org.violetlib:vaqua:10' osgiRuntime project('mucommander-core') @@ -173,7 +181,7 @@ jar { "Implementation-Vendor": "Arik Hadas", "Implementation-Version": revision.substring(0, 7), "Build-Date": new Date().format('yyyyMMdd'), - "Build-URL": "https://www.mucommander.com/version/nightly.xml") + "Build-URL": "https://www.mucommander.com/version/version.xml") } } diff --git a/jetbrains-jediterm/build.gradle b/jetbrains-jediterm/build.gradle index 0103be3d8c..607b46596e 100644 --- a/jetbrains-jediterm/build.gradle +++ b/jetbrains-jediterm/build.gradle @@ -54,7 +54,7 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml", + 'Build-Url': "https://www.mucommander.com/version/version.xml", 'Import-Package': '!javax.annotation.*,!com.google.appengine*,!com.google.apphosting.*,!kotlin.internal.*,!com.ibm.uvm.tools,!kotlin.reflect.jvm.internal,*', 'Export-Package': 'com.jediterm.terminal,' + diff --git a/mucommander-archiver/build.gradle b/mucommander-archiver/build.gradle index 0f9280e577..3350725485 100644 --- a/mucommander-archiver/build.gradle +++ b/mucommander-archiver/build.gradle @@ -24,6 +24,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-command/build.gradle b/mucommander-command/build.gradle index afb93cdbe4..54989fa47c 100644 --- a/mucommander-command/build.gradle +++ b/mucommander-command/build.gradle @@ -33,6 +33,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-commons-collections/build.gradle b/mucommander-commons-collections/build.gradle index cd3d2599d1..40aa08ac24 100644 --- a/mucommander-commons-collections/build.gradle +++ b/mucommander-commons-collections/build.gradle @@ -17,5 +17,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-commons-conf/build.gradle b/mucommander-commons-conf/build.gradle index ae27b9e446..fb0d8c11b2 100644 --- a/mucommander-commons-conf/build.gradle +++ b/mucommander-commons-conf/build.gradle @@ -17,5 +17,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-commons-conf/src/main/java/com/mucommander/commons/conf/Configuration.java b/mucommander-commons-conf/src/main/java/com/mucommander/commons/conf/Configuration.java index 901913a006..1e40094667 100644 --- a/mucommander-commons-conf/src/main/java/com/mucommander/commons/conf/Configuration.java +++ b/mucommander-commons-conf/src/main/java/com/mucommander/commons/conf/Configuration.java @@ -216,7 +216,7 @@ public void setReaderFactory(ConfigurationReaderFactory f) { */ public ConfigurationReaderFactory getReaderFactory() { synchronized(readerLock) { - if(readerFactory == null) + if (readerFactory == null) return XmlConfigurationReader.FACTORY; return readerFactory; } @@ -250,7 +250,7 @@ public void setWriterFactory(ConfigurationWriterFactory f) { */ public ConfigurationWriterFactory getWriterFactory() { synchronized(writerLock) { - if(writerFactory == null) + if (writerFactory == null) return XmlConfigurationWriter.FACTORY; return writerFactory; } @@ -336,19 +336,17 @@ public void read(Reader in) throws ConfigurationException, IOException { * @see #read(Reader,ConfigurationReader) */ public void read(ConfigurationReader reader) throws IOException, ConfigurationException { - Reader in; // Input stream on the configuration source. - ConfigurationSource source; // Configuration source. - - in = null; + Reader in = null; // Input stream on the configuration source. + ConfigurationSource source = getSource(); // Makes sure the configuration source has been properly set. - if((source = getSource()) == null) + if (source == null) throw new SourceConfigurationException("Configuration source hasn't been set."); // Reads the configuration data. try {read(in = source.getReader(), reader);} finally { - if(in != null) { + if (in != null) { try {in.close();} catch(Exception e) {} } @@ -417,19 +415,17 @@ public void write(Writer out) throws ConfigurationException { * @see #write() */ public void write() throws IOException, ConfigurationException { - Writer out; // Where to write the configuration data. - ConfigurationSource source; // Configuration source. - - out = null; + Writer out = null; // Where to write the configuration data. + ConfigurationSource source = getSource(); // Makes sure the source has been set. - if((source = getSource()) == null) + if (source == null) throw new SourceConfigurationException("No configuration source has been set"); // Writes the configuration data. try {write(out = source.getWriter());} finally { - if(out != null) { + if (out != null) { try {out.close();} catch(Exception e) { // Ignores errors here, nothing we can do about them. @@ -460,23 +456,21 @@ public void write(ConfigurationBuilder builder) throws ConfigurationException { * @throws ConfigurationException if any error occurs. */ private synchronized void build(ConfigurationBuilder builder, ConfigurationSection root) throws ConfigurationException { - Iterator enumeration; // Enumeration on the section's variables, then subsections. - String name; // Name of the current variable, then section. - ConfigurationSection section; // Current section. + String name; // Name of the current variable, then section. // Explores the section's variables. - enumeration = root.variableNames(); - while(enumeration.hasNext()) + Iterator enumeration = root.variableNames(); + while (enumeration.hasNext()) builder.addVariable(name = enumeration.next(), root.getVariable(name)); // Explores the section's subsections. enumeration = root.sectionNames(); - while(enumeration.hasNext()) { - name = enumeration.next(); - section = root.getSection(name); + while (enumeration.hasNext()) { + name = enumeration.next(); + ConfigurationSection section = root.getSection(name); // We only go through subsections if contain either variables or subsections of their own. - if(section.hasSections() || section.hasVariables()) { + if (section.hasSections() || section.hasVariables()) { builder.startSection(name); build(builder, section); builder.endSection(name); @@ -529,14 +523,13 @@ public void renameVariable(String fromVar, String toVar) { * @see #getVariable(String,String) */ public synchronized boolean setVariable(String name, String value) { - ConfigurationExplorer explorer; // Used to navigate to the variable's parent section. - String buffer; // Buffer for the variable's name trimmed of section information. + ConfigurationExplorer explorer = new ConfigurationExplorer(root); // Moves to the parent section. - buffer = moveToParent(explorer = new ConfigurationExplorer(root), name, true); + String buffer = moveToParent(explorer, name, true); // If the variable's value was actually modified, triggers an event. - if(explorer.getSection().setVariable(buffer, value)) { + if (explorer.getSection().setVariable(buffer, value)) { triggerEvent(new ConfigurationEvent(this, name, value)); return true; } @@ -684,10 +677,10 @@ public boolean setVariable(String name, long value) { * @see #getVariable(String,String) */ public synchronized String getVariable(String name) { - ConfigurationExplorer explorer; // Used to navigate to the variable's parent section. + ConfigurationExplorer explorer = new ConfigurationExplorer(root); // If the variable's 'path' doesn't exist, return null. - if((name = moveToParent(explorer = new ConfigurationExplorer(root), name, false)) == null) + if ((name = moveToParent(explorer, name, false)) == null) return null; return explorer.getSection().getVariable(name); } @@ -781,20 +774,17 @@ public boolean isVariableSet(String name) { * @param explorer used to backtrack through the configuration tree. */ private void prune(BufferedConfigurationExplorer explorer) { - ConfigurationSection current; - ConfigurationSection parent; - // If we're at the root level, nothing to prune. - if(!explorer.hasSections()) + if (!explorer.hasSections()) return; - current = explorer.popSection(); + ConfigurationSection current = explorer.popSection(); // Look for branches to prune until we've either found a non-empty one // or reached the root of the three. - while(current.isEmpty() && current != root) { + while (current.isEmpty() && current != root) { // Gets the current section's parent and prune. - parent = explorer.hasSections() ? explorer.popSection() : root; + ConfigurationSection parent = explorer.hasSections() ? explorer.popSection() : root; parent.removeSection(current); current = parent; } @@ -810,15 +800,15 @@ private void prune(BufferedConfigurationExplorer explorer) { * @return the variable's old value, or null if it wasn't set. */ public synchronized String removeVariable(String name) { - BufferedConfigurationExplorer explorer; // Used to navigate to the variable's parent section. - String buffer; // Buffer for the variable's name trimmed of section information. + BufferedConfigurationExplorer explorer = new BufferedConfigurationExplorer(root); + String buffer = moveToParent(explorer , name, false); // If the variable's 'path' doesn't exist, return null. - if((buffer = moveToParent(explorer = new BufferedConfigurationExplorer(root), name, false)) == null) + if (buffer == null) return null; // If the variable was actually set, triggers an event. - if((buffer = explorer.getSection().removeVariable(buffer)) != null) { + if ((buffer = explorer.getSection().removeVariable(buffer)) != null) { prune(explorer); triggerEvent(new ConfigurationEvent(this, name, null)); } @@ -929,16 +919,17 @@ public void clear() { * @see #getVariable(String) */ public synchronized String getVariable(String name, String defaultValue) { - ConfigurationExplorer explorer; // Used to navigate to the variable's parent section. - String value; // Buffer for the variable's value. - String buffer; // Buffer for the variable's name trimmed of section information. + // Used to navigate to the variable's parent section. + ConfigurationExplorer explorer = new ConfigurationExplorer(root); // Navigates to the parent section. We do not have to check for null values here, // as the section will be created if it doesn't exist. - buffer = moveToParent(explorer = new ConfigurationExplorer(root), name, true); + String buffer = moveToParent(explorer, name, true); + // Buffer for the variable's value. + String value = explorer.getSection().getVariable(buffer); // If the variable isn't set, set it to defaultValue and triggers an event. - if((value = explorer.getSection().getVariable(buffer)) == null) { + if (value == null) { explorer.getSection().setVariable(buffer, defaultValue); triggerEvent(new ConfigurationEvent(this, name, defaultValue)); return defaultValue; diff --git a/mucommander-commons-file/build.gradle b/mucommander-commons-file/build.gradle index 63310cdbd1..7a6a360e0e 100644 --- a/mucommander-commons-file/build.gradle +++ b/mucommander-commons-file/build.gradle @@ -56,6 +56,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-commons-file/src/main/java/com/mucommander/commons/file/FileFactory.java b/mucommander-commons-file/src/main/java/com/mucommander/commons/file/FileFactory.java index deb187a694..75a097a54e 100644 --- a/mucommander-commons-file/src/main/java/com/mucommander/commons/file/FileFactory.java +++ b/mucommander-commons-file/src/main/java/com/mucommander/commons/file/FileFactory.java @@ -489,8 +489,9 @@ public static AbstractFile getFile(FileURL fileURL, AbstractFile parent, Authent currentFile = filePool.get(clonedURL); if (currentFile==null) { currentFile = wrapArchive(createRawFile(clonedURL, authenticator, instantiationParams)); - // Add the intermediate file instance to the cache - filePool.put(clonedURL, currentFile); + // Add the intermediate file instance to the cache if it exists + if (currentFile.exists()) + filePool.put(clonedURL, currentFile); } lastFileResolved = true; diff --git a/mucommander-commons-file/src/main/java/com/mucommander/commons/file/archive/AbstractArchiveFile.java b/mucommander-commons-file/src/main/java/com/mucommander/commons/file/archive/AbstractArchiveFile.java index 69653f92ea..c9575d7bc0 100644 --- a/mucommander-commons-file/src/main/java/com/mucommander/commons/file/archive/AbstractArchiveFile.java +++ b/mucommander-commons-file/src/main/java/com/mucommander/commons/file/archive/AbstractArchiveFile.java @@ -93,6 +93,9 @@ public abstract class AbstractArchiveFile extends ProxyFile { * need to be reloaded */ protected long entryTreeDate; + /** The password to use for a password-protected archive */ + protected String password; + /** Caches {@link AbstractArchiveEntryFile} instances so that there is only one AbstractArchiveEntryFile * corresponding to the same entry at any given time, to avoid attribute inconsistencies. The key is the * corresponding ArchiveEntry. */ @@ -121,7 +124,7 @@ protected void createEntriesTree() throws IOException, UnsupportedFileOperationE archiveEntryFiles = new WeakHashMap(); long start = System.currentTimeMillis(); - try(ArchiveEntryIterator entries = getEntryIterator()) { + try (ArchiveEntryIterator entries = getEntryIterator()) { ArchiveEntry entry; while((entry=entries.nextEntry())!=null) treeRoot.addArchiveEntry(entry); @@ -142,7 +145,7 @@ protected void createEntriesTree() throws IOException, UnsupportedFileOperationE * underlying file protocol. */ protected void checkEntriesTree() throws IOException, UnsupportedFileOperationException { - if(this.entryTreeRoot==null || getDate()!=this.entryTreeDate) + if (this.entryTreeRoot==null || getDate()!=this.entryTreeDate) createEntriesTree(); } @@ -395,6 +398,14 @@ protected AbstractFile getArchiveEntryFile(DefaultMutableTreeNode entryNode) thr ); } + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + ////////////////////// // Abstract methods // diff --git a/mucommander-commons-file/src/main/java/com/mucommander/commons/file/protocol/local/LocalFile.java b/mucommander-commons-file/src/main/java/com/mucommander/commons/file/protocol/local/LocalFile.java index ae16639084..ba3fcc36ce 100644 --- a/mucommander-commons-file/src/main/java/com/mucommander/commons/file/protocol/local/LocalFile.java +++ b/mucommander-commons-file/src/main/java/com/mucommander/commons/file/protocol/local/LocalFile.java @@ -30,10 +30,11 @@ import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; +import java.util.Arrays; import java.util.Collections; import java.util.StringTokenizer; import java.util.Vector; @@ -68,7 +69,6 @@ import com.mucommander.commons.io.RandomAccessInputStream; import com.mucommander.commons.io.RandomAccessOutputStream; import com.mucommander.commons.runtime.OsFamily; -import com.mucommander.commons.runtime.OsVersion; /** * LocalFile provides access to files located on a locally-mounted filesystem. Note that despite the class' name, @@ -156,8 +156,8 @@ public class LocalFile extends ProtocolFile { /** * List of known UNIX filesystems. */ - public static final String[] KNOWN_UNIX_FS = { "adfs", "affs", "autofs", "cifs", "coda", "cramfs", - "debugfs", "efs", "ext2", "ext3", "fuseblk", "hfs", "hfsplus", "hpfs", + public static final String[] KNOWN_UNIX_FS = { "adfs", "affs", "autofs", "btrfs", "cifs", "coda", "cramfs", + "debugfs", "efs", "ext2", "ext3", "ext4", "fuseblk", "hfs", "hfsplus", "hpfs", "iso9660", "jfs", "minix", "msdos", "ncpfs", "nfs", "nfs4", "ntfs", "qnx4", "reiserfs", "smbfs", "udf", "ufs", "usbfs", "vfat", "xfs" }; @@ -288,32 +288,29 @@ public static boolean hasRootDrives() { * @return all local volumes */ public static AbstractFile[] getVolumes() { - Vector volumesV = new Vector(); + Vector volumes = new Vector(); // Add Mac OS X's /Volumes subfolders and not file roots ('/') since Volumes already contains a named link // (like 'Hard drive' or whatever silly name the user gave his primary hard disk) to / if (OsFamily.MAC_OS.isCurrent()) { - addMacOSXVolumes(volumesV); + addMacOSXVolumes(volumes); } else { // Add java.io.File's root folders - addJavaIoFileRoots(volumesV); + addJavaIoFileRoots(volumes); // Add /proc/mounts folders under UNIX-based systems. if (OsFamily.getCurrent().isUnixBased()) - addMountEntries(volumesV); + addMountEntries(volumes); } // Add home folder, if it is not already present in the list AbstractFile homeFolder = getUserHome(); - if (!(homeFolder == null || volumesV.contains(homeFolder))) - volumesV.add(homeFolder); + if (!(homeFolder == null || volumes.contains(homeFolder))) + volumes.add(homeFolder); - addDesktopEntry(volumesV, homeFolder); + addDesktopEntry(volumes, homeFolder); - AbstractFile volumes[] = new AbstractFile[volumesV.size()]; - volumesV.toArray(volumes); - - return volumes; + return volumes.toArray(AbstractFile[]::new); } @Override @@ -326,7 +323,7 @@ public MonitoredFile toMonitoredFile() { //////////////////// /** - * Resolves the root folders returned by {@link File#listRoots()} and adds them to the given Vector. + * Resolves the root folders returned by {@link FileSystem#getRootDirectories()} and adds them to the given Vector. * * @param v * the Vector to add root folders to @@ -336,7 +333,7 @@ private static void addJavaIoFileRoots(Vector v) { // dialog to appear for removable drives such as A:\ if no disk is present. for (Path path : FileSystems.getDefault().getRootDirectories()) try { - v.add(FileFactory.getFile(path.toAbsolutePath().toString(), true)); + v.add(FileFactory.getFile(path.toFile().getAbsolutePath(), true)); } catch (IOException e) { } } @@ -361,15 +358,8 @@ private static void addMountEntries(Vector v) { st.nextToken(); String mountPoint = st.nextToken().replace("\\040", " "); String fsType = st.nextToken(); - boolean knownFS = false; - for (String fs : KNOWN_UNIX_FS) { - if (fs.equals(fsType)) { - // this is really known physical FS - knownFS = true; - break; - } - } - + // check whether this is really a known physical FS + boolean knownFS = Arrays.stream(KNOWN_UNIX_FS).anyMatch(fs -> fs.equals(fsType)); if (knownFS) { AbstractFile file = FileFactory.getFile(mountPoint); if (file != null && !v.contains(file)) diff --git a/mucommander-commons-io/build.gradle b/mucommander-commons-io/build.gradle index 682067d976..22d769dc2a 100644 --- a/mucommander-commons-io/build.gradle +++ b/mucommander-commons-io/build.gradle @@ -30,5 +30,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-commons-io/src/main/java/com/mucommander/commons/io/bom/BOMConstants.java b/mucommander-commons-io/src/main/java/com/mucommander/commons/io/bom/BOMConstants.java index 635c47e9e2..59e7aa7b55 100644 --- a/mucommander-commons-io/src/main/java/com/mucommander/commons/io/bom/BOMConstants.java +++ b/mucommander-commons-io/src/main/java/com/mucommander/commons/io/bom/BOMConstants.java @@ -25,6 +25,10 @@ public interface BOMConstants { /** UTF-8 BOM: EF BB BF */ + /** + * @deprecated BOM is not usually set for UTF-8 - see: https://github.com/mucommander/mucommander/issues/835 + */ + @Deprecated public final static BOM UTF8_BOM = new BOM( new byte[]{(byte)0xEF, (byte)0xBB, (byte)0xBF}, "UTF-8", diff --git a/mucommander-commons-io/src/main/java/com/mucommander/commons/io/bom/BOMWriter.java b/mucommander-commons-io/src/main/java/com/mucommander/commons/io/bom/BOMWriter.java index c45b8cade9..064cac2bf1 100644 --- a/mucommander-commons-io/src/main/java/com/mucommander/commons/io/bom/BOMWriter.java +++ b/mucommander-commons-io/src/main/java/com/mucommander/commons/io/bom/BOMWriter.java @@ -76,8 +76,8 @@ public BOMWriter(OutputStream out, String encoding) throws UnsupportedEncodingEx * subsequently encode characters in the specified encoding. * * @param out the OutputStream to write the encoded data to - * @param bom the byte-order mark to write at the beginning of the stream. * @param encoding character encoding to use for encoding characters. + * @param bom the byte-order mark to write at the beginning of the stream. * @throws UnsupportedEncodingException if the specified encoding is not a character encoding supported by the Java runtime. */ protected BOMWriter(OutputStream out, String encoding, BOM bom) throws UnsupportedEncodingException { diff --git a/mucommander-commons-runtime/build.gradle b/mucommander-commons-runtime/build.gradle index f90bf0b037..a79e1a7832 100644 --- a/mucommander-commons-runtime/build.gradle +++ b/mucommander-commons-runtime/build.gradle @@ -17,6 +17,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-commons-util/build.gradle b/mucommander-commons-util/build.gradle index 862e24acb2..c34b7f303e 100644 --- a/mucommander-commons-util/build.gradle +++ b/mucommander-commons-util/build.gradle @@ -19,5 +19,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-commons-util/src/main/java/com/mucommander/commons/util/ui/spinner/IntEditor.java b/mucommander-commons-util/src/main/java/com/mucommander/commons/util/ui/spinner/IntEditor.java index 3c643ca60c..db3a1548f3 100644 --- a/mucommander-commons-util/src/main/java/com/mucommander/commons/util/ui/spinner/IntEditor.java +++ b/mucommander-commons-util/src/main/java/com/mucommander/commons/util/ui/spinner/IntEditor.java @@ -27,6 +27,7 @@ import javax.swing.JSpinner.NumberEditor; import javax.swing.JTextField; import javax.swing.SpinnerNumberModel; +import javax.swing.SwingConstants; import javax.swing.text.DefaultFormatterFactory; import javax.swing.text.NumberFormatter; @@ -41,10 +42,14 @@ public IntEditor(JSpinner spinner, String decimalFormatPattern) { } public IntEditor(JSpinner spinner, String decimalFormatPattern, String defaultStr) { - this(spinner, new DecimalFormat(decimalFormatPattern), defaultStr); + this(spinner, new DecimalFormat(decimalFormatPattern), defaultStr, SwingConstants.LEADING); } - private IntEditor(JSpinner spinner, DecimalFormat format, String defaultStr) { + public IntEditor(JSpinner spinner, String decimalFormatPattern, String defaultStr, int alignment) { + this(spinner, new DecimalFormat(decimalFormatPattern), defaultStr, alignment); + } + + private IntEditor(JSpinner spinner, DecimalFormat format, String defaultStr, int alignment) { super(spinner); if (!(spinner.getModel() instanceof SpinnerNumberModel)) { throw new IllegalArgumentException( @@ -77,7 +82,7 @@ public String valueToString(Object value) throws ParseException { ftf.setEditable(true); ftf.setFormatterFactory(factory); - ftf.setHorizontalAlignment(JTextField.LEADING); + ftf.setHorizontalAlignment(alignment); /* TBD - initializing the column width of the text field * is imprecise and doing it here is tricky because diff --git a/mucommander-core/build.gradle b/mucommander-core/build.gradle index 3e30d12e11..b0126491ae 100644 --- a/mucommander-core/build.gradle +++ b/mucommander-core/build.gradle @@ -21,10 +21,12 @@ dependencies { compileOnly project(':mucommander-protocol-api') compileOnly project(':mucommander-os-api') compileOnly project(':mucommander-viewer-api') - api project(':jetbrains-jediterm') compileOnly 'com.formdev:flatlaf:2.2' compileOnly 'org.violetlib:vaqua:10' + compileOnly 'org.jetbrains.jediterm:jediterm-pty:2.69' + compileOnly 'org.jetbrains.pty4j:pty4j:0.12.3' + compileOnly 'org.jetbrains:annotations:23.0.0' implementation 'ch.qos.logback:logback-core:1.2.3' implementation 'ch.qos.logback:logback-classic:1.2.3' @@ -59,7 +61,7 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml", + 'Build-Url': "https://www.mucommander.com/version/version.xml", 'Import-Package': 'org.violetlib.aqua;resolution:=dynamic,com.formdev.flatlaf;resolution:=dynamic,com.apple.*;resolution:=dynamic,sun.security.action;resolution:=dynamic,*', 'Export-Package': 'com.mucommander.core.desktop,' + diff --git a/mucommander-core/src/main/java/com/mucommander/Activator.java b/mucommander-core/src/main/java/com/mucommander/Activator.java index 0d78dfa7cd..130d91e2ba 100644 --- a/mucommander-core/src/main/java/com/mucommander/Activator.java +++ b/mucommander-core/src/main/java/com/mucommander/Activator.java @@ -20,6 +20,8 @@ import java.util.Collections; import java.util.List; +import com.mucommander.ui.viewer.EditorSnapshot; +import com.mucommander.ui.viewer.ViewerSnapshot; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; @@ -39,6 +41,8 @@ import com.mucommander.osgi.FileEditorServiceTracker; import com.mucommander.osgi.FileViewerServiceTracker; import com.mucommander.osgi.OperatingSystemServiceTracker; +import com.mucommander.search.SearchSnapshot; +import com.mucommander.snapshot.MuSnapshot; import com.mucommander.text.TranslationTracker; import com.mucommander.ui.action.ActionManager; import com.mucommander.ui.dialog.about.AboutDialog; @@ -80,6 +84,9 @@ public void start(BundleContext context) throws Exception { LOGGER.debug("starting"); this.context = context; portable = "portable".equals(context.getProperty("app_mode")); + MuSnapshot.registerHandler(new SearchSnapshot()); + MuSnapshot.registerHandler(new ViewerSnapshot()); + MuSnapshot.registerHandler(new EditorSnapshot()); // Register the application-specific 'bookmark' protocol. FileProtocolService bookmarksService = createBookmarkProtocolService(); bookmarksRegistration = context.registerService(FileProtocolService.class, bookmarksService, null); diff --git a/mucommander-core/src/main/java/com/mucommander/job/impl/MoveJob.java b/mucommander-core/src/main/java/com/mucommander/job/impl/MoveJob.java index beec17f1bb..4a29d1323a 100644 --- a/mucommander-core/src/main/java/com/mucommander/job/impl/MoveJob.java +++ b/mucommander-core/src/main/java/com/mucommander/job/impl/MoveJob.java @@ -142,12 +142,11 @@ protected boolean processFile(AbstractFile file, Object recurseParams) { // - if the 'rename' operation is not supported // Note: we want to avoid calling AbstractFile#renameTo when we know it will fail, as it performs some costly // I/O bound checks and ends up throwing an exception which also comes at a cost. - if(!append && file.getURL().schemeEquals(destFile.getURL()) && file.isFileOperationSupported(FileOperation.RENAME)) { + if (!append && file.getURL().schemeEquals(destFile.getURL()) && file.isFileOperationSupported(FileOperation.RENAME)) { try { file.renameTo(destFile); return true; - } - catch(IOException e) { + } catch(IOException e) { // Fail silently: renameTo might fail under normal conditions, for instance for local files which are // not located on the same volume. LOGGER.debug("Failed to rename "+file+" into "+destFile+" (not necessarily an error)", e); @@ -156,14 +155,13 @@ protected boolean processFile(AbstractFile file, Object recurseParams) { // Rename couldn't be used or didn't succeed: move the file manually // Move the directory and all its children recursively, by copying files to the destination and then deleting them. - if(file.isDirectory()) { + if (file.isDirectory()) { // create the destination folder if it doesn't exist - if(!(destFile.exists() && destFile.isDirectory())) { + if (!(destFile.exists() && destFile.isDirectory())) { do { // Loop for retry try { destFile.mkdir(); - } - catch(IOException e) { + } catch(IOException e) { DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_create_folder", destFile.getAbsolutePath())); // Retry loops if(ret==FileJobAction.RETRY) @@ -174,39 +172,39 @@ protected boolean processFile(AbstractFile file, Object recurseParams) { break; } while(true); } - + + // save the source folder's date before its children are removed + long originalDate = file.getDate(); + // move each file in this folder recursively do { // Loop for retry try { - AbstractFile[] subFiles = file.ls(); boolean isFolderEmpty = true; - for (AbstractFile subFile : subFiles) { + for (AbstractFile child : file.ls()) { // Return now if the job was interrupted, so that we do not attempt to delete this folder if (getState() == FileJobState.INTERRUPTED) return false; // Notify job that we're starting to process this file (needed for recursive calls to processFile) - nextFile(subFile); - if (!processFile(subFile, destFile)) + nextFile(child); + if (!processFile(child, destFile)) isFolderEmpty = false; } // Only when finished with folder, set destination folder's date to match the original folder one - if(destFile.isFileOperationSupported(FileOperation.CHANGE_DATE)) { + if (destFile.isFileOperationSupported(FileOperation.CHANGE_DATE)) { try { - destFile.changeDate(file.getDate()); - } - catch (IOException e) { + destFile.changeDate(originalDate); + } catch (IOException e) { LOGGER.debug("failed to change the date of "+destFile, e); // Fail silently } } // If one file failed to be moved, return false (failure) since this folder could not be moved totally - if(!isFolderEmpty) + if (!isFolderEmpty) return false; - } - catch(IOException e) { + } catch(IOException e) { // file.ls() failed DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_read_folder", file.getName())); // Retry loops @@ -227,8 +225,7 @@ protected boolean processFile(AbstractFile file, Object recurseParams) { try { file.delete(); return true; - } - catch(IOException e) { + } catch(IOException e) { DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_delete_folder", file.getAbsolutePath())); // Retry loops if(ret==FileJobAction.RETRY) @@ -243,15 +240,14 @@ protected boolean processFile(AbstractFile file, Object recurseParams) { // if renameTo() was not supported or failed, or if it wasn't possible because of 'append', // try the hard way by copying the file first, and then deleting the source file. - if(tryCopyFile(file, destFile, append, errorDialogTitle) && getState() != FileJobState.INTERRUPTED) { + if (tryCopyFile(file, destFile, append, errorDialogTitle) && getState() != FileJobState.INTERRUPTED) { // Delete the source file do { // Loop for retry try { file.delete(); // All OK return true; - } - catch(IOException e) { + } catch(IOException e) { LOGGER.debug("IOException caught", e); DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_delete_file", file.getAbsolutePath())); diff --git a/mucommander-core/src/main/java/com/mucommander/job/impl/PropertiesJob.java b/mucommander-core/src/main/java/com/mucommander/job/impl/PropertiesJob.java index 3795c0ca93..99a9929dae 100644 --- a/mucommander-core/src/main/java/com/mucommander/job/impl/PropertiesJob.java +++ b/mucommander-core/src/main/java/com/mucommander/job/impl/PropertiesJob.java @@ -20,6 +20,9 @@ import com.mucommander.commons.file.AbstractFile; import com.mucommander.commons.file.util.FileSet; +import com.mucommander.conf.MuConfigurations; +import com.mucommander.conf.MuPreference; +import com.mucommander.conf.MuPreferences; import com.mucommander.job.FileJobState; import com.mucommander.ui.main.MainFrame; @@ -85,6 +88,9 @@ protected boolean processFile(AbstractFile file, Object recurseParams) { if (getState() == FileJobState.INTERRUPTED) return false; + if (file.isHidden() && !MuConfigurations.getPreferences().getVariable(MuPreference.SHOW_HIDDEN_FILES, MuPreferences.DEFAULT_SHOW_HIDDEN_FILES)) + return true; + // If file is a directory, increase folder counter and recurse if (file.isDirectory() && !file.isSymlink()) { nbFolders++; diff --git a/mucommander-core/src/main/java/com/mucommander/job/impl/SearchJob.java b/mucommander-core/src/main/java/com/mucommander/job/impl/SearchJob.java index b71fb6c3ff..3233914a32 100644 --- a/mucommander-core/src/main/java/com/mucommander/job/impl/SearchJob.java +++ b/mucommander-core/src/main/java/com/mucommander/job/impl/SearchJob.java @@ -64,7 +64,7 @@ public SearchJob(MainFrame mainFrame, FileSet files) { } public void setDepth(int depth) { - this.depth = depth; + this.depth = depth == 0 ? Integer.MAX_VALUE : depth; } public void setThreads(int threads) { diff --git a/mucommander-core/src/main/java/com/mucommander/job/impl/UnpackJob.java b/mucommander-core/src/main/java/com/mucommander/job/impl/UnpackJob.java index 4557a4e753..80cfbae64e 100644 --- a/mucommander-core/src/main/java/com/mucommander/job/impl/UnpackJob.java +++ b/mucommander-core/src/main/java/com/mucommander/job/impl/UnpackJob.java @@ -31,6 +31,7 @@ import com.mucommander.text.Translator; import com.mucommander.ui.action.ActionManager; import com.mucommander.ui.dialog.DialogAction; +import com.mucommander.ui.dialog.file.ArchivePasswordDialog; import com.mucommander.ui.dialog.file.FileCollisionDialog; import com.mucommander.ui.dialog.file.ProgressDialog; import com.mucommander.ui.main.MainFrame; @@ -187,136 +188,155 @@ protected boolean processFile(AbstractFile file, Object recurseParams) { String destSeparator = destFolder.getSeparator(); - // Unpack the archive, copying entries one by one, in the iterator's order - try (ArchiveEntryIterator iterator = archiveFile.getEntryIterator()) { - ArchiveEntry entry; - while ((entry = iterator.nextEntry()) != null && getState() != FileJobState.INTERRUPTED) { - String entryPath = entry.getPath(); - - boolean processEntry = false; - if (selectedEntries == null) { // Entries are processed - processEntry = true; - } else { // We need to determine if the entry should be processed or not - // Process this entry if the selectedEntries set contains this entry, or a parent of this entry - int nbSelectedEntries = selectedEntries.size(); - for (int i = 0; i < nbSelectedEntries; i++) { - ArchiveEntry selectedEntry = selectedEntries.get(i); - // Note: paths of directory entries must end with '/', so this compares whether - // selectedEntry is a parent of the current entry. - if (selectedEntry.isDirectory()) { - if (entryPath.startsWith(selectedEntry.getPath())) { + do { + // Unpack the archive, copying entries one by one, in the iterator's order + try (ArchiveEntryIterator iterator = archiveFile.getEntryIterator()) { + ArchiveEntry entry; + while ((entry = iterator.nextEntry()) != null && getState() != FileJobState.INTERRUPTED) { + String entryPath = entry.getPath(); + + boolean processEntry = false; + if (selectedEntries == null) { // Entries are processed + processEntry = true; + } else { // We need to determine if the entry should be processed or not + // Process this entry if the selectedEntries set contains this entry, or a parent of this entry + int nbSelectedEntries = selectedEntries.size(); + for (int i = 0; i < nbSelectedEntries; i++) { + ArchiveEntry selectedEntry = selectedEntries.get(i); + // Note: paths of directory entries must end with '/', so this compares whether + // selectedEntry is a parent of the current entry. + if (selectedEntry.isDirectory()) { + if (entryPath.startsWith(selectedEntry.getPath())) { + processEntry = true; + break; + // Note: we can't remove selectedEntryPath from the set, we still need it + } + } else if (entryPath.equals(selectedEntry.getPath())) { + // If the (regular file) entry is in the set, remove it as we no longer need it (will speed up + // subsequent searches) processEntry = true; + selectedEntries.remove(i); break; - // Note: we can't remove selectedEntryPath from the set, we still need it } - } else if (entryPath.equals(selectedEntry.getPath())) { - // If the (regular file) entry is in the set, remove it as we no longer need it (will speed up - // subsequent searches) - processEntry = true; - selectedEntries.remove(i); - break; } } - } - if (!processEntry) - continue; + if (!processEntry) + continue; - // Resolve the entry file - AbstractFile entryFile = archiveFile.getArchiveEntryFile(entryPath); + // Resolve the entry file + AbstractFile entryFile = archiveFile.getArchiveEntryFile(entryPath); - // Notify the job that we're starting to process this file - nextFile(entryFile); + // Notify the job that we're starting to process this file + nextFile(entryFile); - // Figure out the destination file's path, relatively to the base destination folder - String relDestPath = baseArchiveDepth == 0 - ? entry.getPath() - : PathUtils.removeLeadingFragments(entry.getPath(), "/", baseArchiveDepth); + // Figure out the destination file's path, relatively to the base destination folder + String relDestPath = baseArchiveDepth == 0 + ? entry.getPath() + : PathUtils.removeLeadingFragments(entry.getPath(), "/", baseArchiveDepth); - if (newName != null) - relDestPath = newName + (PathUtils.getDepth(relDestPath, "/") <= 1 ? "" : "/" + PathUtils.removeLeadingFragments(relDestPath, "/", 1)); + if (newName != null) + relDestPath = newName + (PathUtils.getDepth(relDestPath, "/") <= 1 ? "" : "/" + PathUtils.removeLeadingFragments(relDestPath, "/", 1)); - if (!"/".equals(destSeparator)) - relDestPath = relDestPath.replace("/", destSeparator); + if (!"/".equals(destSeparator)) + relDestPath = relDestPath.replace("/", destSeparator); - // Create destination AbstractFile instance - AbstractFile destFile = destFolder.getChild(relDestPath); + // Create destination AbstractFile instance + AbstractFile destFile = destFolder.getChild(relDestPath); - // Check for ZipSlip (see https://snyk.io/research/zip-slip-vulnerability) - do { - if (destFolder.isParentOf(destFile)) - break; + // Check for ZipSlip (see https://snyk.io/research/zip-slip-vulnerability) + do { + if (destFolder.isParentOf(destFile)) + break; - DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("unpack.entry_out_of_target_dir", destFile.getName())); - // Retry loops - if (ret == FileJobAction.RETRY) + DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("unpack.entry_out_of_target_dir", destFile.getName())); + // Retry loops + if (ret == FileJobAction.RETRY) + continue; + // Cancel, skip or close dialog returns false + return false; + } while (true); + + // Check if the file does not already exist in the destination + destFile = checkForCollision(entryFile, destFolder, destFile, false); + if (destFile == null) { + // A collision occurred and either the file was skipped, or the user cancelled the job continue; - // Cancel, skip or close dialog returns false - return false; - } while (true); + } - // Check if the file does not already exist in the destination - destFile = checkForCollision(entryFile, destFolder, destFile, false); - if (destFile == null) { - // A collision occurred and either the file was skipped, or the user cancelled the job - continue; - } + // It is noteworthy that the iterator returns entries in no particular order (consider it random). + // For that reason, we cannot assume that the parent directory of an entry will be processed + // before the entry itself. + + // If the entry is a directory ... + if (entryFile.isDirectory()) { + // Create the directory in the destination, if it doesn't already exist + if (!(destFile.exists() && destFile.isDirectory())) { + // Loop for retry + do { + try { + // Use mkdirs() instead of mkdir() to create any parent folder that doesn't exist yet + destFile.mkdirs(); + } catch (IOException e) { + // Unable to create folder + DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_create_folder", entryFile.getName())); + // Retry loops + if (ret == FileJobAction.RETRY) + continue; + // Cancel or close dialog return false + return false; + // Skip continues + } + break; + } while (true); + } + } + // The entry is a regular file, copy it + else { + // Create the file's parent directory(s) if it doesn't already exist + AbstractFile destParentFile = destFile.getParent(); + if (!destParentFile.exists()) { + // Use mkdirs() instead of mkdir() to create any parent folder that doesn't exist yet + destParentFile.mkdirs(); + } - // It is noteworthy that the iterator returns entries in no particular order (consider it random). - // For that reason, we cannot assume that the parent directory of an entry will be processed - // before the entry itself. - - // If the entry is a directory ... - if (entryFile.isDirectory()) { - // Create the directory in the destination, if it doesn't already exist - if (!(destFile.exists() && destFile.isDirectory())) { - // Loop for retry - do { - try { - // Use mkdirs() instead of mkdir() to create any parent folder that doesn't exist yet - destFile.mkdirs(); - } catch (IOException e) { - // Unable to create folder - DialogAction ret = showErrorDialog(errorDialogTitle, Translator.get("cannot_create_folder", entryFile.getName())); - // Retry loops - if (ret == FileJobAction.RETRY) - continue; - // Cancel or close dialog return false - return false; - // Skip continues - } - break; - } while (true); + if (entry.isSymlink()) { + Files.createSymbolicLink( + FileSystems.getDefault().getPath(destFile.getAbsolutePath()), + FileSystems.getDefault().getPath(entry.getLinkTarget())); + continue; + } + + // The entry is wrapped in a ProxyFile to override #getInputStream() and delegate it to + // ArchiveFile#getEntryInputStream in order to take advantage of the ArchiveEntryIterator, which for + // some archive file implementations (such as TAR) can speed things by an order of magnitude. + if (!tryCopyFile(new ProxiedEntryFile(entryFile, entry, archiveFile, iterator), destFile, append, errorDialogTitle)) + return false; } } - // The entry is a regular file, copy it - else { - // Create the file's parent directory(s) if it doesn't already exist - AbstractFile destParentFile = destFile.getParent(); - if (!destParentFile.exists()) { - // Use mkdirs() instead of mkdir() to create any parent folder that doesn't exist yet - destParentFile.mkdirs(); - } - if (entry.isSymlink()) { - Files.createSymbolicLink( - FileSystems.getDefault().getPath(destFile.getAbsolutePath()), - FileSystems.getDefault().getPath(entry.getLinkTarget())); - continue; + return true; + } catch (IOException e) { + DialogAction action = null; + if (archiveFile.getPassword() == null) { + ArchivePasswordDialog dialog = new ArchivePasswordDialog(getMainFrame()); + String password = (String) dialog.getUserInput(); + if (password != null) { + archiveFile.setPassword(password); + action = FileJobAction.RETRY; } + } - // The entry is wrapped in a ProxyFile to override #getInputStream() and delegate it to - // ArchiveFile#getEntryInputStream in order to take advantage of the ArchiveEntryIterator, which for - // some archive file implementations (such as TAR) can speed things by an order of magnitude. - if (!tryCopyFile(new ProxiedEntryFile(entryFile, entry, archiveFile, iterator), destFile, append, errorDialogTitle)) - return false; + if (action != FileJobAction.RETRY) { + action = showErrorDialog(errorDialogTitle, Translator.get("cannot_read_file", archiveFile.getName())); + archiveFile.setPassword(null); } - } - return true; - } catch (IOException e) { - showErrorDialog(errorDialogTitle, Translator.get("cannot_read_file", archiveFile.getName())); - } + if (action == FileJobAction.RETRY) + continue; + } + break; + } while(true); return false; } diff --git a/mucommander-core/src/main/java/com/mucommander/osgi/FileEditorServiceTracker.java b/mucommander-core/src/main/java/com/mucommander/osgi/FileEditorServiceTracker.java index 790959bc9d..1472414be2 100644 --- a/mucommander-core/src/main/java/com/mucommander/osgi/FileEditorServiceTracker.java +++ b/mucommander-core/src/main/java/com/mucommander/osgi/FileEditorServiceTracker.java @@ -55,7 +55,7 @@ public FileEditorService addingService(ServiceReference refer public void removedService(ServiceReference reference, FileEditorService service) { super.removedService(reference, service); SERVICES.add(service); - LOGGER.info("FileFormatService is unregistered: " + service); + LOGGER.info("FileEditorService is unregistered: " + service); } private static void addEditorService(FileEditorService service) { diff --git a/mucommander-core/src/main/java/com/mucommander/search/SearchBuilder.java b/mucommander-core/src/main/java/com/mucommander/search/SearchBuilder.java index 083e597f32..a3299d9dd1 100644 --- a/mucommander-core/src/main/java/com/mucommander/search/SearchBuilder.java +++ b/mucommander-core/src/main/java/com/mucommander/search/SearchBuilder.java @@ -43,24 +43,6 @@ public class SearchBuilder implements com.mucommander.commons.file.protocol.search.SearchBuilder { private static final Logger LOGGER = LoggerFactory.getLogger(SearchBuilder.class); - public static final String SEARCH_IN_ARCHIVES = "archives"; - public static final String SEARCH_IN_HIDDEN = "hidden"; - public static final String SEARCH_IN_SYMLINKS = "symlinks"; - public static final String SEARCH_IN_SUBFOLDERS = "subfolders"; - public static final String SEARCH_FOR_ARCHIVES = "filter_archives"; - public static final String SEARCH_FOR_HIDDEN = "filter_hidden"; - public static final String SEARCH_FOR_SYMLINKS = "filter_symlinks"; - public static final String SEARCH_FOR_SUBFOLDERS = "filter_subfolders"; - public static final String SEARCH_DEPTH = "depth"; - public static final String SEARCH_THREADS = "threads"; - public static final String MATCH_CASESENSITIVE = "case_sensitive"; - public static final String MATCH_REGEX = "regex"; - public static final String SEARCH_TEXT = "text"; - public static final String TEXT_CASESENSITIVE = "text-case_sensitive"; - public static final String TEXT_MATCH_REGEX= "text-regex"; - public static final String SEARCH_SIZE = "size"; - public static final int DEFAULT_THREADS = 2; - private AbstractFile entrypoint; private String searchStr; private SearchListener listener; @@ -85,13 +67,6 @@ public class SearchBuilder implements com.mucommander.commons.file.protocol.sear private SearchJob searchJob; private SearchBuilder() { - searchInSubfolders = true; - searchForArchives = true; - searchForHidden = true; - searchForSymlinks = true; - searchForSubfolders = true; - searchDepth = Integer.MAX_VALUE; - searchThreads = DEFAULT_THREADS; } public static SearchBuilder newSearch() { @@ -133,121 +108,109 @@ public SearchBuilder depth(int searchDepth) { @Override public SearchBuilder searchInArchives(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_IN_ARCHIVES); - if (value != null) - searchInArchives = Boolean.parseBoolean(value); + String value = SearchProperty.SEARCH_IN_ARCHIVES.get(properties); + searchInArchives = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder searchInHidden(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_IN_HIDDEN); - if (value != null) - searchInHidden = Boolean.parseBoolean(value); + String value = SearchProperty.SEARCH_IN_HIDDEN.get(properties); + searchInHidden = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder searchInSymlinks(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_IN_SYMLINKS); - if (value != null) - searchInSymlinks = Boolean.parseBoolean(value); + String value = SearchProperty.SEARCH_IN_SYMLINKS.get(properties); + searchInSymlinks = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder searchInSubfolders(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_IN_SUBFOLDERS); - if (value != null) - searchInSubfolders = Boolean.parseBoolean(value); + String value = SearchProperty.SEARCH_IN_SUBFOLDERS.get(properties); + searchInSubfolders = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder searchForArchives(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_FOR_ARCHIVES); - if (value != null) - searchForArchives = Boolean.parseBoolean(value); + String value = SearchProperty.SEARCH_FOR_ARCHIVES.get(properties); + searchForArchives = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder searchForHidden(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_FOR_HIDDEN); - if (value != null) - searchForHidden = Boolean.parseBoolean(value); + String value = SearchProperty.SEARCH_FOR_HIDDEN.get(properties); + searchForHidden = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder searchForSymlinks(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_FOR_SYMLINKS); - if (value != null) - searchForSymlinks = Boolean.parseBoolean(value); + String value = SearchProperty.SEARCH_FOR_SYMLINKS.get(properties); + searchForSymlinks = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder searchForSubfolders(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_FOR_SUBFOLDERS); - if (value != null) - searchForSubfolders = Boolean.parseBoolean(value); + String value = SearchProperty.SEARCH_FOR_SUBFOLDERS.get(properties); + searchForSubfolders = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder searchDepth(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_DEPTH); - if (value != null) - searchDepth = Integer.parseInt(value); + String value = SearchProperty.SEARCH_DEPTH.get(properties); + searchDepth = Integer.parseInt(value); return this; } @Override public SearchBuilder searchThreads(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_THREADS); - if (value != null) - searchThreads = Integer.parseInt(value); + String value = SearchProperty.SEARCH_THREADS.get(properties); + searchThreads = Integer.parseInt(value); return this; } @Override public SearchBuilder matchCaseInsensitive(List> properties) { - String value = getProperty(properties, SearchBuilder.MATCH_CASESENSITIVE); - if (value != null) - matchCaseSensitive = Boolean.parseBoolean(value); + String value = SearchProperty.MATCH_CASESENSITIVE.get(properties); + matchCaseSensitive = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder matchRegex(List> properties) { - String value = getProperty(properties, SearchBuilder.MATCH_REGEX); - if (value != null) - matchRegex = Boolean.parseBoolean(value); + String value = SearchProperty.MATCH_REGEX.get(properties); + matchRegex = Boolean.parseBoolean(value); return this; } @Override public SearchBuilder searchText(List> properties) { - String value = getProperty(properties, SearchBuilder.SEARCH_TEXT); - if (value != null) { + String value = SearchProperty.SEARCH_TEXT.get(properties); + if (value.length() > 0) { searchText = value; - textCaseSensitive = Boolean.parseBoolean(getProperty(properties, SearchBuilder.TEXT_CASESENSITIVE)); - textMatchRegex = Boolean.parseBoolean(getProperty(properties, SearchBuilder.TEXT_MATCH_REGEX)); + textCaseSensitive = Boolean.parseBoolean(SearchProperty.TEXT_CASESENSITIVE.get(properties)); + textMatchRegex = Boolean.parseBoolean(SearchProperty.TEXT_MATCH_REGEX.get(properties)); } return this; } @Override public SearchBuilder searchSize(List> properties) { + var sizeKeys = new String[] { SearchProperty.SEARCH_SIZE.getKey(), SearchProperty.SEARCH_SIZE2.getKey() }; properties.stream() - .filter(p -> p.first.equals(SearchBuilder.SEARCH_SIZE)) + .filter(p -> p.first.equals(sizeKeys[0]) || p.first.equals(sizeKeys[1])) .map(p -> p.second) .forEach(value -> { - String[] sizeProperties = SearchUtils.splitSearchSizeClause(value); - SizeRelation searchSizeRelation = SizeRelation.valueOf(sizeProperties[0]); - long searchSize = Long.parseLong(sizeProperties[1]); - SizeUnit searchSizeUnit = SizeUnit.valueOf(sizeProperties[2]); + SizeRelation searchSizeRelation = SearchUtils.getSizeRelation(value); + long searchSize = SearchUtils.getSize(value); + SizeUnit searchSizeUnit = SearchUtils.getSizeUnit(value); Predicate predicate = file -> searchSizeRelation.matches(file.getSize(), searchSize, searchSizeUnit); sizePredicate = sizePredicate == null ? predicate : sizePredicate.and(predicate); }); diff --git a/mucommander-core/src/main/java/com/mucommander/search/SearchDialog.java b/mucommander-core/src/main/java/com/mucommander/search/SearchDialog.java index 7551960fed..6bc413a544 100644 --- a/mucommander-core/src/main/java/com/mucommander/search/SearchDialog.java +++ b/mucommander-core/src/main/java/com/mucommander/search/SearchDialog.java @@ -31,10 +31,10 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.swing.AbstractButton; import javax.swing.BorderFactory; -import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; @@ -65,7 +65,6 @@ import com.mucommander.desktop.ActionType; import com.mucommander.text.Translator; import com.mucommander.ui.action.ActionProperties; -import com.mucommander.ui.action.impl.FindAction; import com.mucommander.ui.dialog.InformationDialog; import com.mucommander.ui.main.MainFrame; import com.mucommander.ui.text.SelectAllOnFocusTextField; @@ -105,29 +104,6 @@ public class SearchDialog extends FocusDialog implements ActionListener, Documen private JComboBox secondSizeUnit; private JTextField secondSize = new SelectAllOnFocusTextField(8); - // Store last values, initialized to the default values - private static boolean lastSearchInSubfolders = true; - private static boolean lastSearchInArchives; - private static boolean lastSearchInHidden; - private static boolean lastSearchInSymlinks; - private static boolean lastSearchForSubfolders = true; - private static boolean lastSearchForArchives = true; - private static boolean lastSearchForHidden = true; - private static boolean lastSearchForSymlinks = true; - private static boolean lastMatchCase; - private static boolean lastMatchRegex; - private static int lastDepth = 0; - private static int lastThreads = SearchBuilder.DEFAULT_THREADS; - private static String lastText = ""; - private static boolean lastTextCase; - private static boolean lastTextRegex; - private static Long lastFirstSize; - private static SizeRelation lastFirstSizeRel = SizeRelation.eq; - private static SizeUnit lastFirstSizeUnit = SizeUnit.kB; - private static Long lastSecondSize; - private static SizeRelation lastSecondSizeRel = SizeRelation.gt; - private static SizeUnit lastSecondSizeUnit = SizeUnit.kB; - private JButton searchButton; private JButton cancelButton; @@ -164,6 +140,7 @@ public SearchDialog(MainFrame mainFrame) { l.setLabelFor(searchFilesField); l.setDisplayedMnemonic('n'); + boolean lastMatchRegex = Boolean.parseBoolean(SearchProperty.MATCH_REGEX.getValue()); wildcards = new JLabel(!lastMatchRegex ? Translator.get("search_dialog.wildcards") : " "); compPanel.addRow("", wildcards, 10); @@ -171,10 +148,11 @@ public SearchDialog(MainFrame mainFrame) { gbc.weightx = 1.0; JPanel groupingPanel = new ProportionalGridPanel(2, gbc); - matchCase = new JCheckBox(Translator.get("search_dialog.case_sensitive"), lastMatchCase); + boolean lastMatchCase = Boolean.parseBoolean(SearchProperty.MATCH_CASESENSITIVE.getValue()); + matchCase = new JCheckBox(SearchProperty.MATCH_CASESENSITIVE.getTranslation(), lastMatchCase); groupingPanel.add(matchCase); - matchRegex = new JCheckBox(Translator.get("search_dialog.matches_regexp"), lastMatchRegex); + matchRegex = new JCheckBox(SearchProperty.MATCH_REGEX.getTranslation(), lastMatchRegex); matchRegex.addChangeListener(e -> { AbstractButton b = (AbstractButton) e.getSource(); wildcards.setText(!b.isSelected() ? Translator.get("search_dialog.wildcards") : " "); @@ -212,24 +190,32 @@ private void cleanError() { groupingPanel = new ProportionalGridPanel(2, gbc); - searchInSubfolders = new JCheckBox(Translator.get("search_dialog.search_in_subfolders"), lastSearchInSubfolders); + boolean value = Boolean.parseBoolean(SearchProperty.SEARCH_IN_SUBFOLDERS.getValue()); + searchInSubfolders = new JCheckBox(SearchProperty.SEARCH_IN_SUBFOLDERS.getTranslation(), value); groupingPanel.add(searchInSubfolders); - searchForSubfolders = new JCheckBox(Translator.get("search_dialog.search_for_folders"), lastSearchForSubfolders); + value = Boolean.parseBoolean(SearchProperty.SEARCH_FOR_SUBFOLDERS.getValue()); + searchForSubfolders = new JCheckBox(SearchProperty.SEARCH_FOR_SUBFOLDERS.getTranslation(), value); groupingPanel.add(searchForSubfolders); - searchInArchives = new JCheckBox(Translator.get("search_dialog.search_in_archives"), lastSearchInArchives); + value = Boolean.parseBoolean(SearchProperty.SEARCH_IN_ARCHIVES.getValue()); + searchInArchives = new JCheckBox(SearchProperty.SEARCH_IN_ARCHIVES.getTranslation(), value); groupingPanel.add(searchInArchives); - searchForArchives = new JCheckBox(Translator.get("search_dialog.search_for_archives"), lastSearchForArchives); + value = Boolean.parseBoolean(SearchProperty.SEARCH_FOR_ARCHIVES.getValue()); + searchForArchives = new JCheckBox(SearchProperty.SEARCH_FOR_ARCHIVES.getTranslation(), value); groupingPanel.add(searchForArchives); - searchInHidden = new JCheckBox(Translator.get("search_dialog.search_in_hidden_files"), lastSearchInHidden); + value = Boolean.parseBoolean(SearchProperty.SEARCH_IN_HIDDEN.getValue()); + searchInHidden = new JCheckBox(SearchProperty.SEARCH_IN_HIDDEN.getTranslation(), value); groupingPanel.add(searchInHidden); - searchForHidden = new JCheckBox(Translator.get("search_dialog.search_for_hidden_files"), lastSearchForHidden); + value = Boolean.parseBoolean(SearchProperty.SEARCH_FOR_HIDDEN.getValue()); + searchForHidden = new JCheckBox(SearchProperty.SEARCH_FOR_HIDDEN.getTranslation(), value); groupingPanel.add(searchForHidden); - searchInSymlinks = new JCheckBox(Translator.get("search_dialog.search_in_symlinks"), lastSearchInSymlinks); + value = Boolean.parseBoolean(SearchProperty.SEARCH_IN_SYMLINKS.getValue()); + searchInSymlinks = new JCheckBox(SearchProperty.SEARCH_IN_SYMLINKS.getTranslation(), value); groupingPanel.add(searchInSymlinks); - searchForSymlinks = new JCheckBox(Translator.get("search_dialog.search_for_symlinks"), lastSearchForSymlinks); + value = Boolean.parseBoolean(SearchProperty.SEARCH_FOR_SYMLINKS.getValue()); + searchForSymlinks = new JCheckBox(SearchProperty.SEARCH_FOR_SYMLINKS.getTranslation(), value); groupingPanel.add(searchForSymlinks); compPanel.addRow("", groupingPanel, 10); @@ -240,15 +226,15 @@ private void cleanError() { IntEditor editor = new IntEditor(depth, "#####", UNLIMITED_DEPTH); depth.setEditor(editor); depth.setModel(new SpinnerNumberModel(0, 0, null, 1)); - depth.setValue(lastDepth); - compPanel.addRow(Translator.get("search_dialog.search_depth"), depth, 5); + depth.setValue(Integer.parseInt(SearchProperty.SEARCH_DEPTH.getValue())); + compPanel.addRow(SearchProperty.SEARCH_DEPTH.getTranslation(), depth, 5); threads = new JSpinner(); editor = new IntEditor(threads, "#####", MAX_THREADS); threads.setEditor(editor); threads.setModel(new SpinnerNumberModel(0, 0, MAX_NUM_OF_SEARCH_THREADS, 1)); - threads.setValue(lastThreads); - compPanel.addRow(Translator.get("search_dialog.search_threads"), threads, 5); + threads.setValue(Integer.parseInt(SearchProperty.SEARCH_THREADS.getValue())); + compPanel.addRow(SearchProperty.SEARCH_THREADS.getTranslation(), threads, 5); fileSearchPanel.add(compPanel); mainPanel.add(fileSearchPanel); @@ -258,16 +244,19 @@ private void cleanError() { textSearchPanel.setBorder(BorderFactory.createTitledBorder(Translator.get("Text search (Optional)"))); compPanel = new XAlignedComponentPanel(5); + String lastText = SearchProperty.SEARCH_TEXT.getValue(); searchTextField = new SelectAllOnFocusTextField(lastText); - l = compPanel.addRow(Translator.get("search_dialog.search_text"), searchTextField, 10); + l = compPanel.addRow(SearchProperty.SEARCH_TEXT.getTranslation(), searchTextField, 10); l.setLabelFor(searchTextField); l.setDisplayedMnemonic('t'); groupingPanel = new ProportionalGridPanel(2, gbc); - textCase = new JCheckBox(Translator.get("search_dialog.text_case_sensitive"), lastTextCase); + value = Boolean.parseBoolean(SearchProperty.TEXT_CASESENSITIVE.getValue()); + textCase = new JCheckBox(SearchProperty.TEXT_CASESENSITIVE.getTranslation(), value); groupingPanel.add(textCase); - textRegex = new JCheckBox(Translator.get("search_dialog.text_matches_regexp"), lastTextRegex); + value = Boolean.parseBoolean(SearchProperty.TEXT_MATCH_REGEX.getValue()); + textRegex = new JCheckBox(SearchProperty.TEXT_MATCH_REGEX.getTranslation(), value); groupingPanel.add(textRegex); compPanel.addRow("", groupingPanel, 5); @@ -294,25 +283,32 @@ private void cleanError() { } void addSizePanel(XAlignedComponentPanel compPanel) { + var firstSizeClause = SearchProperty.SEARCH_SIZE.getValue(); JPanel firstSizePanel = new JPanel(new FlowLayout()); - firstSizeRel.setSelectedItem(lastFirstSizeRel); + + var firstSizeRelation = SearchUtils.getSizeRelation(firstSizeClause); + firstSizeRel.setSelectedItem(firstSizeRelation); firstSizePanel.add(firstSizeRel); - firstSize.setText(lastFirstSize == null ? "" : lastFirstSize.toString()); + var firstSizeValue = SearchUtils.getSize(firstSizeClause); + firstSize.setText(firstSizeValue != null ? firstSizeValue.toString() : ""); firstSizePanel.add(firstSize); firstSizeUnit = new JComboBox<>(getSizeUnitDisplayStrings()); - firstSizeUnit.setSelectedIndex(lastFirstSizeUnit.ordinal()); + firstSizeUnit.setSelectedIndex(SearchUtils.getSizeUnit(firstSizeClause).ordinal()); firstSizePanel.add(firstSizeUnit); + var secondSizeClause = SearchProperty.SEARCH_SIZE2.getValue(); JPanel secondSizePanel = new JPanel(new FlowLayout()); + secondSizePanel.add(secondSizeRel); - secondSize.setText(lastSecondSize == null ? "" : lastSecondSize.toString()); + var secondSizeValue = SearchUtils.getSize(secondSizeClause); + secondSize.setText(secondSizeValue != null ? secondSizeValue.toString() : ""); secondSizePanel.add(secondSize); secondSizeUnit = new JComboBox<>(getSizeUnitDisplayStrings()); - secondSizeUnit.setSelectedIndex(lastSecondSizeUnit.ordinal()); + secondSizeUnit.setSelectedIndex(SearchUtils.getSizeUnit(secondSizeClause).ordinal()); secondSizePanel.add(secondSizeUnit); Runnable updater = () -> { @@ -350,7 +346,7 @@ public void changedUpdate(DocumentEvent e) { JPanel sizePanel = new JPanel(new BorderLayout()); sizePanel.add(combinedSizesPanel, BorderLayout.WEST); - JLabel sizeLabel = compPanel.addRow(Translator.get("search_dialog.size", "Size"), sizePanel, 20); + JLabel sizeLabel = compPanel.addRow(SearchProperty.SEARCH_SIZE.getTranslation(), sizePanel, 20); sizeLabel.setDisplayedMnemonic('s'); sizeLabel.setLabelFor(firstSizeRel); } @@ -414,53 +410,59 @@ public void actionPerformed(ActionEvent e) { * @return true on success, false on input validation error */ private boolean validateAndUpdateValues() { - lastSearchInSubfolders = searchInSubfolders.isSelected(); - lastSearchInArchives = searchInArchives.isSelected(); - lastSearchInHidden = searchInHidden.isSelected(); - lastSearchInSymlinks = searchInSymlinks.isSelected(); - lastSearchForSubfolders = searchForSubfolders.isSelected(); - lastSearchForArchives = searchForArchives.isSelected(); - lastSearchForHidden = searchForHidden.isSelected(); - lastSearchForSymlinks = searchForSymlinks.isSelected(); - lastMatchCase = matchCase.isSelected(); - lastMatchRegex = matchRegex.isSelected(); - lastDepth = ((Number) depth.getValue()).intValue(); - lastThreads = ((Number) threads.getValue()).intValue(); - lastText = searchTextField.getText(); - lastTextCase = textCase.isSelected(); - lastTextRegex = textRegex.isSelected(); - - lastFirstSizeRel = (SizeRelation) firstSizeRel.getSelectedItem(); - lastFirstSizeUnit = SizeUnit.VALUES[firstSizeUnit.getSelectedIndex()]; - - String size = firstSize.getText(); + var firstSizeRelation = (SizeRelation) firstSizeRel.getSelectedItem(); + var firstSizeUnit = SizeUnit.VALUES[this.firstSizeUnit.getSelectedIndex()]; + + Long firstSize, secondSize; + SizeRelation secondSizeRelation = null; + SizeUnit secondSizeUnit = null; + + String size = this.firstSize.getText(); if (StringUtils.isNullOrEmpty(size)) { - lastFirstSize = null; - lastSecondSize = null; + firstSize = null; + secondSize = null; } else { try { - lastFirstSize = Long.parseLong(size); + firstSize = Long.parseLong(size); } catch (NumberFormatException nfe) { InformationDialog.showErrorDialog(this, Translator.get("search_dialog.size_error")); - firstSize.requestFocus(); + this.firstSize.requestFocus(); return false; } - size = secondSize.getText(); + size = this.secondSize.getText(); if (StringUtils.isNullOrEmpty(size)) - lastSecondSize = null; + secondSize = null; else { try { - lastSecondSize = Long.parseLong(size); + secondSize = Long.parseLong(size); } catch (NumberFormatException nfe) { InformationDialog.showErrorDialog(this, Translator.get("search_dialog.size_error")); - secondSize.requestFocus(); + this.secondSize.requestFocus(); return false; } - lastSecondSizeRel = lastFirstSizeRel == SizeRelation.gt ? SizeRelation.lt : SizeRelation.gt; - lastSecondSizeUnit = SizeUnit.VALUES[secondSizeUnit.getSelectedIndex()]; + secondSizeRelation = firstSizeRelation == SizeRelation.gt ? SizeRelation.lt : SizeRelation.gt; + secondSizeUnit = SizeUnit.VALUES[this.secondSizeUnit.getSelectedIndex()]; } } + SearchProperty.SEARCH_IN_SUBFOLDERS.setValue(String.valueOf(searchInSubfolders.isSelected())); + SearchProperty.SEARCH_IN_ARCHIVES.setValue(String.valueOf(searchInArchives.isSelected())); + SearchProperty.SEARCH_IN_HIDDEN.setValue(String.valueOf(searchInHidden.isSelected())); + SearchProperty.SEARCH_IN_SYMLINKS.setValue(String.valueOf(searchInSymlinks.isSelected())); + SearchProperty.SEARCH_FOR_SUBFOLDERS.setValue(String.valueOf(searchForSubfolders.isSelected())); + SearchProperty.SEARCH_FOR_ARCHIVES.setValue(String.valueOf(searchForArchives.isSelected())); + SearchProperty.SEARCH_FOR_HIDDEN.setValue(String.valueOf(searchForHidden.isSelected())); + SearchProperty.SEARCH_FOR_SYMLINKS.setValue(String.valueOf(searchForSymlinks.isSelected())); + SearchProperty.MATCH_CASESENSITIVE.setValue(String.valueOf(matchCase.isSelected())); + SearchProperty.MATCH_REGEX.setValue(String.valueOf(matchRegex.isSelected())); + SearchProperty.SEARCH_DEPTH.setValue(String.valueOf(((Number) depth.getValue()).intValue())); + SearchProperty.SEARCH_THREADS.setValue(String.valueOf(((Number) threads.getValue()).intValue())); + SearchProperty.TEXT_CASESENSITIVE.setValue(String.valueOf(textCase.isSelected())); + SearchProperty.TEXT_MATCH_REGEX.setValue(String.valueOf(textRegex.isSelected())); + SearchProperty.SEARCH_SIZE.setValue(buildSeachSizeClause(firstSizeRelation, firstSize, firstSizeUnit)); + SearchProperty.SEARCH_SIZE2.setValue(buildSeachSizeClause(secondSizeRelation, secondSize, secondSizeUnit)); + SearchProperty.SEARCH_TEXT.setValue(searchTextField.getText()); + return true; } @@ -471,45 +473,9 @@ private boolean validateAndUpdateValues() { * @return the properties of the search as a query string */ private String getSearchQuery() { - List> properties = new ArrayList<>(); - if (!lastSearchInSubfolders) - properties.add(new Pair<>(SearchBuilder.SEARCH_IN_SUBFOLDERS, Boolean.FALSE.toString())); - if (lastSearchInArchives) - properties.add(new Pair<>(SearchBuilder.SEARCH_IN_ARCHIVES, Boolean.TRUE.toString())); - if (lastSearchInHidden) - properties.add(new Pair<>(SearchBuilder.SEARCH_IN_HIDDEN, Boolean.TRUE.toString())); - if (lastSearchInSymlinks) - properties.add(new Pair<>(SearchBuilder.SEARCH_IN_SYMLINKS, Boolean.TRUE.toString())); - if (!lastSearchForSubfolders) - properties.add(new Pair<>(SearchBuilder.SEARCH_FOR_SUBFOLDERS, Boolean.FALSE.toString())); - if (!lastSearchForArchives) - properties.add(new Pair<>(SearchBuilder.SEARCH_FOR_ARCHIVES, Boolean.FALSE.toString())); - if (!lastSearchForHidden) - properties.add(new Pair<>(SearchBuilder.SEARCH_FOR_HIDDEN, Boolean.FALSE.toString())); - if (!lastSearchForSymlinks) - properties.add(new Pair<>(SearchBuilder.SEARCH_FOR_SYMLINKS, Boolean.FALSE.toString())); - if (lastMatchCase) - properties.add(new Pair<>(SearchBuilder.MATCH_CASESENSITIVE, Boolean.TRUE.toString())); - if (lastMatchRegex) - properties.add(new Pair<>(SearchBuilder.MATCH_REGEX, Boolean.TRUE.toString())); - if (lastDepth > 0) - properties.add(new Pair<>(SearchBuilder.SEARCH_DEPTH, String.valueOf(lastDepth))); - if (lastThreads != SearchBuilder.DEFAULT_THREADS) - properties.add(new Pair<>(SearchBuilder.SEARCH_THREADS, String.valueOf(lastThreads))); - if (!lastText.isEmpty()) { - properties.add(new Pair<>(SearchBuilder.SEARCH_TEXT, lastText)); - if (lastTextCase) - properties.add(new Pair<>(SearchBuilder.TEXT_CASESENSITIVE, Boolean.TRUE.toString())); - if (lastTextRegex) - properties.add(new Pair<>(SearchBuilder.TEXT_MATCH_REGEX, Boolean.TRUE.toString())); - } - if (lastFirstSize != null) { - properties.add(new Pair<>(SearchBuilder.SEARCH_SIZE, buildSeachSizeClause(lastFirstSizeRel, lastFirstSize, lastFirstSizeUnit))); - if (lastSecondSize != null) - properties.add(new Pair<>(SearchBuilder.SEARCH_SIZE, buildSeachSizeClause(lastSecondSizeRel, lastSecondSize, lastSecondSizeUnit))); - } - return properties.stream() - .map(pair -> pair.first + "=" + pair.second) + return Stream.of(SearchProperty.values()) + .filter(property -> !property.isDefault()) + .map(SearchProperty::toString) .collect(Collectors.joining("&")); } diff --git a/mucommander-core/src/main/java/com/mucommander/search/SearchProperty.java b/mucommander-core/src/main/java/com/mucommander/search/SearchProperty.java new file mode 100644 index 0000000000..9a7abde9fa --- /dev/null +++ b/mucommander-core/src/main/java/com/mucommander/search/SearchProperty.java @@ -0,0 +1,92 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mucommander.search; + +import java.util.List; +import java.util.Objects; + +import com.mucommander.commons.util.Pair; +import com.mucommander.text.Translator; + +enum SearchProperty { + SEARCH_IN_ARCHIVES("archives", "search_dialog.search_in_archives", Boolean.FALSE.toString()), + SEARCH_IN_HIDDEN("hidden", "search_dialog.search_in_hidden_files", Boolean.FALSE.toString()), + SEARCH_IN_SYMLINKS("symlinks", "search_dialog.search_in_symlinks", Boolean.FALSE.toString()), + SEARCH_IN_SUBFOLDERS("subfolders", "search_dialog.search_in_subfolders", Boolean.TRUE.toString()), + SEARCH_FOR_ARCHIVES("filter_archives", "search_dialog.search_for_archives", Boolean.TRUE.toString()), + SEARCH_FOR_HIDDEN("filter_hidden", "search_dialog.search_for_hidden_files", Boolean.TRUE.toString()), + SEARCH_FOR_SYMLINKS("filter_symlinks", "search_dialog.search_for_symlinks", Boolean.TRUE.toString()), + SEARCH_FOR_SUBFOLDERS("filter_subfolders", "search_dialog.search_for_folders", Boolean.TRUE.toString()), + SEARCH_DEPTH("depth", "search_dialog.search_depth", "0"), + SEARCH_THREADS("threads", "search_dialog.search_threads", "2"), + MATCH_CASESENSITIVE("case_sensitive", "search_dialog.case_sensitive", Boolean.FALSE.toString()), + MATCH_REGEX("regex", "search_dialog.matches_regexp", Boolean.FALSE.toString()), + TEXT_CASESENSITIVE("text-case_sensitive", "search_dialog.text_case_sensitive", Boolean.FALSE.toString()), + TEXT_MATCH_REGEX("text-regex", "search_dialog.text_matches_regexp", Boolean.FALSE.toString()), + SEARCH_SIZE("size", "search_dialog.size", null), + SEARCH_SIZE2("size-2", "search_dialog.size", null), + SEARCH_TEXT("text", "search_dialog.search_text", ""); + + private String key; + private String i18nKey; + private String defaultValue; + private String value; + + SearchProperty(String key, String i18nKey, String defaultValue) { + this.key = key; + this.i18nKey = i18nKey; + this.defaultValue = defaultValue; + value = defaultValue; + } + + public String getKey() { + return key; + } + + public String getTranslation() { + return Translator.get(i18nKey); + } + + public String getDefaultValue() { + return defaultValue; + } + + public String get(List> properties) { + return properties.stream() + .filter(p -> p.first.equals(key)) + .map(p -> p.second) + .findAny() + .orElse(defaultValue); + } + + public void setValue(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public boolean isDefault() { + return Objects.equals(defaultValue, value); + } + + public String toString() { + return key + "=" + value; + } +} diff --git a/mucommander-core/src/main/java/com/mucommander/search/SearchSnapshot.java b/mucommander-core/src/main/java/com/mucommander/search/SearchSnapshot.java new file mode 100644 index 0000000000..bda50828db --- /dev/null +++ b/mucommander-core/src/main/java/com/mucommander/search/SearchSnapshot.java @@ -0,0 +1,42 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.search; + +import static com.mucommander.snapshot.MuSnapshot.SEARCH_SECTION; + +import com.mucommander.commons.conf.Configuration; +import com.mucommander.snapshot.MuSnapshotable; + +/** + * Snapshot preferences for file-search + * @author Arik Hadas + */ +public class SearchSnapshot extends MuSnapshotable { + public SearchSnapshot() { + super(SearchProperty::values, + SearchProperty::getValue, + SearchProperty::setValue, + pref -> pref.getKey() != null ? SEARCH_SECTION + "." + pref.getKey() : null); + } + + @Override + protected void write(Configuration configuration, SearchProperty pref) { + // do not persist properties that are set with their default value + if (!pref.isDefault()) + super.write(configuration, pref); + } +} diff --git a/mucommander-core/src/main/java/com/mucommander/search/SearchUtils.java b/mucommander-core/src/main/java/com/mucommander/search/SearchUtils.java index 5137beded9..f65ff40afa 100644 --- a/mucommander-core/src/main/java/com/mucommander/search/SearchUtils.java +++ b/mucommander-core/src/main/java/com/mucommander/search/SearchUtils.java @@ -68,11 +68,28 @@ public static String wildcardToRegex(String wildcard){ return convert ? s.toString() : wildcard; } - public static String buildSeachSizeClause(SizeRelation relation, long size, SizeUnit unit) { - return String.format("%s:%s:%s", relation.name(), size, unit); + public static String buildSeachSizeClause(SizeRelation relation, Long size, SizeUnit unit) { + return size != null ? String.format("%s:%s:%s", relation.name(), size, unit) : null; } - public static String[] splitSearchSizeClause(String sizeClause) { - return sizeClause.split(":"); + public static SizeRelation getSizeRelation(String sizeClause) { + if (sizeClause == null) + return SizeRelation.eq; + var relation = sizeClause.substring(0, sizeClause.indexOf(':')); + return SizeRelation.valueOf(relation); + } + + public static Long getSize(String sizeClause) { + if (sizeClause == null) + return null; + var size = sizeClause.split(":")[1]; + return Long.parseLong(size); + } + + public static SizeUnit getSizeUnit(String sizeClause) { + if (sizeClause == null) + return SizeUnit.kB; + var unit = sizeClause.substring(sizeClause.lastIndexOf(':') + 1); + return SizeUnit.valueOf(unit); } } diff --git a/mucommander-core/src/main/java/com/mucommander/snapshot/MuSnapshot.java b/mucommander-core/src/main/java/com/mucommander/snapshot/MuSnapshot.java index 1becdcf202..ea40f5bd21 100644 --- a/mucommander-core/src/main/java/com/mucommander/snapshot/MuSnapshot.java +++ b/mucommander-core/src/main/java/com/mucommander/snapshot/MuSnapshot.java @@ -174,7 +174,10 @@ public class MuSnapshot { private static final String SELECTED_TAB = "selection"; /** Describes the title that was set for the tab */ private static final String TAB_TITLE = "title"; - + + /** Section describing last used file search properties. */ + public static final String SEARCH_SECTION = "search"; + /** Cache the screen's size. this value isn't computed during the shutdown process since it cause a deadlock then */ private Dimension screenSize; @@ -575,9 +578,11 @@ void read() throws IOException, ConfigurationException { XmlConfigurationReader reader = new XmlConfigurationReader(); configuration.read(reader); - for (MuSnapshotable handler : snapshotables) { - handler.read(configuration); - } + snapshotables.forEach(this::read); + } + + private void read(MuSnapshotable handler) { + handler.read(configuration); } /** @@ -611,13 +616,15 @@ void write() throws IOException, ConfigurationException { setGlobalHistory(); - for (MuSnapshotable handler : snapshotables) { - handler.write(configuration); - } + snapshotables.forEach(this::write); configuration.write(); } + private void write(MuSnapshotable snapshotable) { + snapshotable.write(configuration); + } + private void setFrameAttributes(MainFrame mainFrame, int index) { // Save window position, size and screen resolution setWindowAttributes(index, mainFrame); diff --git a/mucommander-core/src/main/java/com/mucommander/snapshot/MuSnapshotable.java b/mucommander-core/src/main/java/com/mucommander/snapshot/MuSnapshotable.java index 392ee305bd..3568844c79 100644 --- a/mucommander-core/src/main/java/com/mucommander/snapshot/MuSnapshotable.java +++ b/mucommander-core/src/main/java/com/mucommander/snapshot/MuSnapshotable.java @@ -17,26 +17,75 @@ package com.mucommander.snapshot; +import java.util.Arrays; +import java.util.function.BiConsumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.mucommander.commons.conf.Configuration; /** * Configuration snapshoting support for modules. * - * @author Miroslav Hajda + * @author Miroslav Hajda, Arik Hadas */ -public interface MuSnapshotable { - +public abstract class MuSnapshotable{ + final Logger LOGGER = LoggerFactory.getLogger(getClass()); + + /** lists the snapshot properties */ + private Supplier ls; + /** get the value of a snapshot property */ + private Function get; + /** set the value of a snapshot property */ + private BiConsumer set; + /** returns the key in the snapshot.xml file of a snapshot property */ + private Function key; + + /** + * @param ls lists the snapshot properties + * @param get get the value of a snapshot property + * @param set set the value of a snapshot property + * @param key returns the key in the snapshot.xml file of a snapshot property + */ + protected MuSnapshotable(Supplier ls, Function get, BiConsumer set, Function key) { + this.ls = ls; + this.get = get; + this.set = set; + this.key = key; + } + /** * Performs loading/reading of snapshot preferences. * * @param configuration configuration */ - void read(Configuration configuration); + public void read(Configuration configuration) { + var values = ls.get(); + LOGGER.info("Loading snapshot configuration for: {}", values[0].getClass()); + for (T pref : values) { + var prefKey = key.apply(pref); + if (prefKey != null) { + set.accept(pref, configuration.getVariable(prefKey, get.apply(pref))); + } + } + } /** * Performs storing/writing of snapshot preferences. * * @param configuration configuration */ - void write(Configuration configuration); + public void write(Configuration configuration) { + Arrays.stream(ls.get()).forEach(pref -> write(configuration, pref)); + } + + protected void write(Configuration configuration, T pref) { + var prefKey = key.apply(pref); + if (prefKey != null) { + configuration.setVariable(prefKey, get.apply(pref)); + } + } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/action/impl/SelectedFilesAction.java b/mucommander-core/src/main/java/com/mucommander/ui/action/impl/SelectedFilesAction.java index 13bbb72036..8d0b9e3277 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/action/impl/SelectedFilesAction.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/action/impl/SelectedFilesAction.java @@ -53,7 +53,7 @@ protected boolean getFileTableCondition(FileTable fileTable) { public final void performAction() { FileSet files = mainFrame.getActiveTable().getSelectedFiles(); // Perform the action only if at least one file is selected/marked - if(files.size()>0) + if (!files.isEmpty()) performAction(files); } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/action/impl/ShowInEnclosingFolderAction.java b/mucommander-core/src/main/java/com/mucommander/ui/action/impl/ShowInEnclosingFolderAction.java index 83c1231b3b..a965c58829 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/action/impl/ShowInEnclosingFolderAction.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/action/impl/ShowInEnclosingFolderAction.java @@ -20,7 +20,6 @@ import java.util.Map; import com.mucommander.commons.file.AbstractFile; -import com.mucommander.commons.file.protocol.search.SearchFile; import com.mucommander.desktop.ActionType; import com.mucommander.ui.action.AbstractActionDescriptor; import com.mucommander.ui.action.ActionCategory; @@ -28,7 +27,7 @@ import com.mucommander.ui.main.MainFrame; /** - * + * This action opens the parent folder of the selected file and keeps the latter file selected. * @author Arik Hadas */ public class ShowInEnclosingFolderAction extends SelectedFileAction { @@ -39,16 +38,12 @@ public ShowInEnclosingFolderAction(MainFrame mainFrame, Map prope @Override public void performAction() { - AbstractFile currentFolder = mainFrame.getActivePanel().getCurrentFolder(); - if (!SearchFile.SCHEMA.equals(currentFolder.getURL().getScheme())) + AbstractFile selectedFile = mainFrame.getActiveTable().getSelectedFile(true, true); + if (selectedFile == null) return; - AbstractFile file = mainFrame.getActiveTable().getSelectedFile(true, true); - if (file == null) - return; - - AbstractFile enclosingFolder = file.getParent(); - mainFrame.getInactivePanel().getTabs().add(enclosingFolder, file); + AbstractFile enclosingFolder = selectedFile.getParent(); + mainFrame.getActivePanel().tryChangeCurrentFolder(enclosingFolder, selectedFile, true); } @Override diff --git a/mucommander-core/src/main/java/com/mucommander/ui/action/impl/ToggleTerminalAction.java b/mucommander-core/src/main/java/com/mucommander/ui/action/impl/ToggleTerminalAction.java index 8ca9d10a0e..729db86d7c 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/action/impl/ToggleTerminalAction.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/action/impl/ToggleTerminalAction.java @@ -148,6 +148,10 @@ public void keyPressed(KeyEvent keyEvent) { keyEvent.setKeyCode(-1); revertToTableView(); setVisible(false); + } else if (!terminal.getTtyConnector().isConnected()) { + // just close terminal if it is not active/connected (for example when sb typed 'exit') + revertToTableView(); + setVisible(false); } } }; diff --git a/mucommander-core/src/main/java/com/mucommander/ui/chooser/FontChooser.java b/mucommander-core/src/main/java/com/mucommander/ui/chooser/FontChooser.java index 653f9d220b..a30c0a90af 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/chooser/FontChooser.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/chooser/FontChooser.java @@ -170,14 +170,12 @@ private void updatePreview() { * Called when the font description has been changed. */ public void actionPerformed(ActionEvent e) { - ChangeEvent event; - font = createFont(); updatePreview(); // Notifies listeners. - event = new ChangeEvent(this); - for(ChangeListener listener : listeners.keySet()) + ChangeEvent event = new ChangeEvent(this); + for (ChangeListener listener : listeners.keySet()) listener.stateChanged(event); } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/about/AboutDialog.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/about/AboutDialog.java index 056236f6ff..7098f548cd 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/about/AboutDialog.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/about/AboutDialog.java @@ -170,6 +170,7 @@ private JScrollPane createCreditsPanel() { insertTitle(doc, "Powered by"); // External Libraries. + // TODO - it should be fed dynamically from package/readme.txt insertHeader(doc, "Libraries"); insertDetailedUrl(doc, "Ant", "Apache License", "http://ant.apache.org"); insertDetailedUrl(doc, "Apache Commons", "Apache License", "http://commons.apache.org"); @@ -181,12 +182,15 @@ private JScrollPane createCreditsPanel() { insertDetailedUrl(doc, "7-Zip-JBinding", "LGPL", "http://sevenzipjbind.sourceforge.net"); insertDetailedUrl(doc, "jCIFS", "LGPL", "http://jcifs.samba.org"); insertDetailedUrl(doc, "JetS3t", "Apache License", "http://jets3t.s3.amazonaws.com/index.html"); + insertDetailedUrl(doc, "JediTerm", "LGPL and Apache License", "https://github.com/JetBrains/jediterm"); insertDetailedUrl(doc, "JmDNS", "LGPL", "http://jmdns.sourceforge.net"); insertDetailedUrl(doc, "JNA", "LGPL", "http://jna.dev.java.net"); insertDetailedUrl(doc, "JUnRar", "Freeware", "http://sourceforge.net/projects/java-unrar"); insertDetailedUrl(doc, "Yanfs", "BSD", "http://yanfs.dev.java.net"); insertDetailedUrl(doc, "JCommander", "Apache License", "http://jcommander.org"); - insertDetailedUrl(doc, "ICEpdf", "Apache License", "http://www.icesoft.com/icepdf"); + insertDetailedUrl(doc, "ICEpdf", "Apache License", "https://github.com/pcorless/icepdf"); + insertDetailedUrl(doc, "RSyntaxTextArea", "BSD 3-Clause New or Revised License", "https://bobbylight.github.io/RSyntaxTextArea/"); + insertDetailedUrl(doc, "Unix4j", "MIT License", "http://unix4j.org"); insertDetailedUrl(doc, "FlatLaf", "Apache License", "https://www.formdev.com/flatlaf"); insertDetailedUrl(doc, "VAqua", "GPL", "https://violetlib.org/vaqua/overview.html"); diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/file/ArchivePasswordDialog.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/file/ArchivePasswordDialog.java new file mode 100644 index 0000000000..8376862fb0 --- /dev/null +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/file/ArchivePasswordDialog.java @@ -0,0 +1,128 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mucommander.ui.dialog.file; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; + +import com.mucommander.commons.util.ui.dialog.DialogToolkit; +import com.mucommander.commons.util.ui.dialog.FocusDialog; +import com.mucommander.commons.util.ui.layout.YBoxPanel; +import com.mucommander.commons.util.ui.text.MultiLineLabel; +import com.mucommander.job.ui.DialogResult; +import com.mucommander.text.Translator; +import com.mucommander.ui.main.MainFrame; + +public class ArchivePasswordDialog extends FocusDialog implements ActionListener, DialogResult { + + private JTextField passwordField; + + private JButton okButton; + + private String password; + + // Dialog size constraints + private final static Dimension MINIMUM_DIALOG_DIMENSION = new Dimension(500,0); + // Dialog width should not exceed 360, height is not an issue (always the same) + private final static Dimension MAXIMUM_DIALOG_DIMENSION = new Dimension(800,10000); + + + /** + * Creates a new rename file dialog. + * + * @param mainFrame the parent MainFrame + * @param file the file to rename. + */ + public ArchivePasswordDialog(MainFrame mainFrame) { + super(mainFrame, Translator.get("maybe_password_protected"), mainFrame); + + Container contentPane = getContentPane(); + + YBoxPanel mainPanel = new YBoxPanel(); + mainPanel.add(new JLabel(Translator.get("maybe_password_protected_failure") + ":")); + passwordField = new JPasswordField(); + passwordField.addActionListener(this); + + // Sets the initial selection. + mainPanel.add(passwordField); + + mainPanel.addSpace(10); + contentPane.add(mainPanel, BorderLayout.NORTH); + + okButton = new JButton(Translator.get("ok")); + okButton.setEnabled(false); + passwordField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void removeUpdate(DocumentEvent e) { + okButton.setEnabled(!passwordField.getText().trim().isEmpty()); + } + + @Override + public void insertUpdate(DocumentEvent e) { + okButton.setEnabled(!passwordField.getText().trim().isEmpty()); + } + + @Override + public void changedUpdate(DocumentEvent e) { + } + }); + JButton cancelButton = new JButton(Translator.get("cancel")); + contentPane.add(DialogToolkit.createOKCancelPanel(okButton, cancelButton, getRootPane(), this), BorderLayout.SOUTH); + + // Path field will receive initial focus + setInitialFocusComponent(passwordField); + + setMinimumSize(MINIMUM_DIALOG_DIMENSION); + setMaximumSize(MAXIMUM_DIALOG_DIMENSION); + } + + + /////////////////////////////////// + // ActionListener implementation // + /////////////////////////////////// + + public void actionPerformed(ActionEvent e) { + Object source = e.getSource(); + + // OK Button + if (source == okButton || source == passwordField) { + if (!okButton.isEnabled()) + return; + password = passwordField.getText(); + } else { + password = null; + } + dispose(); + } + + public Object getUserInput() { + showDialog(); + return password; + } + +} diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefCheckBox.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefCheckBox.java index eb1edd4559..c064212967 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefCheckBox.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefCheckBox.java @@ -17,8 +17,6 @@ package com.mucommander.ui.dialog.pref.component; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; import java.util.function.Supplier; import javax.swing.JCheckBox; @@ -44,11 +42,6 @@ public boolean hasChanged() { } public void addDialogListener(final PreferencesDialog dialog) { - addItemListener(new ItemListener() { - - public void itemStateChanged(ItemEvent e) { - dialog.componentChanged(PrefCheckBox.this); - } - }); + addItemListener(e -> dialog.componentChanged(PrefCheckBox.this)); } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefComboBox.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefComboBox.java index b95e391da6..da13206255 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefComboBox.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefComboBox.java @@ -17,12 +17,9 @@ package com.mucommander.ui.dialog.pref.component; -import com.mucommander.ui.dialog.pref.PreferencesDialog; - -import javax.swing.*; +import javax.swing.JComboBox; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; +import com.mucommander.ui.dialog.pref.PreferencesDialog; /** * @author Arik Hadas @@ -34,12 +31,7 @@ public PrefComboBox() { } public void addDialogListener(final PreferencesDialog dialog) { - addItemListener(new ItemListener() { - - public void itemStateChanged(ItemEvent e) { - dialog.componentChanged(PrefComboBox.this); - } - }); + addItemListener(e -> dialog.componentChanged(PrefComboBox.this)); } @Override diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefRadioButton.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefRadioButton.java index a960c2ddff..4e7b1fa8d4 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefRadioButton.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefRadioButton.java @@ -17,11 +17,9 @@ package com.mucommander.ui.dialog.pref.component; -import com.mucommander.ui.dialog.pref.PreferencesDialog; +import javax.swing.JRadioButton; -import javax.swing.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; +import com.mucommander.ui.dialog.pref.PreferencesDialog; /** * @author Arik Hadas @@ -33,11 +31,6 @@ public PrefRadioButton(String description) { } public void addDialogListener(final PreferencesDialog dialog) { - addItemListener(new ItemListener() { - - public void itemStateChanged(ItemEvent e) { - dialog.componentChanged(PrefRadioButton.this); - } - }); + addItemListener(e -> dialog.componentChanged(PrefRadioButton.this)); } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefSpinner.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefSpinner.java new file mode 100644 index 0000000000..8601b9676e --- /dev/null +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefSpinner.java @@ -0,0 +1,50 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.mucommander.ui.dialog.pref.component; + +import java.util.Objects; +import java.util.function.Supplier; + +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; + +import com.mucommander.ui.dialog.pref.PreferencesDialog; + +/* + * @author Arik Hadas + */ +public class PrefSpinner extends JSpinner implements PrefComponent { + + private Supplier conf; + + public PrefSpinner(Comparable minimum, Comparable maximum, Number stepSize, Supplier conf) { + super(new SpinnerNumberModel(conf.get(), minimum, maximum, stepSize)); + this.conf = conf; + } + + @Override + public void addDialogListener(PreferencesDialog dialog) { + addChangeListener(e -> dialog.componentChanged(PrefSpinner.this)); + } + + @Override + public boolean hasChanged() { + return !Objects.equals(conf.get(), getValue()); + } + +} diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefTable.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefTable.java index 3806a97b85..bb3383ea4d 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefTable.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/component/PrefTable.java @@ -17,14 +17,14 @@ package com.mucommander.ui.dialog.pref.component; -import com.mucommander.ui.dialog.pref.PreferencesDialog; +import java.awt.Dimension; -import javax.swing.*; -import javax.swing.event.TableModelEvent; +import javax.swing.JTable; import javax.swing.event.TableModelListener; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; -import java.awt.*; + +import com.mucommander.ui.dialog.pref.PreferencesDialog; /** * @author Arik Hadas @@ -58,11 +58,7 @@ public void setPreferredColumnWidths(double[] percentages) { } public void addDialogListener(final PreferencesDialog dialog) { - getModel().addTableModelListener(dialogListener = new TableModelListener() { - public void tableChanged(TableModelEvent e) { - dialog.componentChanged(PrefTable.this); - } - }); + getModel().addTableModelListener(dialogListener = e -> dialog.componentChanged(PrefTable.this)); } @Override diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/general/AppearancePanel.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/general/AppearancePanel.java index 9e71380b7c..8c8b65393b 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/general/AppearancePanel.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/general/AppearancePanel.java @@ -71,6 +71,7 @@ import com.mucommander.ui.icon.SpinningDial; import com.mucommander.ui.main.WindowManager; import com.mucommander.ui.theme.Theme; +import com.mucommander.ui.theme.Theme.ThemeType; import com.mucommander.ui.theme.ThemeManager; /** @@ -435,7 +436,7 @@ public Component getListCellRendererComponent(JList list, Object value, int inde else label.setText(theme.getName()); - if (theme.getType() != Theme.CUSTOM_THEME) + if (theme.getType() != ThemeType.CUSTOM_THEME) label.setIcon(lockIcon); else label.setIcon(transparentIcon); @@ -896,9 +897,9 @@ private void importLookAndFeel() { private void setTypeLabel(Theme theme) { String label; - if (theme.getType() == Theme.USER_THEME) + if (theme.getType() == ThemeType.USER_THEME) label = Translator.get("theme.custom"); - else if (theme.getType() == Theme.PREDEFINED_THEME) + else if (theme.getType() == ThemeType.PREDEFINED_THEME) label = Translator.get("theme.built_in"); else label = Translator.get("theme.add_on"); @@ -912,7 +913,7 @@ private void resetThemeButtons(Theme theme) { setTypeLabel(theme); - if (theme.getType() != Theme.CUSTOM_THEME) { + if (theme.getType() != ThemeType.CUSTOM_THEME) { renameThemeButton.setEnabled(false); deleteThemeButton.setEnabled(false); } else { diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/general/FoldersPanel.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/general/FoldersPanel.java index 23846ce032..3599969a70 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/general/FoldersPanel.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/general/FoldersPanel.java @@ -19,6 +19,7 @@ import java.awt.BorderLayout; import java.awt.Color; +import java.awt.FlowLayout; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -37,6 +38,7 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SpringLayout; +import javax.swing.SwingConstants; import javax.swing.plaf.basic.BasicTextFieldUI; import javax.swing.text.JTextComponent; @@ -44,6 +46,7 @@ import com.mucommander.commons.util.ui.layout.SpringUtilities; import com.mucommander.commons.util.ui.layout.XBoxPanel; import com.mucommander.commons.util.ui.layout.YBoxPanel; +import com.mucommander.commons.util.ui.spinner.IntEditor; import com.mucommander.conf.MuConfigurations; import com.mucommander.conf.MuPreference; import com.mucommander.conf.MuPreferences; @@ -53,6 +56,7 @@ import com.mucommander.ui.dialog.pref.component.PrefCheckBox; import com.mucommander.ui.dialog.pref.component.PrefFilePathField; import com.mucommander.ui.dialog.pref.component.PrefRadioButton; +import com.mucommander.ui.dialog.pref.component.PrefSpinner; import com.mucommander.ui.main.WindowManager; @@ -91,6 +95,9 @@ class FoldersPanel extends PreferencesPanel implements ItemListener, KeyListener // Always show single tab's header ? private PrefCheckBox showTabHeaderCheckBox; + // Timeout for quick searches + private PrefSpinner quickSearchTimeoutSpinner; + public FoldersPanel(PreferencesDialog parent) { super(parent, Translator.get("prefs_dialog.folders_tab")); @@ -232,7 +239,18 @@ public boolean hasChanged() { MuPreferences.DEFAULT_SHOW_TAB_HEADER)); showTabHeaderCheckBox.addDialogListener(parent); northPanel.add(showTabHeaderCheckBox); - + + JPanel quickSearchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + quickSearchPanel.setBorder(BorderFactory.createEmptyBorder()); + quickSearchTimeoutSpinner = new PrefSpinner(0, 999, 1, () -> MuConfigurations.getPreferences().getVariable( + MuPreference.QUICK_SEARCH_TIMEOUT, + MuPreferences.DEFAULT_QUICK_SEARCH_TIMEOUT)); + quickSearchTimeoutSpinner.addDialogListener(parent); + quickSearchTimeoutSpinner.setEditor(new IntEditor(quickSearchTimeoutSpinner, "###", Translator.get("prefs_dialog.no_quick_search_timeout"), SwingConstants.TRAILING)); + quickSearchPanel.add(new JLabel(Translator.get("prefs_dialog.quick_search_timeout_sec"))); + quickSearchPanel.add(quickSearchTimeoutSpinner); + northPanel.add(quickSearchPanel); + add(northPanel, BorderLayout.NORTH); lastFoldersRadioButton.addDialogListener(parent); @@ -267,6 +285,8 @@ protected void commit() { MuConfigurations.getPreferences().setVariable(MuPreference.SHOW_TAB_HEADER, showTabHeaderCheckBox.isSelected()); + MuConfigurations.getPreferences().setVariable(MuPreference.QUICK_SEARCH_TIMEOUT, (int) quickSearchTimeoutSpinner.getValue()); + // If one of the show/hide file filters have changed, refresh current folders of current MainFrame boolean refreshFolders = MuConfigurations.getPreferences().setVariable(MuPreference.SHOW_HIDDEN_FILES, showHiddenFilesCheckBox.isSelected()); diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/ColorButton.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/ColorButton.java index bb9513e23c..640e91c6cf 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/ColorButton.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/ColorButton.java @@ -163,8 +163,8 @@ private ColorChooser createColorChooser() { /////////////////////////////////// public void actionPerformed(ActionEvent e) { - ColorChooser chooser; - ColorChooser.createDialog(parent, chooser = createColorChooser()).showDialog(); + ColorChooser chooser = createColorChooser(); + ColorChooser.createDialog(parent, chooser).showDialog(); setCurrentColor(chooser.getColor(), true); } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FileEditorPanel.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FileEditorPanel.java index 9de001d11a..5d9bc9ad36 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FileEditorPanel.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FileEditorPanel.java @@ -65,11 +65,8 @@ public FileEditorPanel(PreferencesDialog parent, ThemeData themeData) { * @return the JPanel that contains all of the color configuration elements. */ private JPanel createColorsPanel(FontChooser fontChooser) { - ProportionalGridPanel gridPanel; // Contains all the color buttons. - JPanel colorsPanel; // Used to wrap the colors panel in a flow layout. - - // Initialisation. - gridPanel = new ProportionalGridPanel(3); + // Contains all the color buttons. + ProportionalGridPanel gridPanel = new ProportionalGridPanel(3); // Header. addLabelRow(gridPanel, false); @@ -81,7 +78,7 @@ private JPanel createColorsPanel(FontChooser fontChooser) { ThemeData.EDITOR_SELECTED_FOREGROUND_COLOR, ThemeData.EDITOR_SELECTED_BACKGROUND_COLOR).addPropertyChangeListener(this); // Wraps everything in a flow layout. - colorsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JPanel colorsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); colorsPanel.add(gridPanel); colorsPanel.setBorder(BorderFactory.createTitledBorder(Translator.get("theme_editor.colors"))); @@ -92,18 +89,14 @@ private JPanel createColorsPanel(FontChooser fontChooser) { * Initialises the panel's UI. */ private void initUI() { - YBoxPanel configurationPanel; // Contains all the configuration elements. - FontChooser fontChooser; // Used to select a font. - JPanel mainPanel; // Main panel. - // Font chooser and preview initialisation. - mainPanel = new JPanel(new BorderLayout()); - fontChooser = createFontChooser(ThemeData.EDITOR_FONT); + JPanel mainPanel = new JPanel(new BorderLayout()); + FontChooser fontChooser = createFontChooser(ThemeData.EDITOR_FONT); mainPanel.add(createPreviewPanel(), BorderLayout.EAST); addFontChooserListener(fontChooser, preview); // Configuration panel initialisation. - configurationPanel = new YBoxPanel(); + YBoxPanel configurationPanel = new YBoxPanel(); // Contains all the configuration elements. configurationPanel.add(fontChooser); configurationPanel.addSpace(10); configurationPanel.add(createColorsPanel(fontChooser)); @@ -119,9 +112,6 @@ private void initUI() { * @return the file editor preview panel. */ private JPanel createPreviewPanel() { - JPanel panel; // Preview panel. - JScrollPane scroll; // Wraps the preview text are. - // Initialises the preview text area. preview = new JTextArea(15, 15); @@ -130,28 +120,32 @@ private JPanel createPreviewPanel() { setForegroundColors(); // Creates the panel. - panel = new JPanel(new BorderLayout()); - panel.add(scroll = new JScrollPane(preview, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), BorderLayout.CENTER); + JPanel previewPanel = new JPanel(new BorderLayout()); + JScrollPane scroll= new JScrollPane(preview, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); // Wraps the preview text. + previewPanel.add(scroll, BorderLayout.CENTER); scroll.getViewport().setPreferredSize(preview.getPreferredSize()); - panel.setBorder(BorderFactory.createTitledBorder(Translator.get("preview"))); + previewPanel.setBorder(BorderFactory.createTitledBorder(Translator.get("preview"))); loadText(); preview.setCaretPosition(0); - return panel; + return previewPanel; } /** * Listens on changes on the foreground and background colors. */ public void propertyChange(PropertyChangeEvent event) { + switch(event.getPropertyName()) { // Background color changed. - if(event.getPropertyName().equals(PreviewLabel.BACKGROUND_COLOR_PROPERTY_NAME)) + case PreviewLabel.BACKGROUND_COLOR_PROPERTY_NAME: setBackgroundColors(); - - // Foreground color changed. - else if(event.getPropertyName().equals(PreviewLabel.FOREGROUND_COLOR_PROPERTY_NAME)) + break; + // Foreground color changed. + case PreviewLabel.FOREGROUND_COLOR_PROPERTY_NAME: setForegroundColors(); + break; + } } private void setBackgroundColors() { @@ -170,25 +164,14 @@ private void setForegroundColors() { // - Misc. --------------------------------------------------------------------------- // ----------------------------------------------------------------------------------- private void loadText() { - char[] buffer; // Buffer for each chunk of data read from the license file. - int count; // Number of characters read from the last read operation. - InputStreamReader in; // Stream on the license file. - - in = null; - try { - in = new InputStreamReader(FileEditorPanel.class.getResourceAsStream(RuntimeConstants.LICENSE)); - buffer = new char[2048]; + try (InputStreamReader in = new InputStreamReader(FileEditorPanel.class.getResourceAsStream(RuntimeConstants.LICENSE))){ + char[] buffer = new char[2048]; - while((count = in.read(buffer)) != -1) + int count; // Number of characters read from the last read operation. + while ((count = in.read(buffer)) != -1) preview.append(new String(buffer, 0, count)); } catch(Exception e) {} - finally { - if(in != null) { - try {in.close();} - catch(Exception e) {} - } - } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FilePanel.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FilePanel.java index 3601191f3d..3414e79580 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FilePanel.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FilePanel.java @@ -17,6 +17,11 @@ package com.mucommander.ui.dialog.pref.theme; +import java.awt.BorderLayout; + +import javax.swing.JLabel; +import javax.swing.JPanel; + import com.mucommander.commons.util.ui.layout.ProportionalGridPanel; import com.mucommander.text.Translator; import com.mucommander.ui.chooser.FontChooser; @@ -24,25 +29,23 @@ import com.mucommander.ui.dialog.pref.PreferencesDialog; import com.mucommander.ui.theme.ThemeData; -import javax.swing.*; -import java.awt.*; - /** * @author Nicolas Rinaudo */ class FilePanel extends ThemeEditorPanel { + // - Initialisation ------------------------------------------------------------------ // ----------------------------------------------------------------------------------- /** * Creates a new FilePanel. * @param parent dialog containing the panel - * @param isActive whether the color values should be taken from the active or inactive state. + * @param active whether the color values should be taken from the active or inactive state. * @param data theme to edit. * @param fontChooser File table font chooser. */ - public FilePanel(PreferencesDialog parent, boolean isActive, ThemeData data, FontChooser fontChooser) { - super(parent, Translator.get(isActive ? "theme_editor.active_panel" : "theme_editor.inactive_panel"), data); - initUI(isActive, fontChooser); + public FilePanel(PreferencesDialog parent, boolean active, ThemeData data, FontChooser fontChooser) { + super(parent, Translator.get(active ? "theme_editor.active_panel" : "theme_editor.inactive_panel"), data); + initUI(active, fontChooser); } @@ -50,27 +53,18 @@ public FilePanel(PreferencesDialog parent, boolean isActive, ThemeData data, Fon // - UI initialisation --------------------------------------------------------------- // ----------------------------------------------------------------------------------- private void addForegroundColor(JPanel to, int colorId, ColorButton background, FontChooser fontChooser, FilePreviewPanel previewPanel) { - PreviewLabel preview; - ColorButton button; - - preview = new PreviewLabel(); + PreviewLabel preview = new PreviewLabel(); preview.setTextPainted(true); background.addUpdatedPreviewComponent(preview); addFontChooserListener(fontChooser, preview); - to.add(button = new ColorButton(parent, themeData, colorId, PreviewLabel.FOREGROUND_COLOR_PROPERTY_NAME, preview)); + ColorButton button = new ColorButton(parent, themeData, colorId, PreviewLabel.FOREGROUND_COLOR_PROPERTY_NAME, preview); + to.add(button); button.addUpdatedPreviewComponent(previewPanel); } - private void initUI(boolean isActive, FontChooser fontChooser) { - JPanel gridPanel; - ColorButton backgroundButton; - ColorButton selectedBackgroundButton; - ColorButton borderButton; - FilePreviewPanel preview; - - - gridPanel = new ProportionalGridPanel(3); - preview = new FilePreviewPanel(themeData, isActive); + private void initUI(boolean active, FontChooser fontChooser) { + JPanel gridPanel = new ProportionalGridPanel(3); + FilePreviewPanel preview = new FilePreviewPanel(themeData, active); addFontChooserListener(fontChooser, preview); // Header @@ -80,70 +74,87 @@ private void initUI(boolean isActive, FontChooser fontChooser) { // Background gridPanel.add(createCaptionLabel("theme_editor.background")); - gridPanel.add(backgroundButton = new ColorButton(parent, themeData, isActive ? ThemeData.FILE_TABLE_BACKGROUND_COLOR : - ThemeData.FILE_TABLE_INACTIVE_BACKGROUND_COLOR, - PreviewLabel.BACKGROUND_COLOR_PROPERTY_NAME, preview)); - gridPanel.add(selectedBackgroundButton = new ColorButton(parent, themeData, - isActive ? ThemeData.FILE_TABLE_SELECTED_BACKGROUND_COLOR : - ThemeData.FILE_TABLE_INACTIVE_SELECTED_BACKGROUND_COLOR, - PreviewLabel.BACKGROUND_COLOR_PROPERTY_NAME, preview)); + ColorButton backgroundButton = new ColorButton(parent, themeData, + active ? ThemeData.FILE_TABLE_BACKGROUND_COLOR : + ThemeData.FILE_TABLE_INACTIVE_BACKGROUND_COLOR, + PreviewLabel.BACKGROUND_COLOR_PROPERTY_NAME, preview); + gridPanel.add(backgroundButton); + ColorButton selectedBackgroundButton = new ColorButton(parent, themeData, + active ? ThemeData.FILE_TABLE_SELECTED_BACKGROUND_COLOR : + ThemeData.FILE_TABLE_INACTIVE_SELECTED_BACKGROUND_COLOR, + PreviewLabel.BACKGROUND_COLOR_PROPERTY_NAME, preview); + gridPanel.add(selectedBackgroundButton); // Alternate background gridPanel.add(createCaptionLabel("theme_editor.alternate_background")); gridPanel.add(new ColorButton(parent, themeData, - isActive ? ThemeData.FILE_TABLE_ALTERNATE_BACKGROUND_COLOR : ThemeData.FILE_TABLE_INACTIVE_ALTERNATE_BACKGROUND_COLOR, + active ? ThemeData.FILE_TABLE_ALTERNATE_BACKGROUND_COLOR : ThemeData.FILE_TABLE_INACTIVE_ALTERNATE_BACKGROUND_COLOR, PreviewLabel.BACKGROUND_COLOR_PROPERTY_NAME, preview)); gridPanel.add(new JLabel()); // Folders. gridPanel.add(createCaptionLabel("theme_editor.folder")); - addForegroundColor(gridPanel, isActive ? ThemeData.FOLDER_FOREGROUND_COLOR : ThemeData.FOLDER_INACTIVE_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.FOLDER_FOREGROUND_COLOR : ThemeData.FOLDER_INACTIVE_FOREGROUND_COLOR, backgroundButton, fontChooser, preview); - addForegroundColor(gridPanel, isActive ? ThemeData.FOLDER_SELECTED_FOREGROUND_COLOR : ThemeData.FOLDER_INACTIVE_SELECTED_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.FOLDER_SELECTED_FOREGROUND_COLOR : ThemeData.FOLDER_INACTIVE_SELECTED_FOREGROUND_COLOR, selectedBackgroundButton, fontChooser, preview); // Plain files. gridPanel.add(createCaptionLabel("theme_editor.plain_file")); - addForegroundColor(gridPanel, isActive ? ThemeData.FILE_FOREGROUND_COLOR : ThemeData.FILE_INACTIVE_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.FILE_FOREGROUND_COLOR : ThemeData.FILE_INACTIVE_FOREGROUND_COLOR, backgroundButton, fontChooser, preview); - addForegroundColor(gridPanel, isActive ? ThemeData.FILE_SELECTED_FOREGROUND_COLOR : ThemeData.FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.FILE_SELECTED_FOREGROUND_COLOR : ThemeData.FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, selectedBackgroundButton, fontChooser, preview); // Archives. gridPanel.add(createCaptionLabel("theme_editor.archive_file")); - addForegroundColor(gridPanel, isActive ? ThemeData.ARCHIVE_FOREGROUND_COLOR : ThemeData.ARCHIVE_INACTIVE_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.ARCHIVE_FOREGROUND_COLOR : ThemeData.ARCHIVE_INACTIVE_FOREGROUND_COLOR, backgroundButton, fontChooser, preview); - addForegroundColor(gridPanel, isActive ? ThemeData.ARCHIVE_SELECTED_FOREGROUND_COLOR : ThemeData.ARCHIVE_INACTIVE_SELECTED_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.ARCHIVE_SELECTED_FOREGROUND_COLOR : ThemeData.ARCHIVE_INACTIVE_SELECTED_FOREGROUND_COLOR, selectedBackgroundButton, fontChooser, preview); // Hidden files. gridPanel.add(createCaptionLabel("theme_editor.hidden_file")); - addForegroundColor(gridPanel, isActive ? ThemeData.HIDDEN_FILE_FOREGROUND_COLOR : ThemeData.HIDDEN_FILE_INACTIVE_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.HIDDEN_FILE_FOREGROUND_COLOR : ThemeData.HIDDEN_FILE_INACTIVE_FOREGROUND_COLOR, backgroundButton, fontChooser, preview); - addForegroundColor(gridPanel, isActive ? ThemeData.HIDDEN_FILE_SELECTED_FOREGROUND_COLOR : ThemeData.HIDDEN_FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.HIDDEN_FILE_SELECTED_FOREGROUND_COLOR : ThemeData.HIDDEN_FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, selectedBackgroundButton, fontChooser, preview); // Symlinks. gridPanel.add(createCaptionLabel("theme_editor.symbolic_link")); - addForegroundColor(gridPanel, isActive ? ThemeData.SYMLINK_FOREGROUND_COLOR : ThemeData.SYMLINK_INACTIVE_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.SYMLINK_FOREGROUND_COLOR : ThemeData.SYMLINK_INACTIVE_FOREGROUND_COLOR, backgroundButton, fontChooser, preview); - addForegroundColor(gridPanel, isActive ? ThemeData.SYMLINK_SELECTED_FOREGROUND_COLOR : ThemeData.SYMLINK_INACTIVE_SELECTED_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.SYMLINK_SELECTED_FOREGROUND_COLOR : ThemeData.SYMLINK_INACTIVE_SELECTED_FOREGROUND_COLOR, selectedBackgroundButton, fontChooser, preview); // Marked files. gridPanel.add(createCaptionLabel("theme_editor.marked_file")); - addForegroundColor(gridPanel, isActive ? ThemeData.MARKED_FOREGROUND_COLOR : ThemeData.MARKED_INACTIVE_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.MARKED_FOREGROUND_COLOR : ThemeData.MARKED_INACTIVE_FOREGROUND_COLOR, backgroundButton, fontChooser, preview); - addForegroundColor(gridPanel, isActive ? ThemeData.MARKED_SELECTED_FOREGROUND_COLOR : ThemeData.MARKED_INACTIVE_SELECTED_FOREGROUND_COLOR, + addForegroundColor(gridPanel, active ? ThemeData.MARKED_SELECTED_FOREGROUND_COLOR : ThemeData.MARKED_INACTIVE_SELECTED_FOREGROUND_COLOR, selectedBackgroundButton, fontChooser, preview); + // Read-only + gridPanel.add(createCaptionLabel("theme_editor.read_only_file")); + addForegroundColor(gridPanel, + active ? ThemeData.READ_ONLY_FOREGROUND_COLOR : ThemeData.READ_ONLY_INACTIVE_FOREGROUND_COLOR, + backgroundButton, + fontChooser, + preview); + addForegroundColor(gridPanel, + active ? ThemeData.READ_ONLY_SELECTED_FOREGROUND_COLOR + : ThemeData.READ_ONLY_INACTIVE_SELECTED_FOREGROUND_COLOR, + selectedBackgroundButton, fontChooser, preview); + // Border. gridPanel.add(createCaptionLabel("theme_editor.border")); - gridPanel.add(borderButton = new ColorButton(parent, themeData, isActive ? ThemeData.FILE_TABLE_BORDER_COLOR : - ThemeData.FILE_TABLE_INACTIVE_BORDER_COLOR, PreviewLabel.BORDER_COLOR_PROPERTY_NAME)); + ColorButton borderButton = new ColorButton(parent, themeData, active ? ThemeData.FILE_TABLE_BORDER_COLOR : + ThemeData.FILE_TABLE_INACTIVE_BORDER_COLOR, PreviewLabel.BORDER_COLOR_PROPERTY_NAME); + gridPanel.add(borderButton); borderButton.addUpdatedPreviewComponent(preview); - gridPanel.add(borderButton = new ColorButton(parent, themeData, isActive ? ThemeData.FILE_TABLE_SELECTED_OUTLINE_COLOR : - ThemeData.FILE_TABLE_INACTIVE_SELECTED_OUTLINE_COLOR, PreviewLabel.BORDER_COLOR_PROPERTY_NAME)); + borderButton = new ColorButton(parent, themeData, active ? ThemeData.FILE_TABLE_SELECTED_OUTLINE_COLOR : + ThemeData.FILE_TABLE_INACTIVE_SELECTED_OUTLINE_COLOR, PreviewLabel.BORDER_COLOR_PROPERTY_NAME); + gridPanel.add(borderButton); borderButton.addUpdatedPreviewComponent(preview); setLayout(new BorderLayout()); diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FilePreviewPanel.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FilePreviewPanel.java index 25de30b263..4de7cc3502 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FilePreviewPanel.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FilePreviewPanel.java @@ -40,12 +40,13 @@ class FilePreviewPanel extends JScrollPane implements PropertyChangeListener { // - Row identifiers ------------------------------------------------------------------ // ----------------------------------------------------------------------------------- - private static final int FOLDER = 0; - private static final int PLAIN_FILE = 1; - private static final int ARCHIVE = 2; - private static final int HIDDEN_FILE = 3; - private static final int SYMLINK = 4; - private static final int MARKED_FILE = 5; + private static final int FOLDER = 0; + private static final int PLAIN_FILE = 1; + private static final int ARCHIVE = 2; + private static final int HIDDEN_FILE = 3; + private static final int SYMLINK = 4; + private static final int READ_ONLY_FILE = 5; + private static final int MARKED_FILE = 6; @@ -136,6 +137,7 @@ public PreviewTable() { {"", Translator.get("theme_editor.archive_file")}, {"", Translator.get("theme_editor.hidden_file")}, {"", Translator.get("theme_editor.symbolic_link")}, + {"", Translator.get("theme_editor.read_only_file")}, {"", Translator.get("theme_editor.marked_file")}}, new String[] {"", Translator.get("preview")}); @@ -291,6 +293,13 @@ private Color getForegroundColor(int row, boolean isSelected) { return FilePreviewPanel.this.data.getColor(isSelected ? ThemeData.SYMLINK_INACTIVE_SELECTED_FOREGROUND_COLOR : ThemeData.SYMLINK_INACTIVE_FOREGROUND_COLOR); + // Read-only + case READ_ONLY_FILE: + if (FilePreviewPanel.this.isActive) + return FilePreviewPanel.this.data.getColor(isSelected ? ThemeData.READ_ONLY_SELECTED_FOREGROUND_COLOR : + ThemeData.READ_ONLY_FOREGROUND_COLOR); + return FilePreviewPanel.this.data.getColor(isSelected ? ThemeData.READ_ONLY_INACTIVE_SELECTED_FOREGROUND_COLOR : + ThemeData.READ_ONLY_INACTIVE_FOREGROUND_COLOR); // Marked files. case MARKED_FILE: if(FilePreviewPanel.this.isActive) diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FolderPanePanel.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FolderPanePanel.java index 097755992c..ede6629751 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FolderPanePanel.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/FolderPanePanel.java @@ -17,6 +17,13 @@ package com.mucommander.ui.dialog.pref.theme; +import java.awt.BorderLayout; +import java.awt.FlowLayout; + +import javax.swing.BorderFactory; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; + import com.mucommander.commons.util.ui.layout.ProportionalGridPanel; import com.mucommander.commons.util.ui.layout.YBoxPanel; import com.mucommander.text.Translator; @@ -24,9 +31,6 @@ import com.mucommander.ui.dialog.pref.PreferencesDialog; import com.mucommander.ui.theme.ThemeData; -import javax.swing.*; -import java.awt.*; - /** * @author Nicolas Rinaudo, Maxence Bernard */ @@ -52,18 +56,15 @@ public FolderPanePanel(PreferencesDialog parent, ThemeData themeData) { * Initialises the panel's UI. */ private void initUI() { - JTabbedPane tabbedPane; - FontChooser fontChooser; - FilePanel filePanel; - - tabbedPane = new JTabbedPane(JTabbedPane.TOP); + JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); // Adds the general panel. + FontChooser fontChooser = createFontChooser(ThemeData.FILE_TABLE_FONT); tabbedPane.add(Translator.get("theme_editor.general"), - createScrollPane(createGeneralPanel(fontChooser = createFontChooser(ThemeData.FILE_TABLE_FONT)))); + createScrollPane(createGeneralPanel(fontChooser))); // Adds the active panel. - filePanel = new FilePanel(parent, true, themeData, fontChooser); + FilePanel filePanel = new FilePanel(parent, true, themeData, fontChooser); tabbedPane.add(filePanel.getTitle(), createScrollPane(filePanel)); // Adds the inactive panel. @@ -79,28 +80,23 @@ private void initUI() { * Creates the 'general' theme. */ private JPanel createGeneralPanel(FontChooser chooser) { - YBoxPanel mainPanel; - JPanel quickSearchPanel; - ProportionalGridPanel panel; - JPanel wrapper; - // Initialises the quicksearch panel. - panel = new ProportionalGridPanel(4); + ProportionalGridPanel panel = new ProportionalGridPanel(4); addLabelRow(panel); panel.add(addColorButtons(panel, chooser, "theme_editor.quick_search.unmatched_file", ThemeData.FILE_TABLE_UNMATCHED_FOREGROUND_COLOR, ThemeData.FILE_TABLE_UNMATCHED_BACKGROUND_COLOR)); - quickSearchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JPanel quickSearchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); quickSearchPanel.add(panel); quickSearchPanel.setBorder(BorderFactory.createTitledBorder(Translator.get("theme_editor.quick_search"))); // Initialises the panel. - mainPanel = new YBoxPanel(); + YBoxPanel mainPanel = new YBoxPanel(); mainPanel.add(chooser); mainPanel.addSpace(10); mainPanel.add(quickSearchPanel); // Wraps everything in a border layout. - wrapper = new JPanel(new BorderLayout()); + JPanel wrapper = new JPanel(new BorderLayout()); wrapper.add(mainPanel, BorderLayout.NORTH); return wrapper; } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/ThemeEditorPanel.java b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/ThemeEditorPanel.java index 8918b74e24..97082d6c82 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/ThemeEditorPanel.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/dialog/pref/theme/ThemeEditorPanel.java @@ -85,9 +85,7 @@ public ThemeEditorPanel(PreferencesDialog parent, String title, ThemeData themeD * @return a caption label containing the specified localised entry. */ protected JLabel createCaptionLabel(String dictionaryKey) { - JLabel captionLabel; - - captionLabel = new JLabel(Translator.get(dictionaryKey)); + JLabel captionLabel = new JLabel(Translator.get(dictionaryKey)); captionLabel.setFont(captionLabelFont); captionLabel.setForeground(captionTextColor); @@ -125,7 +123,7 @@ protected void addLabelRow(ProportionalGridPanel panel, boolean includePreview) panel.add(createCaptionLabel("theme_editor.background")); // Adds the preview label if requested. - if(includePreview) + if (includePreview) panel.add(createCaptionLabel("preview")); } @@ -138,13 +136,11 @@ protected void addLabelRow(ProportionalGridPanel panel, boolean includePreview) * @param fontId identifier of the font this chooser will be editing. */ protected FontChooser createFontChooser(int fontId) { - FontChooser fontChooser; // Font chooser that will be returned. - ChangeListener listener; // Internal listener. - // Initialises the font chooser. - fontChooser = new FontChooser(themeData.getFont(fontId)); + FontChooser fontChooser = new FontChooser(themeData.getFont(fontId)); fontChooser.setBorder(BorderFactory.createTitledBorder(Translator.get("theme_editor.font"))); - fontChooser.addChangeListener(listener = new ThemeFontChooserListener(themeData, fontId, parent)); + ChangeListener listener = new ThemeFontChooserListener(themeData, fontId, parent); + fontChooser.addChangeListener(listener); // Hold a reference to this listener to prevent garbage collection listenerReferences.add(listener); @@ -163,7 +159,7 @@ protected FontChooser createFontChooser(int fontId) { */ protected void addFontChooserListener(FontChooser fontChooser, JComponent previewComponent) { // Update button font when a new font has been chosen in the FontChooser - if(fontChooser!=null) { + if (fontChooser!=null) { ChangeListener listener; fontChooser.addChangeListener(listener = new PreviewFontChooserListener(previewComponent)); previewComponent.setFont(fontChooser.getCurrentFont()); @@ -185,9 +181,7 @@ protected void addFontChooserListener(FontChooser fontChooser, JComponent previe * @param panel panel to wrap in a JScrollPane. */ protected JComponent createScrollPane(JPanel panel) { - JScrollPane scrollPane; - - scrollPane = new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + JScrollPane scrollPane = new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setBorder(null); return scrollPane; @@ -228,25 +222,24 @@ protected PreviewLabel addColorButtons(ProportionalGridPanel gridPanel, FontChoo * @param comp component to register as a listener on the color buttons. */ protected PreviewLabel addColorButtons(ProportionalGridPanel gridPanel, FontChooser fontChooser, String label, int foregroundId, int backgroundId, JComponent comp) { - ColorButton colorButton; - PreviewLabel previewLabel; - // Adds the row's caption label. gridPanel.add(createCaptionLabel(label)); // Initialises the color buttons' preview label. - previewLabel = new PreviewLabel(); + PreviewLabel previewLabel = new PreviewLabel(); previewLabel.setTextPainted(true); addFontChooserListener(fontChooser, previewLabel); // Creates the foreground color button. - gridPanel.add(colorButton = new ColorButton(parent, themeData, foregroundId, PreviewLabel.FOREGROUND_COLOR_PROPERTY_NAME, previewLabel)); - if(comp != null) + ColorButton colorButton = new ColorButton(parent, themeData, foregroundId, PreviewLabel.FOREGROUND_COLOR_PROPERTY_NAME, previewLabel); + gridPanel.add(colorButton); + if (comp != null) colorButton.addUpdatedPreviewComponent(comp); // Creates the background color button. - gridPanel.add(colorButton = new ColorButton(parent, themeData, backgroundId, PreviewLabel.BACKGROUND_COLOR_PROPERTY_NAME, previewLabel)); - if(comp != null) + colorButton = new ColorButton(parent, themeData, backgroundId, PreviewLabel.BACKGROUND_COLOR_PROPERTY_NAME, previewLabel); + gridPanel.add(colorButton); + if (comp != null) colorButton.addUpdatedPreviewComponent(comp); return previewLabel; diff --git a/mucommander-core/src/main/java/com/mucommander/ui/event/LocationManager.java b/mucommander-core/src/main/java/com/mucommander/ui/event/LocationManager.java index 3c75e8cfbf..99c5af4129 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/event/LocationManager.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/event/LocationManager.java @@ -26,8 +26,10 @@ import com.mucommander.commons.file.AbstractFile; import com.mucommander.commons.file.FileURL; import com.mucommander.commons.file.MonitoredFile; +import com.mucommander.commons.file.archive.AbstractArchiveFile; import com.mucommander.core.FolderChangeMonitor; import com.mucommander.core.GlobalLocationHistory; +import com.mucommander.ui.dialog.file.ArchivePasswordDialog; import com.mucommander.ui.main.ConfigurableFolderFilter; import com.mucommander.ui.main.FolderPanel; @@ -83,16 +85,27 @@ public void setCurrentFolder(AbstractFile folder, AbstractFile fileToSelect, boo MonitoredFile newCurrentFile = folder.toMonitoredFile(); newCurrentFile.startWatch(); - AbstractFile[] children = emptyAbstractFilesArray; - try { - children = folder.ls(configurableFolderFilter); - firstRun = false; - } catch (Exception e) { - LOGGER.debug("Couldn't ls children of " + folder.getAbsolutePath() + ", error: " + e.getMessage()); - if (!firstRun) { - throw new RuntimeException(e.getMessage()); - } - } + AbstractFile[] children = emptyAbstractFilesArray; + do { + try { + children = folder.ls(configurableFolderFilter); + firstRun = false; + } catch (Exception e) { + LOGGER.debug("Couldn't ls children of " + folder.getAbsolutePath() + ", error: " + e.getMessage()); + if (folder.isArchive()) { + ArchivePasswordDialog dialog = new ArchivePasswordDialog(folderPanel.getMainFrame()); + String password = (String) dialog.getUserInput(); + if (password != null) { + ((AbstractArchiveFile) folder).setPassword(password); + continue; + } + } + if (!firstRun) { + throw new RuntimeException(e.getMessage()); + } + } + break; + } while (true); folderPanel.setCurrentFolder(folder, children, fileToSelect, changeLockedTab); diff --git a/mucommander-core/src/main/java/com/mucommander/ui/main/ConfigurableFolderFilter.java b/mucommander-core/src/main/java/com/mucommander/ui/main/ConfigurableFolderFilter.java index 038414c371..04afc65296 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/main/ConfigurableFolderFilter.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/main/ConfigurableFolderFilter.java @@ -54,17 +54,17 @@ public ConfigurableFolderFilter() { private void configureFilters() { // Filters out hidden files, null when 'show hidden files' option is enabled - if(!MuConfigurations.getPreferences().getVariable(MuPreference.SHOW_HIDDEN_FILES, MuPreferences.DEFAULT_SHOW_HIDDEN_FILES)) { + if (!MuConfigurations.getPreferences().getVariable(MuPreference.SHOW_HIDDEN_FILES, MuPreferences.DEFAULT_SHOW_HIDDEN_FILES)) { // This filter is inverted and matches non-hidden files addFileFilter(hiddenFileFilter); } // Filters out Mac OS X .DS_Store files, null when 'show DS_Store files' option is enabled - if(!MuConfigurations.getPreferences().getVariable(MuPreference.SHOW_DS_STORE_FILES, MuPreferences.DEFAULT_SHOW_DS_STORE_FILES)) + if (!MuConfigurations.getPreferences().getVariable(MuPreference.SHOW_DS_STORE_FILES, MuPreferences.DEFAULT_SHOW_DS_STORE_FILES)) addFileFilter(dsFileFilter); /** Filters out Mac OS X system folders, null when 'show system folders' option is enabled */ - if(!MuConfigurations.getPreferences().getVariable(MuPreference.SHOW_SYSTEM_FOLDERS, MuPreferences.DEFAULT_SHOW_SYSTEM_FOLDERS)) + if (!MuConfigurations.getPreferences().getVariable(MuPreference.SHOW_SYSTEM_FOLDERS, MuPreferences.DEFAULT_SHOW_SYSTEM_FOLDERS)) addFileFilter(systemFileFilter); } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/main/MainFrame.java b/mucommander-core/src/main/java/com/mucommander/ui/main/MainFrame.java index a1fe0c78d5..c73d01891a 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/main/MainFrame.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/main/MainFrame.java @@ -49,7 +49,6 @@ import com.mucommander.snapshot.MuSnapshot; import com.mucommander.ui.action.ActionKeymap; import com.mucommander.ui.action.ActionManager; -import com.mucommander.ui.action.impl.CloseWindowAction; import com.mucommander.ui.button.ToolbarMoreButton; import com.mucommander.ui.event.ActivePanelListener; import com.mucommander.ui.event.LocationEvent; diff --git a/mucommander-core/src/main/java/com/mucommander/ui/main/StatusBar.java b/mucommander-core/src/main/java/com/mucommander/ui/main/StatusBar.java index 281d908e81..75a668bfbf 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/main/StatusBar.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/main/StatusBar.java @@ -17,20 +17,21 @@ package com.mucommander.ui.main; +import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Graphics; +import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; +import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.io.IOException; import javax.swing.Box; -import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JLabel; @@ -44,8 +45,6 @@ import com.mucommander.commons.conf.ConfigurationEvent; import com.mucommander.commons.conf.ConfigurationListener; import com.mucommander.commons.file.AbstractFile; -import com.mucommander.commons.util.cache.FastLRUCache; -import com.mucommander.commons.util.cache.LRUCache; import com.mucommander.commons.util.ui.border.MutableLineBorder; import com.mucommander.conf.MuConfigurations; import com.mucommander.conf.MuPreference; @@ -87,7 +86,7 @@ * * @author Maxence Bernard */ -public class StatusBar extends JPanel implements Runnable, MouseListener, ActivePanelListener, TableSelectionListener, LocationListener, ComponentListener, ThemeListener { +public class StatusBar extends JPanel { private static final Logger LOGGER = LoggerFactory.getLogger(StatusBar.class); private MainFrame mainFrame; @@ -128,6 +127,12 @@ public class StatusBar extends JPanel implements Runnable, MouseListener, Active /** Holds the path of the volume for which free/total space was last retrieved by {@link #autoUpdateThread} */ private String volumePath; + /** hold references to listeners that are stored with weak references to prevent them from being collected by the garbage collector */ + private LocationListener locationListener; + private TableSelectionListener tableSelectionListener; + private ActivePanelListener activePanelListener; + private ThemeListener themeListener; + static { // Initialize the size column format based on the configuration setSelectedFileSizeFormat(MuConfigurations.getPreferences().getVariable(MuPreference.DISPLAY_COMPACT_FILE_SIZE, @@ -167,52 +172,93 @@ private static void setSelectedFileSizeFormat(boolean compactSize) { */ public StatusBar(MainFrame mainFrame) { // Create and add status bar - setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + setLayout(new BorderLayout()); this.mainFrame = mainFrame; selectedFilesLabel = new JLabel(""); dial = new SpinningDial(); - add(selectedFilesLabel); + add(selectedFilesLabel, BorderLayout.CENTER); - add(Box.createHorizontalGlue()); + JPanel eastPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); JobsPopupButton jobsButton = new JobsPopupButton(); jobsButton.setPopupMenuLocation(SwingConstants.TOP); - add(jobsButton); - add(Box.createRigidArea(new Dimension(2, 0))); + eastPanel.add(jobsButton); + eastPanel.add(Box.createRigidArea(new Dimension(2, 0))); // Add a button for interacting with the trash, only if the current platform has a trash implementation - if(DesktopManager.getTrash()!=null) { + if (DesktopManager.getTrash() != null) { TrashPopupButton trashButton = new TrashPopupButton(mainFrame); trashButton.setPopupMenuLocation(SwingConstants.TOP); - add(trashButton); - add(Box.createRigidArea(new Dimension(2, 0))); + eastPanel.add(trashButton); + eastPanel.add(Box.createRigidArea(new Dimension(2, 0))); } volumeSpaceLabel = new VolumeSpaceLabel(); - add(volumeSpaceLabel); + eastPanel.add(volumeSpaceLabel); + + add(eastPanel, BorderLayout.EAST); // Show/hide this status bar based on user preferences // Note: setVisible has to be called even with true for the auto-update thread to be initialized setVisible(MuConfigurations.getPreferences().getVariable(MuPreference.STATUS_BAR_VISIBLE, MuPreferences.DEFAULT_STATUS_BAR_VISIBLE)); // Catch location events to update status bar info when folder is changed + locationListener = new LocationListener() { + @Override + public void locationChanged(LocationEvent e) { + dial.setAnimated(false); + updateStatusInfo(); + } + @Override + public void locationChanging(LocationEvent e) { + // Show a message in the status bar saying that folder is being changed + setStatusInfo(Translator.get("status_bar.connecting_to_folder"), dial, true); + dial.setAnimated(true); + } + @Override + public void locationCancelled(LocationEvent e) { + dial.setAnimated(false); + updateStatusInfo(); + } + @Override + public void locationFailed(LocationEvent e) { + dial.setAnimated(false); + updateStatusInfo(); + } + }; + FolderPanel leftPanel = mainFrame.getLeftPanel(); - leftPanel.getLocationManager().addLocationListener(this); + leftPanel.getLocationManager().addLocationListener(locationListener); FolderPanel rightPanel = mainFrame.getRightPanel(); - rightPanel.getLocationManager().addLocationListener(this); + rightPanel.getLocationManager().addLocationListener(locationListener); // Catch table selection change events to update the selected files info when the selected files have changed on // one of the file tables - leftPanel.getFileTable().addTableSelectionListener(this); - rightPanel.getFileTable().addTableSelectionListener(this); + tableSelectionListener = new TableSelectionListener() { + @Override + public void selectedFileChanged(FileTable source) { + // No need to update if the originating FileTable is not the currently active one + if(source==mainFrame.getActiveTable() && mainFrame.isForegroundActive()) + updateSelectedFilesInfo(); + } + @Override + public void markedFilesChanged(FileTable source) { + // No need to update if the originating FileTable is not the currently active one + if(source==mainFrame.getActiveTable() && mainFrame.isForegroundActive()) + updateSelectedFilesInfo(); + } + }; + leftPanel.getFileTable().addTableSelectionListener(tableSelectionListener); + rightPanel.getFileTable().addTableSelectionListener(tableSelectionListener); // Catch active panel change events to update status bar info when current table has changed - mainFrame.addActivePanelListener(this); + activePanelListener = folderPanel -> updateStatusInfo(); + mainFrame.addActivePanelListener(activePanelListener); // Catch main frame close events to make sure autoUpdateThread is finished mainFrame.addWindowListener(new WindowAdapter() { @@ -232,20 +278,62 @@ public void windowGainedFocus(WindowEvent e) { }); // Catch mouse events to pop up a menu on right-click - selectedFilesLabel.addMouseListener(this); - volumeSpaceLabel.addMouseListener(this); - addMouseListener(this); + MouseAdapter mouseAdapter = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + // Discard mouse events while in 'no events mode' + if (mainFrame.getNoEventsMode()) + return; + + // Right clicking on the toolbar brings up a popup menu that allows the user to hide this status bar + if (DesktopManager.isRightMouseButton(e)) { + // if (e.isPopupTrigger()) { // Doesn't work under Mac OS X (CTRL+click doesn't return true) + JPopupMenu popupMenu = new JPopupMenu(); + popupMenu.add(ActionManager.getActionInstance(ActionType.ToggleStatusBar, mainFrame)); + popupMenu.show(StatusBar.this, e.getX(), e.getY()); + popupMenu.setVisible(true); + } + }; + }; + selectedFilesLabel.addMouseListener(mouseAdapter); + volumeSpaceLabel.addMouseListener(mouseAdapter); + addMouseListener(mouseAdapter); // Catch component events to be notified when this component is made visible // and update status info - addComponentListener(this); + addComponentListener(new ComponentAdapter() { + @Override + public void componentShown(ComponentEvent e) { + // Invoked when the component has been made visible (apparently not called when just created) + // Status bar needs to be updated since it is not updated when not visible + updateStatusInfo(); + }; + }); // Initialises theme. selectedFilesLabel.setFont(ThemeManager.getCurrentFont(Theme.STATUS_BAR_FONT)); selectedFilesLabel.setForeground(ThemeManager.getCurrentColor(Theme.STATUS_BAR_FOREGROUND_COLOR)); volumeSpaceLabel.setFont(ThemeManager.getCurrentFont(Theme.STATUS_BAR_FONT)); volumeSpaceLabel.setForeground(ThemeManager.getCurrentColor(Theme.STATUS_BAR_FOREGROUND_COLOR)); - ThemeManager.addCurrentThemeListener(this); + themeListener = new ThemeListener() { + @Override + public void fontChanged(FontChangedEvent event) { + if(event.getFontId() == Theme.STATUS_BAR_FONT) { + selectedFilesLabel.setFont(event.getFont()); + volumeSpaceLabel.setFont(event.getFont()); + repaint(); + } + } + @Override + public void colorChanged(ColorChangedEvent event) { + if(event.getColorId() == Theme.STATUS_BAR_FOREGROUND_COLOR) { + selectedFilesLabel.setForeground(event.getColor()); + volumeSpaceLabel.setForeground(event.getColor()); + repaint(); + } + } + }; + ThemeManager.addCurrentThemeListener(themeListener); } @@ -291,25 +379,27 @@ public void updateSelectedFilesInfo() { else nbSelectedFiles = nbMarkedFiles; - String filesInfo; + StringBuilder filesInfo = new StringBuilder(); + String tooltip = null; - if(fileCount==0) { + if (fileCount==0) { // Set status bar to a space character, not an empty string // otherwise it will disappear - filesInfo = " "; - } - else { - filesInfo = Translator.get("status_bar.selected_files", ""+nbSelectedFiles, ""+fileCount); + filesInfo.append(" "); + } else { + filesInfo.append(Translator.get("status_bar.selected_files", nbSelectedFiles, fileCount)); - if(nbMarkedFiles>0) - filesInfo += " - " + SizeFormat.format(markedTotalSize, selectedFileSizeFormat); + if (nbMarkedFiles > 0) + filesInfo.append(String.format(" - %s", SizeFormat.format(markedTotalSize, selectedFileSizeFormat))); - if(selectedFile!=null) - filesInfo += " - "+selectedFile.getName(); + if (selectedFile != null) { + filesInfo.append(String.format(" - %s", selectedFile.getName())); + tooltip = selectedFile.getName(); + } } // Update label - setStatusInfo(filesInfo); + setStatusInfo(filesInfo.toString(), tooltip, null, false); } @@ -322,7 +412,12 @@ public void updateSelectedFilesInfo() { * @param iconBeforeText if true, icon will be placed on the left side of the text, if not on the right side */ public void setStatusInfo(String text, Icon icon, boolean iconBeforeText) { + setStatusInfo(text, null, icon, iconBeforeText); + } + + private void setStatusInfo(String text, String tooltip, Icon icon, boolean iconBeforeText) { selectedFilesLabel.setText(text); + selectedFilesLabel.setToolTipText(tooltip); if(icon==null) { // What we don't want here is the label's height to change depending on whether it has an icon or not. @@ -357,7 +452,37 @@ public void setStatusInfo(String infoMessage) { private synchronized void startAutoUpdate() { if (autoUpdateThread==null) { // Start volume info auto-update thread - autoUpdateThread = new Thread(this, "StatusBar autoUpdateThread"); + autoUpdateThread = new Thread(() -> { + // Periodically updates volume info (free / total space). + while (!mainFrameDisposed) { // Stop when MainFrame is disposed + // Update volume info if: + // - status bar is visible + // - MainFrame is active and in the foreground + // Volume info update will potentially hit the LRU cache and not actually update volume info + if (isVisible() && mainFrame.isForegroundActive()) { + final AbstractFile currentFolder = getCurrentFolder(); + volumePath = getVolumePath(currentFolder); + + // Retrieves free and total volume space. + long volumeFree = getFreeSpace(currentFolder); + long volumeTotal = getTotalSpace(currentFolder); + + volumeSpaceLabel.setVolumeSpace(volumeTotal, volumeFree); + } + + // Sleep for a while + if (!autoUpdateThreadNotified) { + synchronized(autoUpdateThread) { + if (!autoUpdateThreadNotified) { + try { autoUpdateThread.wait(AUTO_UPDATE_PERIOD); } + catch (InterruptedException e) {} + } + } + } + autoUpdateThreadNotified = false; + } + }); + autoUpdateThread.setName("StatusBar autoUpdateThread"); // Set the thread as a daemon thread autoUpdateThread.setDaemon(true); autoUpdateThread.start(); @@ -380,35 +505,6 @@ public void setVisible(boolean visible) { } - ////////////////////// - // Runnable methods // - ////////////////////// - - /** - * Periodically updates volume info (free / total space). - */ - public void run() { - while (!mainFrameDisposed) { // Stop when MainFrame is disposed - // Update volume info if: - // - status bar is visible - // - MainFrame is active and in the foreground - // Volume info update will potentially hit the LRU cache and not actually update volume info - if (isVisible() && mainFrame.isForegroundActive()) { - final AbstractFile currentFolder = getCurrentFolder(); - volumePath = getVolumePath(currentFolder); - - // Retrieves free and total volume space. - long volumeFree = getFreeSpace(currentFolder); - long volumeTotal = getTotalSpace(currentFolder); - - volumeSpaceLabel.setVolumeSpace(volumeTotal, volumeFree); - } - - // Sleep for a while - sleep(); - } - } - private AbstractFile getCurrentFolder() { return mainFrame.getActivePanel().getCurrentFolder(); } @@ -421,20 +517,8 @@ private boolean isVolumeChanged() { return volumePath == null || !volumePath.equals(getVolumePath(getCurrentFolder())); } - private void sleep() { - if (!autoUpdateThreadNotified) { - synchronized(autoUpdateThread) { - if (!autoUpdateThreadNotified) { - try { autoUpdateThread.wait(AUTO_UPDATE_PERIOD); } - catch (InterruptedException e) {} - } - } - } - autoUpdateThreadNotified = false; - } - private void triggerVolumeInfoUpdate() { - if (!autoUpdateThreadNotified) { + if (!autoUpdateThreadNotified && autoUpdateThread != null) { synchronized(autoUpdateThread) { if (!autoUpdateThreadNotified) { autoUpdateThreadNotified = true; @@ -460,127 +544,6 @@ private long getTotalSpace(AbstractFile currentFolder) { catch(IOException e) { return -1; } } - //////////////////////////////////////// - // ActivePanelListener implementation // - //////////////////////////////////////// - - public void activePanelChanged(FolderPanel folderPanel) { - updateStatusInfo(); - } - - - /////////////////////////////////////////// - // TableSelectionListener implementation // - /////////////////////////////////////////// - - public void selectedFileChanged(FileTable source) { - // No need to update if the originating FileTable is not the currently active one - if(source==mainFrame.getActiveTable() && mainFrame.isForegroundActive()) - updateSelectedFilesInfo(); - } - - public void markedFilesChanged(FileTable source) { - // No need to update if the originating FileTable is not the currently active one - if(source==mainFrame.getActiveTable() && mainFrame.isForegroundActive()) - updateSelectedFilesInfo(); - } - - - ///////////////////////////////////// - // LocationListener implementation // - ///////////////////////////////////// - - public void locationChanged(LocationEvent e) { - dial.setAnimated(false); - updateStatusInfo(); - } - - public void locationChanging(LocationEvent e) { - // Show a message in the status bar saying that folder is being changed - setStatusInfo(Translator.get("status_bar.connecting_to_folder"), dial, true); - dial.setAnimated(true); - } - - public void locationCancelled(LocationEvent e) { - dial.setAnimated(false); - updateStatusInfo(); - } - - public void locationFailed(LocationEvent e) { - dial.setAnimated(false); - updateStatusInfo(); - } - - - ////////////////////////////////// - // MouseListener implementation // - ////////////////////////////////// - - public void mouseClicked(MouseEvent e) { - // Discard mouse events while in 'no events mode' - if(mainFrame.getNoEventsMode()) - return; - - // Right clicking on the toolbar brings up a popup menu that allows the user to hide this status bar - if (DesktopManager.isRightMouseButton(e)) { - // if (e.isPopupTrigger()) { // Doesn't work under Mac OS X (CTRL+click doesn't return true) - JPopupMenu popupMenu = new JPopupMenu(); - popupMenu.add(ActionManager.getActionInstance(ActionType.ToggleStatusBar, mainFrame)); - popupMenu.show(this, e.getX(), e.getY()); - popupMenu.setVisible(true); - } - } - - public void mouseReleased(MouseEvent e) { - } - - public void mousePressed(MouseEvent e) { - } - - public void mouseEntered(MouseEvent e) { - } - - public void mouseExited(MouseEvent e) { - } - - - ////////////////////////////////////// - // ComponentListener implementation // - ////////////////////////////////////// - - public void componentShown(ComponentEvent e) { - // Invoked when the component has been made visible (apparently not called when just created) - // Status bar needs to be updated since it is not updated when not visible - updateStatusInfo(); - } - - public void componentHidden(ComponentEvent e) { - } - - public void componentMoved(ComponentEvent e) { - } - - public void componentResized(ComponentEvent e) { - } - - - public void fontChanged(FontChangedEvent event) { - if(event.getFontId() == Theme.STATUS_BAR_FONT) { - selectedFilesLabel.setFont(event.getFont()); - volumeSpaceLabel.setFont(event.getFont()); - repaint(); - } - } - - public void colorChanged(ColorChangedEvent event) { - if(event.getColorId() == Theme.STATUS_BAR_FOREGROUND_COLOR) { - selectedFilesLabel.setForeground(event.getColor()); - volumeSpaceLabel.setForeground(event.getColor()); - repaint(); - } - } - - /////////////////// // Inner classes // /////////////////// diff --git a/mucommander-core/src/main/java/com/mucommander/ui/main/commandbar/CommandBar.java b/mucommander-core/src/main/java/com/mucommander/ui/main/commandbar/CommandBar.java index b28a3f20cf..2679b7d52a 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/main/commandbar/CommandBar.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/main/commandbar/CommandBar.java @@ -17,25 +17,34 @@ package com.mucommander.ui.main.commandbar; +import java.awt.GridLayout; +import java.awt.Point; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.Arrays; + +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; + import com.mucommander.core.desktop.DesktopManager; import com.mucommander.desktop.ActionType; import com.mucommander.ui.action.ActionManager; import com.mucommander.ui.main.MainFrame; -import javax.swing.*; -import java.awt.*; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; - /** * CommandBar is the button bar that sits at the bottom of the main window and provides access to * main commander actions (view, edit, copy, move...). * * @author Maxence Bernard, Arik Hadas */ -public class CommandBar extends JPanel implements KeyListener, MouseListener, CommandBarAttributesListener { +public class CommandBar extends JPanel { /** Parent MainFrame instance */ private MainFrame mainFrame; @@ -62,19 +71,65 @@ public CommandBar(MainFrame mainFrame) { this.mainFrame = mainFrame; // Listen to modifier key events to display alternate actions - mainFrame.getLeftPanel().getFileTable().addKeyListener(this); - mainFrame.getRightPanel().getFileTable().addKeyListener(this); + KeyAdapter keyAdapter = new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + // Display alternate actions when the modifier key is pressed + if (e.getKeyCode() == modifier.getKeyCode()) + setAlternateActionsMode(true); + } + @Override + public void keyReleased(KeyEvent e) { + // Display regular actions when the modifier key is released + if (e.getKeyCode() == modifier.getKeyCode()) + setAlternateActionsMode(false); + } + }; + mainFrame.getLeftPanel().getFileTable().addKeyListener(keyAdapter); + mainFrame.getRightPanel().getFileTable().addKeyListener(keyAdapter); // Listen to mouse events to popup a menu when command bar is right clicked - addMouseListener(this); + MouseAdapter mouseAdapter = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + // Right clicking on the toolbar brings up a popup menu + if (DesktopManager.isRightMouseButton(e)) { + // if (e.isPopupTrigger()) { // Doesn't work under Mac OS X (CTRL+click doesn't return true) + JPopupMenu popupMenu = new JPopupMenu(); + popupMenu.add(ActionManager.getActionInstance(ActionType.ToggleCommandBar, mainFrame)); + popupMenu.add(ActionManager.getActionInstance(ActionType.CustomizeCommandBar, mainFrame)); + // Get the click location in the CommandBar's coordinate system. + // The location returned by the MouseEvent is in the source component (button) coordinate system. it's converted using SwingUtilities to the CommandBar's coordinate system. + Point clickLocation = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), CommandBar.this); + popupMenu.show(CommandBar.this, clickLocation.x, clickLocation.y); + popupMenu.setVisible(true); + } + } + }; + addMouseListener(mouseAdapter); actionIds = CommandBarAttributes.getActions(); alternateActionIds = CommandBarAttributes.getAlternateActions(); modifier = CommandBarAttributes.getModifier(); - addButtons(); + addButtons(mouseAdapter); - CommandBarAttributes.addCommandBarAttributesListener(this); + CommandBarAttributesListener commandBarAttributesListener = () -> { + actionIds = CommandBarAttributes.getActions(); + alternateActionIds = CommandBarAttributes.getAlternateActions(); + modifier = CommandBarAttributes.getModifier(); + removeAll(); + addButtons(mouseAdapter); + doLayout(); + }; + CommandBarAttributes.addCommandBarAttributesListener(commandBarAttributesListener); + + mainFrame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + CommandBarAttributes.removeCommandBarAttributesListener(commandBarAttributesListener); + } + }); } /** @@ -82,17 +137,19 @@ public CommandBar(MainFrame mainFrame) { * * actions array must be initialized before this function is called. */ - private void addButtons() { + private void addButtons(MouseListener mouseListener) { setLayout(new GridLayout(0,actionIds.length)); - // Create buttons and add them to this command bar - int nbButtons = actionIds.length; - buttons = new CommandBarButton[nbButtons]; - for(int i=0; i { + CommandBarButton button = CommandBarButton.create(action, mainFrame); + button.addMouseListener(mouseListener); + return button; + }) + .toArray(CommandBarButton[]::new); + // And add them to this command bar + Arrays.stream(buttons).forEach(this::add); } /** @@ -101,10 +158,10 @@ private void addButtons() { */ public void setAlternateActionsMode(boolean on) { // Do nothing if command bar is not currently visible - if(!isVisible()) + if (!isVisible()) return; - if(this.modifierDown != on) { + if (this.modifierDown != on) { this.modifierDown = on; int nbButtons = buttons.length; @@ -112,68 +169,4 @@ public void setAlternateActionsMode(boolean on) { buttons[i].setButtonAction(on && alternateActionIds[i]!=null?alternateActionIds[i]:actionIds[i], mainFrame); } } - - ///////////////////////// - // KeyListener methods // - ///////////////////////// - - public void keyPressed(KeyEvent e) { - // Display alternate actions when the modifier key is pressed - if(e.getKeyCode() == modifier.getKeyCode()) - setAlternateActionsMode(true); - } - - public void keyReleased(KeyEvent e) { - // Display regular actions when the modifier key is released - if(e.getKeyCode() == modifier.getKeyCode()) - setAlternateActionsMode(false); - } - - public void keyTyped(KeyEvent e) { - } - - /////////////////////////// - // MouseListener methods // - /////////////////////////// - - public void mouseClicked(MouseEvent e) { - // Right clicking on the toolbar brings up a popup menu - if (DesktopManager.isRightMouseButton(e)) { - // if (e.isPopupTrigger()) { // Doesn't work under Mac OS X (CTRL+click doesn't return true) - JPopupMenu popupMenu = new JPopupMenu(); - popupMenu.add(ActionManager.getActionInstance(ActionType.ToggleCommandBar, mainFrame)); - popupMenu.add(ActionManager.getActionInstance(ActionType.CustomizeCommandBar, mainFrame)); - // Get the click location in the CommandBar's coordinate system. - // The location returned by the MouseEvent is in the source component (button) coordinate system. it's converted using SwingUtilities to the CommandBar's coordinate system. - Point clickLocation = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), this); - popupMenu.show(this, clickLocation.x, clickLocation.y); - popupMenu.setVisible(true); - } - } - - public void mouseReleased(MouseEvent e) { - } - - public void mousePressed(MouseEvent e) { - } - - public void mouseEntered(MouseEvent e) { - } - - public void mouseExited(MouseEvent e) { - } - - - ////////////////////////////////////////// - // CommandBarAttributesListener methods // - ////////////////////////////////////////// - - public void commandBarAttributeChanged() { - actionIds = CommandBarAttributes.getActions(); - alternateActionIds = CommandBarAttributes.getAlternateActions(); - modifier = CommandBarAttributes.getModifier(); - removeAll(); - addButtons(); - doLayout(); - } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/main/commandbar/CommandBarAttributes.java b/mucommander-core/src/main/java/com/mucommander/ui/main/commandbar/CommandBarAttributes.java index 47a83dcfb6..0b7cd816e5 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/main/commandbar/CommandBarAttributes.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/main/commandbar/CommandBarAttributes.java @@ -22,7 +22,8 @@ import com.mucommander.desktop.ActionType; import java.awt.event.KeyEvent; -import java.util.WeakHashMap; +import java.util.ArrayList; +import java.util.List; /** * This class is responsible to handle the attributes of CommandBars - their actions, alternate actions and modifier. @@ -67,7 +68,7 @@ public class CommandBarAttributes { private static KeyStroke DEFAULT_MODIFIER = KeyStroke.getKeyStroke(KeyEvent.VK_SHIFT, 0); /** Contains all registered command-bar attributes listeners, stored as weak references */ - private static WeakHashMap listeners = new WeakHashMap(); + private static List listeners = new ArrayList<>(); /** * This method restore the default command-bar attributes. @@ -144,7 +145,7 @@ public static void setAttributes(String[] actionIds, String[] alternateActionIds // - Listeners ------------------------------------------------------------- // ------------------------------------------------------------------------- public static void addCommandBarAttributesListener(CommandBarAttributesListener listener) { - synchronized(listeners) {listeners.put(listener, null);} + synchronized(listeners) {listeners.add(listener);} } public static void removeCommandBarAttributesListener(CommandBarAttributesListener listener) { @@ -152,10 +153,9 @@ public static void removeCommandBarAttributesListener(CommandBarAttributesListen } protected static void fireAttributesChanged() { - synchronized(listeners) { + synchronized(listeners) { // Iterate on all listeners - for(CommandBarAttributesListener listener : listeners.keySet()) - listener.commandBarAttributeChanged(); + listeners.forEach(CommandBarAttributesListener::commandBarAttributeChanged); } } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/main/table/FileTable.java b/mucommander-core/src/main/java/com/mucommander/ui/main/table/FileTable.java index 721bd19d37..cdfc3fbe31 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/main/table/FileTable.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/main/table/FileTable.java @@ -69,8 +69,6 @@ import com.mucommander.ui.action.ActionKeymap; import com.mucommander.ui.action.ActionManager; import com.mucommander.ui.action.MuAction; -import com.mucommander.ui.action.impl.MarkNextRowAction; -import com.mucommander.ui.action.impl.MarkPreviousRowAction; import com.mucommander.ui.action.impl.MarkSelectedFileAction; import com.mucommander.ui.action.impl.RefreshAction; import com.mucommander.ui.dialog.file.AbstractCopyDialog; @@ -1057,7 +1055,7 @@ public void removeTableSelectionListener(TableSelectionListener listener) { /** * Notifies all registered listeners that the currently selected file has changed on this FileTable. */ - public void fireSelectedFileChangedEvent() { + private void fireSelectedFileChangedEvent() { tableSelectionListeners.keySet().forEach(listener -> listener.selectedFileChanged(this)); } @@ -1911,10 +1909,6 @@ public void run() { } } - public void updateSelectedFilesStatusbar() { - mainFrame.getStatusBar().updateSelectedFilesInfo(); - } - /** * Updates the header renderer of each column according to {@link FileTable#createHeaderRenderer} */ diff --git a/mucommander-core/src/main/java/com/mucommander/ui/main/table/FileTableCellRenderer.java b/mucommander-core/src/main/java/com/mucommander/ui/main/table/FileTableCellRenderer.java index e88a5d6dd7..c8936c65fc 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/main/table/FileTableCellRenderer.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/main/table/FileTableCellRenderer.java @@ -127,27 +127,32 @@ private void setCellLabelsFont(Font newFont) { private static int getColorIndex(int row, AbstractFile file, FileTableModel tableModel) { // Parent directory. - if(row==0 && tableModel.hasParentFolder()) + if (row==0 && tableModel.hasParentFolder()) return ThemeCache.FOLDER; // Marked file. - if(tableModel.isRowMarked(row)) + if (tableModel.isRowMarked(row)) return ThemeCache.MARKED; // Symlink. - if(file.isSymlink()) + if (file.isSymlink()) return ThemeCache.SYMLINK; // Hidden file. - if(file.isHidden()) + if (file.isHidden()) return ThemeCache.HIDDEN_FILE; + // Read-only file + int maskedPermissions = file.getPermissions().getIntValue() & 292; // 292 => 100100100 + if (file.getPermissions().getIntValue() == maskedPermissions && maskedPermissions > 0) + return ThemeCache.READ_ONLY; + // Directory. - if(file.isDirectory()) + if (file.isDirectory()) return ThemeCache.FOLDER; // Archive. - if(file.isBrowsable()) + if (file.isBrowsable()) return ThemeCache.ARCHIVE; // Plain file. @@ -225,7 +230,7 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole label.setText(leftText+"..."+rightText); } - // Set the toop + // Set the tooltip label.setToolTipText(text); } // Have to set it to null otherwise the defaultRender sets the tooltip text to the last one diff --git a/mucommander-core/src/main/java/com/mucommander/ui/main/tabs/FileTableTabs.java b/mucommander-core/src/main/java/com/mucommander/ui/main/tabs/FileTableTabs.java index 1281c01be2..fe56abfd33 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/main/tabs/FileTableTabs.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/main/tabs/FileTableTabs.java @@ -131,10 +131,6 @@ protected FileTableTab removeTab() { * MuActions support ********************/ - public void add(AbstractFile file, AbstractFile selectedFile) { - addTab(defaultTabsFactory.createTab(file.getURL(), selectedFile)); - } - public void add(AbstractFile file) { addTab(defaultTabsFactory.createTab(file.getURL())); } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/quicksearch/QuickSearch.java b/mucommander-core/src/main/java/com/mucommander/ui/quicksearch/QuickSearch.java index adb8db59c6..a0d78c4427 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/quicksearch/QuickSearch.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/quicksearch/QuickSearch.java @@ -20,6 +20,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.mucommander.commons.conf.ConfigurationEvent; +import com.mucommander.commons.conf.ConfigurationListener; +import com.mucommander.conf.MuConfigurations; +import com.mucommander.conf.MuPreference; +import com.mucommander.conf.MuPreferences; + import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; @@ -33,7 +39,7 @@ * * @author Arik Hadas */ -public abstract class QuickSearch extends KeyAdapter implements Runnable { +public abstract class QuickSearch extends KeyAdapter implements Runnable, ConfigurationListener { private static final Logger LOGGER = LoggerFactory.getLogger(QuickSearch.class); /** Quick search string */ @@ -46,8 +52,11 @@ public abstract class QuickSearch extends KeyAdapter implements Runnable { * has a null value when quick search is not active */ private Thread timeoutThread; - /** Quick search timeout in ms */ - private final static int QUICK_SEARCH_TIMEOUT = 2000; + /** Quick search timeout in milliseconds */ + private int quickSearchTimeout; + + /** Whether or not the search is active */ + private boolean active; /** Icon that is used to indicate in the status bar that quick search has failed */ protected final static String QUICK_SEARCH_KO_ICON = "quick_search_ko.png"; @@ -62,6 +71,10 @@ protected QuickSearch(JComponent component) { // Listener to key events to start quick search or update search string when it is active component.addKeyListener(this); + // set the initial timeout according to the configuration + quickSearchTimeout = MuConfigurations.getPreferences().getVariable(MuPreference.QUICK_SEARCH_TIMEOUT, MuPreferences.DEFAULT_QUICK_SEARCH_TIMEOUT) * 1000; + // and update the timeout when the configuration changes + MuConfigurations.addPreferencesListener(this); } /** @@ -73,9 +86,12 @@ protected synchronized void start() { if(!isActive()) { // Reset search string searchString = ""; - // Start the thread that's responsible for canceling the quick search on timeout - timeoutThread = new Thread(this, "QuickSearch timeout thread"); - timeoutThread.start(); + // Start the thread that's responsible for canceling the quick search on timeout, if timeout is set + if (quickSearchTimeout > 0) { + timeoutThread = new Thread(this, "QuickSearch timeout thread"); + timeoutThread.start(); + } + active = true; lastSearchStringChange = System.currentTimeMillis(); searchStarted(); @@ -88,7 +104,7 @@ protected synchronized void start() { public synchronized void stop() { if(isActive()) { timeoutThread = null; - + active = false; searchStopped(); } } @@ -99,7 +115,7 @@ public synchronized void stop() { * @return true if a quick search is being performed */ public synchronized boolean isActive() { - return timeoutThread != null; + return active; } @@ -348,7 +364,7 @@ public void run() { } synchronized(this) { - if(timeoutThread!=null && System.currentTimeMillis()-lastSearchStringChange >= QUICK_SEARCH_TIMEOUT) { + if (timeoutThread!=null && System.currentTimeMillis()-lastSearchStringChange >= quickSearchTimeout) { stop(); } } @@ -371,4 +387,12 @@ public synchronized void keyReleased(KeyEvent e) { stop(); } } + + @Override + public void configurationChanged(ConfigurationEvent event) { + String var = event.getVariable(); + if (var.equals(MuPreferences.QUICK_SEARCH_TIMEOUT)) { + quickSearchTimeout = event.getIntegerValue() * 1000; + } + } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/terminal/TerminalWindow.java b/mucommander-core/src/main/java/com/mucommander/ui/terminal/TerminalWindow.java index d2d1c12d2b..33487ebfac 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/terminal/TerminalWindow.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/terminal/TerminalWindow.java @@ -20,7 +20,6 @@ import java.awt.event.KeyListener; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -110,6 +109,7 @@ public TextStyle getDefaultStyle() { envs = new HashMap<>(System.getenv()); envs.putAll(getDefaultLocaleSetting()); envs.put("TERM", "xterm-256color"); + envs.put("HISTCONTROL", "ignoreboth"); if (OsFamily.MAC_OS.isCurrent()) { envs.put("BASH_SILENCE_DEPRECATION_WARNING", "1"); } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/theme/Theme.java b/mucommander-core/src/main/java/com/mucommander/ui/theme/Theme.java index ca055f7364..db918fd763 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/theme/Theme.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/theme/Theme.java @@ -26,16 +26,14 @@ * @author Nicolas Rinaudo */ public class Theme extends ThemeData { - // - Theme types --------------------------------------------------------------------- - // ----------------------------------------------------------------------------------- - /** Describes the user defined theme. */ - public static final int USER_THEME = 0; - /** Describes predefined muCommander themes. */ - public static final int PREDEFINED_THEME = 1; - /** Describes custom muCommander themes. */ - public static final int CUSTOM_THEME = 2; - - + public enum ThemeType { + /** Describes the user defined theme. */ + USER_THEME, + /** Describes predefined muCommander themes. */ + PREDEFINED_THEME, + /** Describes custom muCommander themes. */ + CUSTOM_THEME; + } // - Theme listeners ----------------------------------------------------------------- // ----------------------------------------------------------------------------------- @@ -46,9 +44,9 @@ public class Theme extends ThemeData { // - Instance variables -------------------------------------------------------------- // ----------------------------------------------------------------------------------- /** Theme name. */ - private String name; + private String name; /** Theme type. */ - private int type; + private ThemeType type; // While this field might look useless, it's actually critical for proper event notification: // ThemeData uses a weak hashmap to store its listeners, meaning that each listener must be 'linked' @@ -66,25 +64,25 @@ public class Theme extends ThemeData { */ Theme(ThemeListener listener) { super(); - init(listener, USER_THEME, null); + init(listener, ThemeType.USER_THEME, null); } - Theme(ThemeListener listener, int type, String name) { + Theme(ThemeListener listener, ThemeType type, String name) { super(); init(listener, type, name); } Theme(ThemeListener listener, ThemeData template) { super(template); - init(listener, USER_THEME, null); + init(listener, ThemeType.USER_THEME, null); } - Theme(ThemeListener listener, ThemeData template, int type, String name) { + Theme(ThemeListener listener, ThemeData template, ThemeType type, String name) { super(template); init(listener, type, name); } - private void init(ThemeListener listener, int type, String name) { + private void init(ThemeListener listener, ThemeType type, String name) { // This might seem like a roundabout way of doing things, but it's actually necessary. // If we didn't explicitly call a defaultValuesListener method, proGuard would 'optimise' // the instance out with catastrophic results (the listener would become a weak reference, @@ -113,13 +111,13 @@ private void init(ThemeListener listener, int type, String name) { *

* @return true if the theme is modifiable, false otherwise. */ - public boolean canModify() {return type == USER_THEME;} + public boolean canModify() {return type == ThemeType.USER_THEME;} /** * Returns the theme's type. * @return the theme's type. */ - public int getType() {return type;} + public ThemeType getType() {return type;} /** * Returns the theme's name. @@ -145,10 +143,10 @@ private void init(ThemeListener listener, int type, String name) { @Override public boolean setFont(int id, Font font) { // Makes sure we're not trying to modify a non-user theme. - if(type != USER_THEME) + if (type != ThemeType.USER_THEME) throw new IllegalStateException("Trying to modify a non user theme."); - if(super.setFont(id, font)) { + if (super.setFont(id, font)) { // We're using getFont here to make sure that no event is propagated with a null value. triggerFontEvent(new FontChangedEvent(this, id, getFont(id))); return true; @@ -170,10 +168,10 @@ public boolean setFont(int id, Font font) { @Override public boolean setColor(int id, Color color) { // Makes sure we're not trying to modify a non-user theme. - if(type != USER_THEME) + if (type != ThemeType.USER_THEME) throw new IllegalStateException("Trying to modify a non user theme."); - if(super.setColor(id, color)) { + if (super.setColor(id, color)) { // We're using getColor here to make sure that no event is propagated with a null value. triggerColorEvent(new ColorChangedEvent(this, id, getColor(id))); return true; @@ -189,11 +187,11 @@ public boolean setColor(int id, Color color) { *

* @param type theme's type. */ - void setType(int type) { + void setType(ThemeType type) { checkType(type); this.type = type; - if(type == USER_THEME) + if (type == ThemeType.USER_THEME) setName(Translator.get("theme.custom_theme")); } @@ -207,8 +205,8 @@ void setType(int type) { // - Misc. --------------------------------------------------------------------------- // ----------------------------------------------------------------------------------- - static void checkType(int type) { - if(type != USER_THEME && type != PREDEFINED_THEME && type != CUSTOM_THEME) + static void checkType(ThemeType type) { + if (type != ThemeType.USER_THEME && type != ThemeType.PREDEFINED_THEME && type != ThemeType.CUSTOM_THEME) throw new IllegalArgumentException("Illegal theme type: " + type); } @@ -219,14 +217,13 @@ static void checkType(int type) { public String toString() {return getName();} private static void addThemeListener(ThemeListener listener) {listeners.put(listener, null);} private static void removeThemeListener(ThemeListener listener) {listeners.remove(listener);} + private static void triggerFontEvent(FontChangedEvent event) { - for(ThemeListener listener : listeners.keySet()) - listener.fontChanged(event); + listeners.keySet().forEach(listener -> listener.fontChanged(event)); } private static void triggerColorEvent(ColorChangedEvent event) { - for(ThemeListener listener : listeners.keySet()) - listener.colorChanged(event); + listeners.keySet().forEach(listener -> listener.colorChanged(event)); } private class DefaultValuesListener implements ThemeListener { @@ -237,12 +234,12 @@ public DefaultValuesListener() {} public void setTheme(Theme theme) {this.theme = theme;} public void colorChanged(ColorChangedEvent event) { - if(!theme.isColorSet(event.getColorId())) + if (!theme.isColorSet(event.getColorId())) Theme.triggerColorEvent(new ColorChangedEvent(theme, event.getColorId(), getColor(event.getColorId()))); } public void fontChanged(FontChangedEvent event) { - if(!theme.isFontSet(event.getFontId())) + if (!theme.isFontSet(event.getFontId())) Theme.triggerFontEvent(new FontChangedEvent(theme, event.getFontId(), getFont(event.getFontId()))); } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeCache.java b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeCache.java index b92f9ea10e..1f0c650de2 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeCache.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeCache.java @@ -48,6 +48,7 @@ public class ThemeCache implements ThemeListener { public static final int SYMLINK = 3; public static final int MARKED = 4; public static final int PLAIN_FILE = 5; + public static final int READ_ONLY = 6; // - Font definitions ------------------------------------------------------------ // ------------------------------------------------------------------------------- @@ -59,7 +60,7 @@ public class ThemeCache implements ThemeListener { // - Initialisation -------------------------------------------------------------- // ------------------------------------------------------------------------------- static { - foregroundColors = new Color[2][2][6]; + foregroundColors = new Color[2][2][7]; backgroundColors = new Color[2][4]; // Active background colors. @@ -76,6 +77,7 @@ public class ThemeCache implements ThemeListener { // Normal foreground foregroundColors. foregroundColors[ACTIVE][NORMAL][HIDDEN_FILE] = ThemeManager.getCurrentColor(Theme.HIDDEN_FILE_FOREGROUND_COLOR); + foregroundColors[ACTIVE][NORMAL][READ_ONLY] = ThemeManager.getCurrentColor(Theme.READ_ONLY_FOREGROUND_COLOR); foregroundColors[ACTIVE][NORMAL][FOLDER] = ThemeManager.getCurrentColor(Theme.FOLDER_FOREGROUND_COLOR); foregroundColors[ACTIVE][NORMAL][ARCHIVE] = ThemeManager.getCurrentColor(Theme.ARCHIVE_FOREGROUND_COLOR); foregroundColors[ACTIVE][NORMAL][SYMLINK] = ThemeManager.getCurrentColor(Theme.SYMLINK_FOREGROUND_COLOR); @@ -84,6 +86,7 @@ public class ThemeCache implements ThemeListener { // Normal unfocused foreground foregroundColors. foregroundColors[INACTIVE][NORMAL][HIDDEN_FILE] = ThemeManager.getCurrentColor(Theme.HIDDEN_FILE_INACTIVE_FOREGROUND_COLOR); + foregroundColors[INACTIVE][NORMAL][READ_ONLY] = ThemeManager.getCurrentColor(Theme.READ_ONLY_INACTIVE_FOREGROUND_COLOR); foregroundColors[INACTIVE][NORMAL][FOLDER] = ThemeManager.getCurrentColor(Theme.FOLDER_INACTIVE_FOREGROUND_COLOR); foregroundColors[INACTIVE][NORMAL][ARCHIVE] = ThemeManager.getCurrentColor(Theme.ARCHIVE_INACTIVE_FOREGROUND_COLOR); foregroundColors[INACTIVE][NORMAL][SYMLINK] = ThemeManager.getCurrentColor(Theme.SYMLINK_INACTIVE_FOREGROUND_COLOR); @@ -92,6 +95,7 @@ public class ThemeCache implements ThemeListener { // Selected foreground foregroundColors. foregroundColors[ACTIVE][SELECTED][HIDDEN_FILE] = ThemeManager.getCurrentColor(Theme.HIDDEN_FILE_SELECTED_FOREGROUND_COLOR); + foregroundColors[ACTIVE][SELECTED][READ_ONLY] = ThemeManager.getCurrentColor(Theme.READ_ONLY_SELECTED_FOREGROUND_COLOR); foregroundColors[ACTIVE][SELECTED][FOLDER] = ThemeManager.getCurrentColor(Theme.FOLDER_SELECTED_FOREGROUND_COLOR); foregroundColors[ACTIVE][SELECTED][ARCHIVE] = ThemeManager.getCurrentColor(Theme.ARCHIVE_SELECTED_FOREGROUND_COLOR); foregroundColors[ACTIVE][SELECTED][SYMLINK] = ThemeManager.getCurrentColor(Theme.SYMLINK_SELECTED_FOREGROUND_COLOR); @@ -100,6 +104,7 @@ public class ThemeCache implements ThemeListener { // Selected unfocused foreground foregroundColors. foregroundColors[INACTIVE][SELECTED][HIDDEN_FILE] = ThemeManager.getCurrentColor(Theme.HIDDEN_FILE_INACTIVE_SELECTED_FOREGROUND_COLOR); + foregroundColors[INACTIVE][SELECTED][READ_ONLY] = ThemeManager.getCurrentColor(Theme.READ_ONLY_INACTIVE_SELECTED_FOREGROUND_COLOR); foregroundColors[INACTIVE][SELECTED][FOLDER] = ThemeManager.getCurrentColor(Theme.FOLDER_INACTIVE_SELECTED_FOREGROUND_COLOR); foregroundColors[INACTIVE][SELECTED][ARCHIVE] = ThemeManager.getCurrentColor(Theme.ARCHIVE_INACTIVE_SELECTED_FOREGROUND_COLOR); foregroundColors[INACTIVE][SELECTED][SYMLINK] = ThemeManager.getCurrentColor(Theme.SYMLINK_INACTIVE_SELECTED_FOREGROUND_COLOR); @@ -198,6 +203,16 @@ public void colorChanged(ColorChangedEvent event) { foregroundColors[ACTIVE][SELECTED][SYMLINK] = event.getColor(); break; + // Read-only + case Theme.READ_ONLY_FOREGROUND_COLOR: + foregroundColors[ACTIVE][NORMAL][READ_ONLY] = event.getColor(); + break; + + // Selected read-only + case Theme.READ_ONLY_SELECTED_FOREGROUND_COLOR: + foregroundColors[ACTIVE][SELECTED][READ_ONLY] = event.getColor(); + break; + // Marked files. case Theme.MARKED_FOREGROUND_COLOR: foregroundColors[ACTIVE][NORMAL][MARKED] = event.getColor(); @@ -258,6 +273,16 @@ public void colorChanged(ColorChangedEvent event) { foregroundColors[INACTIVE][SELECTED][SYMLINK] = event.getColor(); break; + // Read-only + case Theme.READ_ONLY_INACTIVE_FOREGROUND_COLOR: + foregroundColors[INACTIVE][NORMAL][READ_ONLY] = event.getColor(); + break; + + // Selected read-only + case Theme.READ_ONLY_INACTIVE_SELECTED_FOREGROUND_COLOR: + foregroundColors[INACTIVE][SELECTED][READ_ONLY] = event.getColor(); + break; + // Marked files. case Theme.MARKED_INACTIVE_FOREGROUND_COLOR: foregroundColors[INACTIVE][NORMAL][MARKED] = event.getColor(); diff --git a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeData.java b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeData.java index 1ca2c3f043..0b6e85ac41 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeData.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeData.java @@ -17,12 +17,19 @@ package com.mucommander.ui.theme; -import javax.swing.*; -import java.awt.*; +import java.awt.Color; +import java.awt.Font; import java.util.Hashtable; import java.util.Map; import java.util.WeakHashMap; +import javax.swing.JComponent; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.JTextField; + /** * Base class for all things Theme. *

@@ -86,7 +93,7 @@ public class ThemeData { * by an instance of theme data by looping from 0 to this color. *

*/ - public static final int COLOR_COUNT = 68; + public static final int COLOR_COUNT = 72; @@ -676,7 +683,39 @@ public class ThemeData { */ public static final int QUICK_LIST_SELECTED_ITEM_FOREGROUND_COLOR = 67; + /** + * Color used to paint read-only files text in the folder panels. + *

+ * This defaults to the current JTable foreground color. + *

+ */ + public static final int READ_ONLY_FOREGROUND_COLOR = 68; + + /** + * Color used to paint read-only files text in the folder panels when they don't have the focus. + *

+ * This behaves in exactly the same fashion as {@link #READ_ONLY_FOREGROUND_COLOR}, and defaults + * to the same value. + *

+ */ + public static final int READ_ONLY_INACTIVE_FOREGROUND_COLOR = 69; + + /** + * Color used to paint selected read-only files text in the folder panels. + *

+ * This defaults to the current JTable selection foreground color. + *

+ */ + public static final int READ_ONLY_SELECTED_FOREGROUND_COLOR = 70; + /** + * Color used to paint selected read-only files text in the folder panels when they don't have the focus. + *

+ * This behaves in exactly the same fashion as {@link #READ_ONLY_SELECTED_FOREGROUND_COLOR}, and defaults + * to the same value. + *

+ */ + public static final int READ_ONLY_INACTIVE_SELECTED_FOREGROUND_COLOR = 71; // - Default fonts ------------------------------------------------------------------------------------------------- @@ -747,6 +786,8 @@ public class ThemeData { + + public static void registerDefaultColor(String name, DefaultColor color) { DEFAULT_COLORS.put(name, color); } @@ -917,20 +958,24 @@ public Color getColor(ThemeData data) { registerColor(FOLDER_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); registerColor(ARCHIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); registerColor(SYMLINK_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); + registerColor(READ_ONLY_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); registerColor(FILE_INACTIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); registerColor(HIDDEN_FILE_INACTIVE_FOREGROUND_COLOR, Color.GRAY); registerColor(FOLDER_INACTIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); registerColor(ARCHIVE_INACTIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); registerColor(SYMLINK_INACTIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); + registerColor(READ_ONLY_INACTIVE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); registerColor(FILE_FOREGROUND_COLOR, DEFAULT_TABLE_FOREGROUND); registerColor(HIDDEN_FILE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); registerColor(FOLDER_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); registerColor(ARCHIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); registerColor(SYMLINK_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); + registerColor(READ_ONLY_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); registerColor(HIDDEN_FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); registerColor(FOLDER_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); registerColor(ARCHIVE_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); registerColor(SYMLINK_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); + registerColor(READ_ONLY_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); registerColor(FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); registerColor(FILE_SELECTED_FOREGROUND_COLOR, DEFAULT_TABLE_SELECTION_FOREGROUND); @@ -1045,17 +1090,14 @@ public ThemeData() { * @see #cloneData() */ public ThemeData cloneData(boolean freezeDefaults) { - ThemeData data; // New data. - int i; // Used to browse the fonts and colors. - - data = new ThemeData(); + ThemeData data = new ThemeData(); // Clones the theme's colors. - for(i = 0; i < COLOR_COUNT; i++) + for (int i = 0; i < COLOR_COUNT; i++) data.colors[i] = freezeDefaults ? getColor(i) : colors[i]; // Clones the theme's fonts. - for(i = 0; i < FONT_COUNT; i++) + for (int i = 0; i < FONT_COUNT; i++) data.fonts[i] = freezeDefaults ? getFont(i) : fonts[i]; return data; @@ -1088,14 +1130,12 @@ public ThemeData cloneData(boolean freezeDefaults) { * @param data data to import. */ public void importData(ThemeData data) { - int i; - // Imports the theme's colors. - for(i = 0; i < COLOR_COUNT; i++) + for (int i = 0; i < COLOR_COUNT; i++) setColor(i, data.colors[i]); // Imports the theme's fonts. - for(i = 0; i < FONT_COUNT; i++) + for (int i = 0; i < FONT_COUNT; i++) setFont(i, data.fonts[i]); } @@ -1122,9 +1162,7 @@ public void importData(ThemeData data) { * @return true if the call actually changed the data, false otherwise. */ public synchronized boolean setColor(int id, Color color) { - boolean buffer; // Used to store the result of isColorDifferent. - - buffer = isColorDifferent(id, color); + boolean buffer = isColorDifferent(id, color); colors[id] = color; switch(id) { case FILE_TABLE_SELECTED_SECONDARY_BACKGROUND_COLOR: @@ -1156,9 +1194,7 @@ public synchronized boolean setColor(int id, Color color) { * @return true if the call actually changed the data, false otherwise. */ public synchronized boolean setFont(int id, Font font) { - boolean buffer; // Used to store the result of isFontDifferent. - - buffer = isFontDifferent(id, font); + boolean buffer = isFontDifferent(id, font); fonts[id] = font; return buffer; @@ -1269,16 +1305,14 @@ private static Font getDefaultFont(int id, ThemeData data) { * @see #isColorDifferent(int,Color,boolean) */ public boolean isIdentical(ThemeData data, boolean ignoreDefaults) { - int i; - // Compares the colors. - for(i = 0; i < COLOR_COUNT; i++) - if(isColorDifferent(i, data.colors[i] , ignoreDefaults)) + for (int i = 0; i < COLOR_COUNT; i++) + if (isColorDifferent(i, data.colors[i] , ignoreDefaults)) return false; // Compares the fonts. - for(i = 0; i < FONT_COUNT; i++) - if(isFontDifferent(i, data.fonts[i], ignoreDefaults)) + for (int i = 0; i < FONT_COUNT; i++) + if (isFontDifferent(i, data.fonts[i], ignoreDefaults)) return false; return true; @@ -1327,12 +1361,12 @@ public synchronized boolean isFontDifferent(int id, Font font, boolean ignoreDef // If the specified font is null, the only way for both fonts to be equal is for fonts[id] // to be null as well. - if(font == null) + if (font == null) return fonts[id] != null; // If fonts[id] is null and we're set to ignore defaults, both fonts are different. // If we're set to use defaults, we must compare font and the default value for id. - if(fonts[id] == null) + if (fonts[id] == null) return ignoreDefaults || !getDefaultFont(id, this).equals(font); // 'Standard' case: both fonts are set, compare them normally. @@ -1372,12 +1406,12 @@ public synchronized boolean isColorDifferent(int id, Color color, boolean ignore // If the specified color is null, the only way for both colors to be equal is for colors[id] // to be null as well. - if(color == null) + if (color == null) return colors[id] != null; // If colors[id] is null and we're set to ignore defaults, both colors are different. // If we're set to use defaults, we must compare color and the default value for id. - if(colors[id] == null) + if (colors[id] == null) return ignoreDefaults || !getDefaultColor(id, this).equals(color); // 'Standard' case: both colors are set, compare them normally. @@ -1426,14 +1460,11 @@ public synchronized boolean isColorDifferent(int id, Color color, boolean ignore * @param font new value for the font that changed. */ static void triggerFontEvent(int id, Font font) { - FontChangedEvent event; // Event that will be dispatched. - // Creates the event. - event = new FontChangedEvent(null, id, font); + FontChangedEvent event = new FontChangedEvent(null, id, font); // Dispatches it. - for(ThemeListener listener : listeners.keySet()) - listener.fontChanged(event); + listeners.keySet().forEach(listener -> listener.fontChanged(event)); } /** @@ -1442,14 +1473,11 @@ static void triggerFontEvent(int id, Font font) { * @param color new value for the color that changed. */ static void triggerColorEvent(int id, Color color) { - ColorChangedEvent event; // Event that will be dispatched. - // Creates the event. - event = new ColorChangedEvent(null, id, color); + ColorChangedEvent event = new ColorChangedEvent(null, id, color); // Dispatches it. - for(ThemeListener listener : listeners.keySet()) - listener.colorChanged(event); + listeners.keySet().forEach(listener -> listener.colorChanged(event)); } @@ -1462,7 +1490,7 @@ static void triggerColorEvent(int id, Color color) { * @throws IllegalArgumentException if id is not a legal color identifier. */ private static void checkColorIdentifier(int id) { - if(id < 0 || id >= COLOR_COUNT) + if (id < 0 || id >= COLOR_COUNT) throw new IllegalArgumentException("Illegal color identifier: " + id); } @@ -1472,7 +1500,7 @@ private static void checkColorIdentifier(int id) { * @throws IllegalArgumentException if id is not a legal font identifier. */ private static void checkFontIdentifier(int id) { - if(id < 0 || id >= FONT_COUNT) + if (id < 0 || id >= FONT_COUNT) throw new IllegalArgumentException("Illegal font identifier: " + id); } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeManager.java b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeManager.java index 07f0ae999f..a2665cc007 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeManager.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeManager.java @@ -50,6 +50,7 @@ import com.mucommander.io.backup.BackupInputStream; import com.mucommander.io.backup.BackupOutputStream; import com.mucommander.text.Translator; +import com.mucommander.ui.theme.Theme.ThemeType; /** * Offers methods for accessing and modifying themes. @@ -111,7 +112,7 @@ private ThemeManager() {} *

*/ public static void loadCurrentTheme() { - int type; // Current theme's type. + ThemeType type; // Current theme's type. String name; // Current theme's name. boolean wasUserThemeLoaded; // Whether we have tried loading the user theme or not. @@ -120,7 +121,7 @@ public static void loadCurrentTheme() { catch(Exception e) {type = getThemeTypeFromLabel(MuPreferences.DEFAULT_THEME_TYPE);} // Loads the current theme name as defined in configuration. - if(type != Theme.USER_THEME) { + if(type != ThemeType.USER_THEME) { wasUserThemeLoaded = false; name = MuConfigurations.getPreferences().getVariable(MuPreference.THEME_NAME, MuPreferences.DEFAULT_THEME_NAME); } @@ -136,7 +137,7 @@ public static void loadCurrentTheme() { type = getThemeTypeFromLabel(MuPreferences.DEFAULT_THEME_TYPE); name = MuPreferences.DEFAULT_THEME_NAME; - if(type == Theme.USER_THEME) + if(type == ThemeType.USER_THEME) wasUserThemeLoaded = true; // If the default theme can be loaded, tries to load the user theme if we haven't done so yet. @@ -144,7 +145,7 @@ public static void loadCurrentTheme() { try {currentTheme = readTheme(type, name);} catch(Exception e2) { if(!wasUserThemeLoaded) { - try {currentTheme = readTheme(Theme.USER_THEME, null);} + try {currentTheme = readTheme(ThemeType.USER_THEME, null);} catch(Exception e3) {} } if(currentTheme == null) { @@ -199,14 +200,14 @@ public static Vector getAvailableThemes() { themes = new Vector(); // Tries to load the user theme. If it's corrupt, uses an empty user theme. - try {themes.add(readTheme(Theme.USER_THEME, null));} + try {themes.add(readTheme(ThemeType.USER_THEME, null));} catch(Exception e) {themes.add(new Theme(listener));} // Loads predefined themes. iterator = predefinedThemeNames(); while(iterator.hasNext()) { name = iterator.next(); - try {themes.add(readTheme(Theme.PREDEFINED_THEME, name));} + try {themes.add(readTheme(ThemeType.PREDEFINED_THEME, name));} catch(Exception e) { LOGGER.warn("Failed to load predefined theme " + name, e); } @@ -217,7 +218,7 @@ public static Vector getAvailableThemes() { iterator = customThemeNames(); while(iterator.hasNext()) { name = iterator.next(); - try {themes.add(readTheme(Theme.CUSTOM_THEME, name));} + try {themes.add(readTheme(ThemeType.CUSTOM_THEME, name));} catch(Exception e) { LOGGER.warn("Failed to load custom theme " + name, e); } @@ -362,7 +363,7 @@ public static void deleteCustomTheme(String name) throws IOException { AbstractFile file; // Makes sure the specified theme is not the current one. - if(isCurrentTheme(Theme.CUSTOM_THEME, name)) + if(isCurrentTheme(ThemeType.CUSTOM_THEME, name)) throw new IllegalArgumentException("Cannot delete current theme."); // Deletes the theme. @@ -372,7 +373,7 @@ public static void deleteCustomTheme(String name) throws IOException { } public static void renameCustomTheme(Theme theme, String name) throws IOException { - if(theme.getType() != Theme.CUSTOM_THEME) + if(theme.getType() != ThemeType.CUSTOM_THEME) throw new IllegalArgumentException("Cannot rename non-custom themes."); // Makes sure the operation is necessary. @@ -429,18 +430,18 @@ private static BackupOutputStream getUserThemeOutputStream() throws IOException * @return an output stream on the requested theme. * @throws IOException if an I/O related error occurs. */ - private static BackupOutputStream getOutputStream(int type, String name) throws IOException { + private static BackupOutputStream getOutputStream(ThemeType type, String name) throws IOException { switch(type) { // Predefined themes. - case Theme.PREDEFINED_THEME: + case PREDEFINED_THEME: throw new IllegalArgumentException("Can not open output streams on predefined themes."); // Custom themes. - case Theme.CUSTOM_THEME: + case CUSTOM_THEME: return getCustomThemeOutputStream(name); // User theme. - case Theme.USER_THEME: + case USER_THEME: return getUserThemeOutputStream(); } @@ -517,7 +518,7 @@ public static void writeThemeData(ThemeData data, File file) throws IOException * @throws IllegalArgumentException if theme is a predefined theme. * @see #writeTheme(Theme) */ - public static void writeTheme(ThemeData data, int type, String name) throws IOException { + public static void writeTheme(ThemeData data, ThemeType type, String name) throws IOException { OutputStream out; out = null; @@ -545,10 +546,10 @@ public static void writeTheme(ThemeData data, int type, String name) throws IOEx * @param name name of the theme to export. * @param out where to write the theme. * @throws IOException if any I/O related error occurs. - * @see #exportTheme(int,String,File) + * @see #exportTheme(ThemeType,String,File) * @see #writeThemeData(ThemeData,OutputStream) */ - public static void exportTheme(int type, String name, OutputStream out) throws IOException { + public static void exportTheme(ThemeType type, String name, OutputStream out) throws IOException { InputStream in; // Where to read the theme from. in = null; @@ -575,10 +576,10 @@ public static void exportTheme(int type, String name, OutputStream out) throws I * @param name name of the theme to export. * @param file where to write the theme. * @throws IOException if any I/O related error occurs - * @see #exportTheme(int,String,OutputStream) + * @see #exportTheme(ThemeType,String,OutputStream) * @see #writeThemeData(ThemeData,File). */ - public static void exportTheme(int type, String name, File file) throws IOException { + public static void exportTheme(ThemeType type, String name, File file) throws IOException { OutputStream out; // Where to write the data to. out = null; @@ -595,7 +596,7 @@ public static void exportTheme(int type, String name, File file) throws IOExcept * Exports the specified theme to the specified output stream. *

* This is a convenience method only and is strictly equivalent to calling - * {@link #exportTheme(int,String,OutputStream) exportTheme(}theme.getType(), theme.getName(), out); + * {@link #exportTheme(ThemeType,String,OutputStream) exportTheme(}theme.getType(), theme.getName(), out); *

* @param theme theme to export. * @param out where to write the theme. @@ -659,8 +660,8 @@ private static String getAvailableCustomThemeName(String name) { public static Theme duplicateTheme(Theme theme) throws IOException, Exception {return importTheme(theme.cloneData(), theme.getName());} public static Theme importTheme(ThemeData data, String name) throws IOException, Exception { - writeTheme(data, Theme.CUSTOM_THEME, name = getAvailableCustomThemeName(name)); - return new Theme(listener, data, Theme.CUSTOM_THEME, name); + writeTheme(data, ThemeType.CUSTOM_THEME, name = getAvailableCustomThemeName(name)); + return new Theme(listener, data, ThemeType.CUSTOM_THEME, name); } public static Theme importTheme(File file) throws IOException, Exception { @@ -692,7 +693,7 @@ public static Theme importTheme(File file) throws IOException, Exception { } } - return new Theme(listener, data, Theme.CUSTOM_THEME, name); + return new Theme(listener, data, ThemeType.CUSTOM_THEME, name); } @@ -740,18 +741,18 @@ private static InputStream getCustomThemeInputStream(String name) throws IOExcep * @throws IOException thrown if an IO related error occurs. * @throws IllegalArgumentException thrown if type is not a legal theme type. */ - private static InputStream getInputStream(int type, String name) throws IOException { + private static InputStream getInputStream(ThemeType type, String name) throws IOException { switch(type) { // User theme. - case Theme.USER_THEME: + case USER_THEME: return getUserThemeInputStream(); // Predefined theme. - case Theme.PREDEFINED_THEME: + case PREDEFINED_THEME: return getPredefinedThemeInputStream(name); // Custom theme. - case Theme.CUSTOM_THEME: + case CUSTOM_THEME: return getCustomThemeInputStream(name); } @@ -765,7 +766,7 @@ private static InputStream getInputStream(int type, String name) throws IOExcept * @param name name of the theme to retrieve. * @return the requested theme. */ - public static Theme readTheme(int type, String name) throws Exception { + public static Theme readTheme(ThemeType type, String name) throws Exception { ThemeData data; // Buffer for the theme data. InputStream in; // Where to read the theme from. @@ -830,23 +831,23 @@ public static ThemeData readThemeData(File file) throws Exception { // - Current theme access ------------------------------------------------------------ // ----------------------------------------------------------------------------------- - private static void setConfigurationTheme(int type, String name) { + private static void setConfigurationTheme(ThemeType type, String name) { // Sets configuration depending on the new theme's type. switch(type) { // User defined theme. - case Theme.USER_THEME: + case USER_THEME: MuConfigurations.getPreferences().setVariable(MuPreference.THEME_TYPE, MuPreferences.THEME_USER); MuConfigurations.getPreferences().setVariable(MuPreference.THEME_NAME, null); break; // Predefined themes. - case Theme.PREDEFINED_THEME: + case PREDEFINED_THEME: MuConfigurations.getPreferences().setVariable(MuPreference.THEME_TYPE, MuPreferences.THEME_PREDEFINED); MuConfigurations.getPreferences().setVariable(MuPreference.THEME_NAME, name); break; // Custom themes. - case Theme.CUSTOM_THEME: + case CUSTOM_THEME: MuConfigurations.getPreferences().setVariable(MuPreference.THEME_TYPE, MuPreferences.THEME_CUSTOM); MuConfigurations.getPreferences().setVariable(MuPreference.THEME_NAME, name); break; @@ -874,7 +875,7 @@ public static void saveCurrentTheme() throws IOException { return; // Saves the user theme if it's the current one. - if(currentTheme.getType() == Theme.USER_THEME && wasUserThemeModified) { + if(currentTheme.getType() == ThemeType.USER_THEME && wasUserThemeModified) { writeTheme(currentTheme); wasUserThemeModified = false; } @@ -917,14 +918,14 @@ public synchronized static void setCurrentTheme(Theme theme) { public synchronized static Theme overwriteUserTheme(ThemeData themeData) throws IOException { // If the current theme is the user one, we just need to import the new data. - if(currentTheme.getType() == Theme.USER_THEME) { + if(currentTheme.getType() == ThemeType.USER_THEME) { currentTheme.importData(themeData); writeTheme(currentTheme); return currentTheme; } else { - writeTheme(themeData, Theme.USER_THEME, null); + writeTheme(themeData, ThemeType.USER_THEME, null); return new Theme(listener, themeData); } } @@ -938,7 +939,7 @@ public synchronized static Theme overwriteUserTheme(ThemeData themeData) throws */ public synchronized static boolean willOverwriteUserTheme(int fontId, Font font) { if(currentTheme.isFontDifferent(fontId, font)) - return currentTheme.getType() != Theme.USER_THEME; + return currentTheme.getType() != ThemeType.USER_THEME; return false; } @@ -951,7 +952,7 @@ public synchronized static boolean willOverwriteUserTheme(int fontId, Font font) */ public synchronized static boolean willOverwriteUserTheme(int colorId, Color color) { if(currentTheme.isColorDifferent(colorId, color)) - return currentTheme.getType() != Theme.USER_THEME; + return currentTheme.getType() != ThemeType.USER_THEME; return false; } @@ -970,8 +971,8 @@ public synchronized static boolean setCurrentFont(int id, Font font) { // Only updates if necessary. if(currentTheme.isFontDifferent(id, font)) { // Checks whether we need to overwrite the user theme to perform this action. - if(currentTheme.getType() != Theme.USER_THEME) { - currentTheme.setType(Theme.USER_THEME); + if(currentTheme.getType() != ThemeType.USER_THEME) { + currentTheme.setType(ThemeType.USER_THEME); setConfigurationTheme(currentTheme); } @@ -996,8 +997,8 @@ public synchronized static boolean setCurrentColor(int id, Color color) { // Only updates if necessary. if(currentTheme.isColorDifferent(id, color)) { // Checks whether we need to overwrite the user theme to perform this action. - if(currentTheme.getType() != Theme.USER_THEME) { - currentTheme.setType(Theme.USER_THEME); + if(currentTheme.getType() != ThemeType.USER_THEME) { + currentTheme.setType(ThemeType.USER_THEME); setConfigurationTheme(currentTheme); } @@ -1015,10 +1016,10 @@ public synchronized static boolean setCurrentColor(int id, Color color) { */ public static boolean isCurrentTheme(Theme theme) {return theme == currentTheme;} - private static boolean isCurrentTheme(int type, String name) { + private static boolean isCurrentTheme(ThemeType type, String name) { if(type != currentTheme.getType()) return false; - if(type == Theme.USER_THEME) + if(type == ThemeType.USER_THEME) return true; return name.equals(currentTheme.getName()); } @@ -1118,15 +1119,15 @@ private static void triggerColorEvent(ColorChangedEvent event) { /** * Returns a valid type identifier from the specified configuration type definition. * @param label label of the theme type as defined in {@link MuPreferences}. - * @return a valid theme type identifier. + * @return a valid theme type identifier. */ - private static int getThemeTypeFromLabel(String label) { + private static ThemeType getThemeTypeFromLabel(String label) { if(label.equals(MuPreferences.THEME_USER)) - return Theme.USER_THEME; + return ThemeType.USER_THEME; else if(label.equals(MuPreferences.THEME_PREDEFINED)) - return Theme.PREDEFINED_THEME; + return ThemeType.PREDEFINED_THEME; else if(label.equals(MuPreferences.THEME_CUSTOM)) - return Theme.CUSTOM_THEME; + return ThemeType.CUSTOM_THEME; throw new IllegalStateException("Unknown theme type: " + label); } @@ -1143,7 +1144,7 @@ private static String getThemeName(AbstractFile themeFile) { */ private static class CurrentThemeListener implements ThemeListener { public void fontChanged(FontChangedEvent event) { - if(event.getSource().getType() == Theme.USER_THEME) + if(event.getSource().getType() == ThemeType.USER_THEME) wasUserThemeModified = true; if(event.getSource() == currentTheme) @@ -1151,7 +1152,7 @@ public void fontChanged(FontChangedEvent event) { } public void colorChanged(ColorChangedEvent event) { - if(event.getSource().getType() == Theme.USER_THEME) + if(event.getSource().getType() == ThemeType.USER_THEME) wasUserThemeModified = true; if(event.getSource() == currentTheme) diff --git a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeReader.java b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeReader.java index 4336f63ba7..5a69739028 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeReader.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeReader.java @@ -102,6 +102,9 @@ class ThemeReader extends DefaultHandler implements ThemeXmlConstants { private static final int STATE_QUICK_LIST_ITEM = 40; private static final int STATE_QUICK_LIST_ITEM_NORMAL = 41; private static final int STATE_QUICK_LIST_ITEM_SELECTED = 42; + private static final int STATE_READ_ONLY = 43; + private static final int STATE_READ_ONLY_NORMAL = 44; + private static final int STATE_READ_ONLY_SELECTED = 45; // - Instance variables -------------------------------------------------------------- @@ -227,6 +230,12 @@ else if(qName.equals(ELEMENT_SYMLINK)) { state = STATE_SYMLINK; } + else if(qName.equals(ELEMENT_READ_ONLY)) { + if(state != STATE_TABLE) + traceIllegalDeclaration(qName); + state = STATE_READ_ONLY; + } + else if(qName.equals(ELEMENT_MARKED)) { if(state != STATE_TABLE) traceIllegalDeclaration(qName); @@ -279,6 +288,8 @@ else if(state == STATE_ARCHIVE) state = STATE_ARCHIVE_NORMAL; else if(state == STATE_SYMLINK) state = STATE_SYMLINK_NORMAL; + else if(state == STATE_READ_ONLY) + state = STATE_READ_ONLY_NORMAL; else if(state == STATE_MARKED) state = STATE_MARKED_NORMAL; else if(state == STATE_FILE) @@ -309,6 +320,8 @@ else if(state == STATE_ARCHIVE) state = STATE_ARCHIVE_SELECTED; else if(state == STATE_SYMLINK) state = STATE_SYMLINK_SELECTED; + else if(state == STATE_READ_ONLY) + state = STATE_READ_ONLY_SELECTED; else if(state == STATE_MARKED) state = STATE_MARKED_SELECTED; else if(state == STATE_FILE) @@ -383,6 +396,8 @@ else if(state == STATE_ARCHIVE_NORMAL) template.setColor(ThemeData.ARCHIVE_INACTIVE_FOREGROUND_COLOR, createColor(attributes)); else if(state == STATE_SYMLINK_NORMAL) template.setColor(ThemeData.SYMLINK_INACTIVE_FOREGROUND_COLOR, createColor(attributes)); + else if(state == STATE_READ_ONLY_NORMAL) + template.setColor(ThemeData.READ_ONLY_INACTIVE_FOREGROUND_COLOR, createColor(attributes)); else if(state == STATE_HIDDEN_NORMAL) template.setColor(ThemeData.HIDDEN_FILE_INACTIVE_FOREGROUND_COLOR, createColor(attributes)); else if(state == STATE_MARKED_NORMAL) @@ -395,6 +410,8 @@ else if(state == STATE_ARCHIVE_SELECTED) template.setColor(ThemeData.ARCHIVE_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes)); else if(state == STATE_SYMLINK_SELECTED) template.setColor(ThemeData.SYMLINK_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes)); + else if(state == STATE_READ_ONLY_SELECTED) + template.setColor(ThemeData.READ_ONLY_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes)); else if(state == STATE_HIDDEN_SELECTED) template.setColor(ThemeData.HIDDEN_FILE_INACTIVE_SELECTED_FOREGROUND_COLOR, createColor(attributes)); else if(state == STATE_MARKED_SELECTED) @@ -549,6 +566,11 @@ else if(state == STATE_SYMLINK_NORMAL) else if(state == STATE_SYMLINK_SELECTED) template.setColor(ThemeData.SYMLINK_SELECTED_FOREGROUND_COLOR, createColor(attributes)); + else if(state == STATE_READ_ONLY_NORMAL) + template.setColor(ThemeData.READ_ONLY_FOREGROUND_COLOR, createColor(attributes)); + else if(state == STATE_READ_ONLY_SELECTED) + template.setColor(ThemeData.READ_ONLY_SELECTED_FOREGROUND_COLOR, createColor(attributes)); + else if(state == STATE_MARKED_NORMAL) template.setColor(ThemeData.MARKED_FOREGROUND_COLOR, createColor(attributes)); else if(state == STATE_MARKED_SELECTED) @@ -638,6 +660,9 @@ else if(qName.equals(ELEMENT_ARCHIVE)) else if(qName.equals(ELEMENT_SYMLINK)) state = STATE_TABLE; + else if(qName.equals(ELEMENT_READ_ONLY)) + state = STATE_TABLE; + else if(qName.equals(ELEMENT_MARKED)) state = STATE_TABLE; @@ -694,6 +719,8 @@ else if(state == STATE_ARCHIVE_NORMAL) state = STATE_ARCHIVE; else if(state == STATE_SYMLINK_NORMAL) state = STATE_SYMLINK; + else if(state == STATE_READ_ONLY_NORMAL) + state = STATE_READ_ONLY; else if(state == STATE_MARKED_NORMAL) state = STATE_MARKED; else if(state == STATE_FILE_NORMAL) @@ -722,6 +749,8 @@ else if(state == STATE_ARCHIVE_SELECTED) state = STATE_ARCHIVE; else if(state == STATE_SYMLINK_SELECTED) state = STATE_SYMLINK; + else if(state == STATE_READ_ONLY_SELECTED) + state = STATE_READ_ONLY; else if(state == STATE_MARKED_SELECTED) state = STATE_MARKED; else if(state == STATE_FILE_SELECTED) diff --git a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeWriter.java b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeWriter.java index 07b5ff6774..1ddcbd38aa 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeWriter.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeWriter.java @@ -188,6 +188,25 @@ public static void write(ThemeData theme, OutputStream stream) throws IOExceptio out.endElement(ELEMENT_SELECTED); out.endElement(ELEMENT_SYMLINK); + // Read-only files + out.startElement(ELEMENT_READ_ONLY); + out.println(); + out.startElement(ELEMENT_NORMAL); + out.println(); + if(theme.isColorSet(Theme.READ_ONLY_INACTIVE_FOREGROUND_COLOR)) + out.writeStandAloneElement(ELEMENT_INACTIVE_FOREGROUND, getColorAttributes(theme.getColor(Theme.READ_ONLY_INACTIVE_FOREGROUND_COLOR))); + if(theme.isColorSet(Theme.READ_ONLY_FOREGROUND_COLOR)) + out.writeStandAloneElement(ELEMENT_FOREGROUND, getColorAttributes(theme.getColor(Theme.READ_ONLY_FOREGROUND_COLOR))); + out.endElement(ELEMENT_NORMAL); + out.startElement(ELEMENT_SELECTED); + out.println(); + if(theme.isColorSet(Theme.READ_ONLY_INACTIVE_SELECTED_FOREGROUND_COLOR)) + out.writeStandAloneElement(ELEMENT_INACTIVE_FOREGROUND, getColorAttributes(theme.getColor(Theme.READ_ONLY_INACTIVE_SELECTED_FOREGROUND_COLOR))); + if(theme.isColorSet(Theme.READ_ONLY_SELECTED_FOREGROUND_COLOR)) + out.writeStandAloneElement(ELEMENT_FOREGROUND, getColorAttributes(theme.getColor(Theme.READ_ONLY_SELECTED_FOREGROUND_COLOR))); + out.endElement(ELEMENT_SELECTED); + out.endElement(ELEMENT_READ_ONLY); + // Marked files. out.startElement(ELEMENT_MARKED); out.println(); diff --git a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeXmlConstants.java b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeXmlConstants.java index ccb60ac3ef..4317c87651 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeXmlConstants.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/theme/ThemeXmlConstants.java @@ -42,6 +42,8 @@ interface ThemeXmlConstants { public static final String ELEMENT_QUICK_LIST = "quick_list"; + // File table element + public static final String ELEMENT_READ_ONLY = "read_only"; // - Status element ------------------------------------------------------------------ // ----------------------------------------------------------------------------------- diff --git a/mucommander-core/src/main/java/com/mucommander/ui/viewer/EditorPreferences.java b/mucommander-core/src/main/java/com/mucommander/ui/viewer/EditorPreferences.java new file mode 100644 index 0000000000..5e24baeafb --- /dev/null +++ b/mucommander-core/src/main/java/com/mucommander/ui/viewer/EditorPreferences.java @@ -0,0 +1,50 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.ui.viewer; + +/** + * Editor preferences. + */ +public enum EditorPreferences { + + SHOW_FULLSCREEN("show_fullscreen", "false"), + WINDOW_POSITION_X("window_position_x", ""), + WINDOW_POSITION_Y("window_position_y", ""), + WINDOW_WIDTH("window_width", ""), + WINDOW_HEIGHT("window_height", "") + ; + + private String prefKey; + private String value; + + EditorPreferences(String prefKey, String defaultValue) { + this.prefKey = prefKey; + this.value = defaultValue; + } + + public String getPrefKey() { + return prefKey; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/mucommander-core/src/main/java/com/mucommander/ui/viewer/EditorSnapshot.java b/mucommander-core/src/main/java/com/mucommander/ui/viewer/EditorSnapshot.java new file mode 100644 index 0000000000..cfdc8fc37b --- /dev/null +++ b/mucommander-core/src/main/java/com/mucommander/ui/viewer/EditorSnapshot.java @@ -0,0 +1,33 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.ui.viewer; + +import static com.mucommander.snapshot.MuSnapshot.FILE_PRESENTER_SECTION; + +import com.mucommander.snapshot.MuSnapshotable; + +/** + * Snapshot preferences for editor. + */ +public final class EditorSnapshot extends MuSnapshotable { + public EditorSnapshot() { + super(EditorPreferences::values, + EditorPreferences::getValue, + EditorPreferences::setValue, + pref -> pref.getPrefKey() != null ? FILE_PRESENTER_SECTION + "." + pref.getPrefKey() : null); + } +} diff --git a/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileEditorPresenter.java b/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileEditorPresenter.java index 238dfa108e..5e265d4af5 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileEditorPresenter.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileEditorPresenter.java @@ -17,6 +17,8 @@ package com.mucommander.ui.viewer; import java.awt.Cursor; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; @@ -38,30 +40,28 @@ import com.mucommander.commons.file.AbstractFile; import com.mucommander.commons.util.ui.helper.MenuToolkit; import com.mucommander.commons.util.ui.helper.MnemonicHelper; +import com.mucommander.text.Translator; import com.mucommander.viewer.CloseCancelledException; import com.mucommander.viewer.EditorPresenter; import com.mucommander.viewer.FileEditor; import com.mucommander.viewer.FileEditorService; -import com.mucommander.text.Translator; /** * File editor presenter to handle multiple file editors. * - *

- * Warning: the file viewer/editor API may soon receive a major overhaul. - *

- * * @author Maxence Bernard, Arik Hadas */ public class FileEditorPresenter extends FilePresenter implements EditorPresenter { - private FileEditor fileEditor = null; private final JMenuBar menuBar; private final JMenu editorMenu; private final ButtonGroup editorsButtonGroup; private final List services = new ArrayList<>(); + private FileEditor fileEditor; private int editorsCount = 0; private int activeEditor = 0; + + private JMenuItem fullScreenMenuItem; private JMenuItem closeMenuItem; public FileEditorPresenter() { @@ -96,16 +96,6 @@ public JFrame getWindowFrame() { return getFrame(); } - @Override - public boolean isFullScreen() { - return getFrame().isFullScreen(); - } - - @Override - public void setFullScreen(boolean fullScreen) { - getFrame().setFullScreen(fullScreen); - } - @Override public void longOperation(Runnable operation) { getFrame().setCursor(new Cursor(Cursor.WAIT_CURSOR)); @@ -121,7 +111,7 @@ public void addEditorService(FileEditorService service) throws UserCancelledExce try { switchFileEditor(serviceIndex); } catch (IOException ex) { - Logger.getLogger(FileViewerPresenter.class.getName()).log(Level.SEVERE, null, ex); + Logger.getLogger(FileEditorPresenter.class.getName()).log(Level.SEVERE, null, ex); } catch (CloseCancelledException ex) { editorMenu.getItem(activeEditor).setSelected(true); } @@ -146,38 +136,71 @@ public void windowClosing(WindowEvent e) { try { fileEditor.close(); } catch (CloseCancelledException ex) { + // cancelled return; } - } - getFrame().dispose(); + close(); + } } }); MnemonicHelper menuItemMnemonicHelper = new MnemonicHelper(); editorMenu.addSeparator(); + + fullScreenMenuItem = MenuToolkit.addCheckBoxMenuItem(editorMenu, + Translator.get("file_editor.fullscreen"), + menuItemMnemonicHelper, + KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.CTRL_MASK), + (e) -> { + boolean fullScreen = getFrame().isFullScreen(); + switchFullScreenMode(!fullScreen); + }); + + String windowWidthValue = EditorPreferences.WINDOW_WIDTH.getValue(); + if (!windowWidthValue.isEmpty()) { + int windowX = Integer.parseInt(EditorPreferences.WINDOW_POSITION_X.getValue()); + int windowY = Integer.parseInt(EditorPreferences.WINDOW_POSITION_Y.getValue()); + int windowWidth = Integer.parseInt(windowWidthValue); + int windowHeight = Integer.parseInt(EditorPreferences.WINDOW_HEIGHT.getValue()); + getFrame().setBounds(windowX, windowY, windowWidth, windowHeight); + } else { + getFrame().setDefaultBounds(); + } + + String showFullscreenValue = EditorPreferences.SHOW_FULLSCREEN.getValue(); + if (Boolean.TRUE.toString().equals(showFullscreenValue)) { + switchFullScreenMode(true); + } + editorMenu.add(fullScreenMenuItem); + closeMenuItem = MenuToolkit.addMenuItem(editorMenu, Translator.get("file_editor.close"), menuItemMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), - (e) -> { - try { - fileEditor.close(); - getFrame().dispose(); - } catch (CloseCancelledException ex) { - // cancelled - } - }); + e -> getFrame().dispatchEvent(new WindowEvent(getFrame(), WindowEvent.WINDOW_CLOSING))); editorMenu.add(closeMenuItem); try { switchFileEditor(0); } catch (CloseCancelledException ex) { - Logger.getLogger(FileViewerPresenter.class.getName()).log(Level.SEVERE, "Unexpected cancellation", ex); + Logger.getLogger(FileEditorPresenter.class.getName()).log(Level.SEVERE, "Unexpected cancellation", ex); } } } + private void close() { + FileFrame frame = getFrame(); + frame.revalidate(); + Rectangle bounds = frame.getBounds(); + EditorPreferences.WINDOW_POSITION_X.setValue(Integer.toString(bounds.x)); + EditorPreferences.WINDOW_POSITION_Y.setValue(Integer.toString(bounds.y)); + EditorPreferences.WINDOW_WIDTH.setValue(Integer.toString(bounds.width)); + EditorPreferences.WINDOW_HEIGHT.setValue(Integer.toString(bounds.height)); + + frame.dispose(); + } + private void switchFileEditor(int index) throws IOException, CloseCancelledException { if (fileEditor != null) { fileEditor.close(); @@ -196,7 +219,21 @@ private void switchFileEditor(int index) throws IOException, CloseCancelledExcep fileEditor.open(getCurrentFile()); fileEditor.extendMenu(menuBar); menuBar.revalidate(); + menuBar.repaint(); setComponentToPresent(editorComponent); activeEditor = index; } + + private void switchFullScreenMode(boolean showFullScreen) { + getFrame().setFullScreen(showFullScreen); + fullScreenMenuItem.setSelected(showFullScreen); + EditorPreferences.SHOW_FULLSCREEN.setValue(Boolean.toString(showFullScreen)); + } + + @Override + public void requestFocus() { + if (fileEditor != null) { + fileEditor.requestFocus(); + } + } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileFrame.java b/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileFrame.java index ab43fa47dc..590a34da0f 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileFrame.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileFrame.java @@ -1,161 +1,146 @@ -package com.mucommander.ui.viewer; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Frame; -import java.awt.Image; - -import javax.swing.JComponent; -import javax.swing.JFrame; -import javax.swing.JPanel; -import javax.swing.WindowConstants; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.mucommander.commons.file.AbstractFile; -import com.mucommander.commons.util.ui.dialog.DialogToolkit; -import com.mucommander.commons.util.ui.helper.FocusRequester; -import com.mucommander.ui.dialog.InformationDialog; -import com.mucommander.ui.layout.AsyncPanel; -import com.mucommander.ui.main.MainFrame; - -/** - * This class is used as an abstraction for the {@link EditorFrame} and {@link ViewerFrame}. - * - * @author Arik Hadas - */ -public abstract class FileFrame extends JFrame { - private static final Logger LOGGER = LoggerFactory.getLogger(FileFrame.class); - - private final static Dimension WAIT_DIALOG_SIZE = new Dimension(400, 350); - - // The file presenter within this frame - private FilePresenter filePresenter; - - // The main frame from which this frame was initiated - private MainFrame mainFrame; - - FileFrame(MainFrame mainFrame, AbstractFile file, Image icon) { - this.mainFrame = mainFrame; - - setIconImage(icon); - - // Call #dispose() on close (default is hide) - setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - - setResizable(true); - - initContentPane(file); - } - - public MainFrame getMainFrame() { - return mainFrame; - } - - protected void initContentPane(final AbstractFile file) { - try { - filePresenter = createFilePresenter(file); - } catch (UserCancelledException e) { - // May get a UserCancelledException if the user canceled (refused to confirm the operation after a warning) - return; - } - - // If not suitable presenter was found for the given file - if (filePresenter == null) { - showGenericErrorDialog(); - return; - } - - AsyncPanel asyncPanel = new AsyncPanel() { - - @Override - public JComponent getTargetComponent() { - try { - // Ask the presenter to present the file - filePresenter.open(file); - } - catch(Exception e) { - LOGGER.debug("Exception caught", e); - - showGenericErrorDialog(); - - dispose(); - return filePresenter==null?new JPanel():filePresenter; - } - - setJMenuBar(filePresenter.getMenuBar()); - - return filePresenter; - } - - @Override - protected void updateLayout() { - super.updateLayout(); - - // Sets panel to preferred size, without exceeding a maximum size and with a minimum size - pack(); - - // Request focus on the viewer when it is visible - FocusRequester.requestFocus(filePresenter); - } - }; - - // Add the AsyncPanel to the content pane - JPanel contentPane = new JPanel(new BorderLayout()); - contentPane.add(asyncPanel, BorderLayout.CENTER); - setContentPane(contentPane); - - setSize(WAIT_DIALOG_SIZE); - DialogToolkit.centerOnWindow(this, mainFrame); - - setVisible(true); - } - - private void showGenericErrorDialog() { - InformationDialog.showErrorDialog(mainFrame, getGenericErrorDialogTitle(), getGenericErrorDialogMessage()); - } - - /** - * Sets this file presenter to full screen - */ - public void setFullScreen(boolean on) { - int currentExtendedState = getExtendedState(); - setExtendedState(on ? currentExtendedState | Frame.MAXIMIZED_BOTH : currentExtendedState & ~Frame.MAXIMIZED_BOTH); - } - - /** - * Returns whether this frame is set to be displayed in full screen mode - * - * @return true if the frame is set to full screen, false otherwise - */ - public boolean isFullScreen() { - return (getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH; - } - - //////////////////////// - // Overridden methods // - //////////////////////// - - @Override - public void pack() { - if (!isFullScreen()) { - super.pack(); - - DialogToolkit.fitToScreen(this); - DialogToolkit.fitToMinDimension(this, getMinimumSize()); - - DialogToolkit.centerOnWindow(this, mainFrame); - } - } - - ////////////////////// - // Abstract methods // - ////////////////////// - - protected abstract String getGenericErrorDialogTitle(); - - protected abstract String getGenericErrorDialogMessage(); - - protected abstract FilePresenter createFilePresenter(AbstractFile file) throws UserCancelledException; -} +package com.mucommander.ui.viewer; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Image; + +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.WindowConstants; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mucommander.commons.file.AbstractFile; +import com.mucommander.commons.util.ui.dialog.DialogToolkit; +import com.mucommander.commons.util.ui.helper.FocusRequester; +import com.mucommander.ui.dialog.InformationDialog; +import com.mucommander.ui.layout.AsyncPanel; +import com.mucommander.ui.main.MainFrame; + +/** + * This class is used as an abstraction for the {@link EditorFrame} and {@link ViewerFrame}. + * + * @author Arik Hadas + */ +public abstract class FileFrame extends JFrame { + private static final Logger LOGGER = LoggerFactory.getLogger(FileFrame.class); + + private final static Dimension WAIT_DIALOG_SIZE = new Dimension(400, 350); + + // The file presenter within this frame + private FilePresenter filePresenter; + + // The main frame from which this frame was initiated + private MainFrame mainFrame; + + FileFrame(MainFrame mainFrame, AbstractFile file, Image icon) { + this.mainFrame = mainFrame; + + setIconImage(icon); + + // Call #dispose() on close (default is hide) + setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + + setResizable(true); + + initContentPane(file); + } + + public MainFrame getMainFrame() { + return mainFrame; + } + + protected void initContentPane(final AbstractFile file) { + try { + filePresenter = createFilePresenter(file); + } catch (UserCancelledException e) { + // May get a UserCancelledException if the user canceled (refused to confirm the operation after a warning) + return; + } + + // If not suitable presenter was found for the given file + if (filePresenter == null) { + LOGGER.debug("FilePresenter was null i.e. not suitable presenter was found for a given file!"); + showGenericErrorDialog(); + return; + } + + AsyncPanel asyncPanel = new AsyncPanel() { + + @Override + public JComponent getTargetComponent() { + try { + // Ask the presenter to present the file + filePresenter.open(file); + } catch(Exception e) { + LOGGER.error("Exception caught", e); + showGenericErrorDialog(); + dispose(); + return filePresenter == null ? new JPanel() : filePresenter; + } + + setJMenuBar(filePresenter.getMenuBar()); + + return filePresenter; + } + + @Override + protected void updateLayout() { + // Request focus on the viewer when it is visible + FocusRequester.requestFocus(filePresenter); + } + }; + + // Add the AsyncPanel to the content pane + JPanel contentPane = new JPanel(new BorderLayout()); + contentPane.add(asyncPanel, BorderLayout.CENTER); + setContentPane(contentPane); + + setSize(WAIT_DIALOG_SIZE); + DialogToolkit.centerOnWindow(this, mainFrame); + + setVisible(true); + } + + private void showGenericErrorDialog() { + InformationDialog.showErrorDialog(mainFrame, getGenericErrorDialogTitle(), getGenericErrorDialogMessage()); + } + + /** + * Returns whether this frame is set to be displayed in full screen mode + * + * @return true if the frame is set to full screen, false otherwise + */ + public boolean isFullScreen() { + return (getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH; + } + + /** + * Sets this file presenter to full screen + */ + public void setFullScreen(boolean on) { + int currentExtendedState = getExtendedState(); + setExtendedState( + on ? currentExtendedState | Frame.MAXIMIZED_BOTH : currentExtendedState & ~Frame.MAXIMIZED_BOTH); + } + + public void setDefaultBounds() { + DialogToolkit.fitToScreen(this); + DialogToolkit.fitToMinDimension(this, getMinimumSize()); + + DialogToolkit.centerOnWindow(this, mainFrame); + } + + ////////////////////// + // Abstract methods // + ////////////////////// + + protected abstract String getGenericErrorDialogTitle(); + + protected abstract String getGenericErrorDialogMessage(); + + protected abstract FilePresenter createFilePresenter(AbstractFile file) throws UserCancelledException; +} diff --git a/mucommander-core/src/main/java/com/mucommander/ui/viewer/FilePresenter.java b/mucommander-core/src/main/java/com/mucommander/ui/viewer/FilePresenter.java index 31dcd222fa..af48833dd8 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/viewer/FilePresenter.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/viewer/FilePresenter.java @@ -4,6 +4,7 @@ import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; import java.io.IOException; import javax.swing.AbstractAction; @@ -65,7 +66,7 @@ public void focusGained(FocusEvent e) { getActionMap().put(CUSTOM_DISPOSE_EVENT, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - getFrame().dispose(); + getFrame().dispatchEvent(new WindowEvent(getFrame(), WindowEvent.WINDOW_CLOSING)); } }); } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileViewerPresenter.java b/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileViewerPresenter.java index b8c1d11427..e3a1c40fc3 100644 --- a/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileViewerPresenter.java +++ b/mucommander-core/src/main/java/com/mucommander/ui/viewer/FileViewerPresenter.java @@ -17,7 +17,11 @@ package com.mucommander.ui.viewer; import java.awt.Cursor; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -37,30 +41,27 @@ import com.mucommander.commons.file.AbstractFile; import com.mucommander.commons.util.ui.helper.MenuToolkit; import com.mucommander.commons.util.ui.helper.MnemonicHelper; +import com.mucommander.text.Translator; import com.mucommander.ui.main.table.FileTable; import com.mucommander.viewer.FileViewer; import com.mucommander.viewer.FileViewerService; import com.mucommander.viewer.ViewerPresenter; import com.mucommander.viewer.WarnUserException; -import com.mucommander.text.Translator; /** * File viewer presenter to handle multiple file viewers. * - *

- * Warning: the file viewer/editor API may soon receive a major overhaul. - *

- * * @author Maxence Bernard, Arik Hadas */ public class FileViewerPresenter extends FilePresenter implements ViewerPresenter { - private FileViewer fileViewer = null; private final JMenuBar menuBar; private final JMenu viewerMenu; private final ButtonGroup viewersButtonGroup; private final List services = new ArrayList<>(); + private FileViewer fileViewer; private int viewersCount = 0; + private JMenuItem fullScreenMenuItem; private JMenuItem closeMenuItem; public FileViewerPresenter() { @@ -113,7 +114,7 @@ public void goToFile(Function advance, FileViewerService viewe fileTable.selectRow(newRow); newFile = fileTable.getSelectedFile(); try { - canView = viewerService.canViewFile(newFile); + canView = (newFile != null) && viewerService.canViewFile(newFile); } catch (WarnUserException ex) { canView = false; } @@ -123,16 +124,6 @@ public void goToFile(Function advance, FileViewerService viewe fileViewer.open(newFile); } - @Override - public boolean isFullScreen() { - return getFrame().isFullScreen(); - } - - @Override - public void setFullScreen(boolean fullScreen) { - getFrame().setFullScreen(fullScreen); - } - @Override public void longOperation(Runnable operation) { getFrame().setCursor(new Cursor(Cursor.WAIT_CURSOR)); @@ -163,22 +154,69 @@ public void addViewerService(FileViewerService service) throws UserCancelledExce protected void show(AbstractFile file) throws IOException { setCurrentFile(file); if (fileViewer == null) { + getFrame().setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + getFrame().addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + if (fileViewer != null) { + fileViewer.close(); + } + + close(); + } + }); + MnemonicHelper menuItemMnemonicHelper = new MnemonicHelper(); viewerMenu.addSeparator(); + + fullScreenMenuItem = MenuToolkit.addCheckBoxMenuItem(viewerMenu, + Translator.get("file_viewer.fullscreen"), + menuItemMnemonicHelper, + KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.CTRL_MASK), + (e) -> { + boolean fullScreen = getFrame().isFullScreen(); + switchFullScreenMode(!fullScreen); + }); + + String windowWidthValue = ViewerPreferences.WINDOW_WIDTH.getValue(); + if (!windowWidthValue.isEmpty()) { + int windowX = Integer.parseInt(ViewerPreferences.WINDOW_POSITION_X.getValue()); + int windowY = Integer.parseInt(ViewerPreferences.WINDOW_POSITION_Y.getValue()); + int windowWidth = Integer.parseInt(windowWidthValue); + int windowHeight = Integer.parseInt(ViewerPreferences.WINDOW_HEIGHT.getValue()); + getFrame().setBounds(windowX, windowY, windowWidth, windowHeight); + } else { + getFrame().setDefaultBounds(); + } + + String showFullScreenValue = ViewerPreferences.SHOW_FULLSCREEN.getValue(); + if (Boolean.TRUE.toString().equals(showFullScreenValue)) { + switchFullScreenMode(true); + } + viewerMenu.add(fullScreenMenuItem); + closeMenuItem = MenuToolkit.addMenuItem(viewerMenu, Translator.get("file_viewer.close"), menuItemMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), - (e) -> { - fileViewer.close(); - getFrame().dispose(); - }); + e -> getFrame().dispatchEvent(new WindowEvent(getFrame(), WindowEvent.WINDOW_CLOSING))); viewerMenu.add(closeMenuItem); switchFileViewer(0); } } + private void close() { + FileFrame frame = getFrame(); + Rectangle bounds = frame.getBounds(); + ViewerPreferences.WINDOW_POSITION_X.setValue(Integer.toString(bounds.x)); + ViewerPreferences.WINDOW_POSITION_Y.setValue(Integer.toString(bounds.y)); + ViewerPreferences.WINDOW_WIDTH.setValue(Integer.toString(bounds.width)); + ViewerPreferences.WINDOW_HEIGHT.setValue(Integer.toString(bounds.height)); + + frame.dispose(); + } + private void switchFileViewer(int index) throws IOException { if (fileViewer != null) { clearComponentToPresent(); @@ -197,6 +235,20 @@ private void switchFileViewer(int index) throws IOException { fileViewer.open(getCurrentFile()); fileViewer.extendMenu(menuBar); menuBar.revalidate(); + menuBar.repaint(); setComponentToPresent(viewerComponent); } + + private void switchFullScreenMode(boolean showFullScreen) { + getFrame().setFullScreen(showFullScreen); + fullScreenMenuItem.setSelected(showFullScreen); + ViewerPreferences.SHOW_FULLSCREEN.setValue(Boolean.toString(showFullScreen)); + } + + @Override + public void requestFocus() { + if (fileViewer != null) { + fileViewer.requestFocus(); + } + } } diff --git a/mucommander-core/src/main/java/com/mucommander/ui/viewer/ViewerPreferences.java b/mucommander-core/src/main/java/com/mucommander/ui/viewer/ViewerPreferences.java new file mode 100644 index 0000000000..d009301998 --- /dev/null +++ b/mucommander-core/src/main/java/com/mucommander/ui/viewer/ViewerPreferences.java @@ -0,0 +1,50 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.ui.viewer; + +/** + * Viewer preferences. + */ +public enum ViewerPreferences { + + SHOW_FULLSCREEN("show_fullscreen", "false"), + WINDOW_POSITION_X("window_position_x", ""), + WINDOW_POSITION_Y("window_position_y", ""), + WINDOW_WIDTH("window_width", ""), + WINDOW_HEIGHT("window_height", "") + ; + + private String prefKey; + private String value; + + ViewerPreferences(String prefKey, String defaultValue) { + this.prefKey = prefKey; + value = defaultValue; + } + + public String getPrefKey() { + return prefKey; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/mucommander-core/src/main/java/com/mucommander/ui/viewer/ViewerSnapshot.java b/mucommander-core/src/main/java/com/mucommander/ui/viewer/ViewerSnapshot.java new file mode 100644 index 0000000000..d6ce79a3ca --- /dev/null +++ b/mucommander-core/src/main/java/com/mucommander/ui/viewer/ViewerSnapshot.java @@ -0,0 +1,33 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.ui.viewer; + +import static com.mucommander.snapshot.MuSnapshot.FILE_PRESENTER_SECTION; + +import com.mucommander.snapshot.MuSnapshotable; + +/** + * Snapshot preferences for viewer. + */ +public final class ViewerSnapshot extends MuSnapshotable { + public ViewerSnapshot() { + super(ViewerPreferences::values, + ViewerPreferences::getValue, + ViewerPreferences::setValue, + pref -> pref.getPrefKey() != null ? FILE_PRESENTER_SECTION + "." + pref.getPrefKey() : null); + } +} diff --git a/mucommander-core/src/main/resources/license.txt b/mucommander-core/src/main/resources/license.txt index f3ac4097a9..1ee30bea2a 100644 --- a/mucommander-core/src/main/resources/license.txt +++ b/mucommander-core/src/main/resources/license.txt @@ -19,9 +19,11 @@ Additionally, muCommander uses the following third party works: - the J7Zip library under the terms of the GNU Lesser General Public License - the jCIFS library under the terms of the GNU Lesser General Public License - the JetS3t library under the terms of the Apache License +- the JediTerm library under the terms of dual GNU Lesser General Public License and Apache License - the JmDNS library under the terms of the GNU Lesser General Public License - the JNA library under the terms of the GNU Lesser General Public License - the JUnRar library under the terms of the GNU Lesser General Public License +- the RSyntaxTextArea library under the terms of BSD 3-Clause "New" or "Revised" License - the Yanfs library under the terms of the Berkeley Software Distribution License - the JCommander library under the terms of the Apache License - the ICEpdf library under the terms of the Apache License diff --git a/mucommander-encoding/build.gradle b/mucommander-encoding/build.gradle index e215c52e4a..f760408bc6 100644 --- a/mucommander-encoding/build.gradle +++ b/mucommander-encoding/build.gradle @@ -23,5 +23,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-ar/build.gradle b/mucommander-format-ar/build.gradle index ebe4cf44b8..611d861262 100644 --- a/mucommander-format-ar/build.gradle +++ b/mucommander-format-ar/build.gradle @@ -21,6 +21,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-bzip2/build.gradle b/mucommander-format-bzip2/build.gradle index 63d7a932e1..ddc4ac711f 100644 --- a/mucommander-format-bzip2/build.gradle +++ b/mucommander-format-bzip2/build.gradle @@ -22,6 +22,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-cpio/build.gradle b/mucommander-format-cpio/build.gradle index 6ae8d39b5c..5623844ccb 100644 --- a/mucommander-format-cpio/build.gradle +++ b/mucommander-format-cpio/build.gradle @@ -23,6 +23,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-gzip/build.gradle b/mucommander-format-gzip/build.gradle index c3034f0666..2209b27132 100644 --- a/mucommander-format-gzip/build.gradle +++ b/mucommander-format-gzip/build.gradle @@ -21,6 +21,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-iso/build.gradle b/mucommander-format-iso/build.gradle index e2547e6f21..83b64c1a30 100644 --- a/mucommander-format-iso/build.gradle +++ b/mucommander-format-iso/build.gradle @@ -21,6 +21,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-libguestfs/build.gradle b/mucommander-format-libguestfs/build.gradle index ed1fd1d608..d61ea1a806 100644 --- a/mucommander-format-libguestfs/build.gradle +++ b/mucommander-format-libguestfs/build.gradle @@ -20,5 +20,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-lst/build.gradle b/mucommander-format-lst/build.gradle index 07c40388a7..59bfa8280c 100644 --- a/mucommander-format-lst/build.gradle +++ b/mucommander-format-lst/build.gradle @@ -21,6 +21,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-rar/build.gradle b/mucommander-format-rar/build.gradle index 2d670d5773..f56a4f5d07 100644 --- a/mucommander-format-rar/build.gradle +++ b/mucommander-format-rar/build.gradle @@ -11,7 +11,7 @@ dependencies { api 'net.sf.sevenzipjbinding:sevenzipjbinding:16.02-2.01' implementation 'org.apache.commons:commons-vfs2:2.3' - implementation 'com.github.junrar:junrar:7.5.1' + implementation 'com.github.junrar:junrar:7.5.4' testImplementation 'org.testng:testng:6.11' } @@ -31,5 +31,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarArchiveFile.java b/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarArchiveFile.java index 445f1b5da2..0db2e16dbe 100644 --- a/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarArchiveFile.java +++ b/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarArchiveFile.java @@ -20,16 +20,16 @@ import java.io.IOException; import java.io.InputStream; -import java.util.Vector; +import java.util.Objects; +import com.github.junrar.exception.RarException; +import com.github.junrar.rarfile.FileHeader; import com.mucommander.commons.file.AbstractFile; import com.mucommander.commons.file.UnsupportedFileOperationException; import com.mucommander.commons.file.archive.AbstractROArchiveFile; import com.mucommander.commons.file.archive.ArchiveEntry; import com.mucommander.commons.file.archive.ArchiveEntryIterator; import com.mucommander.commons.file.archive.WrapperArchiveEntryIterator; -import com.github.junrar.exception.RarException; -import com.github.junrar.rarfile.FileHeader; /** * RarArchiveFile provides read-only access to archives in the Rar format. @@ -46,7 +46,7 @@ public class RarArchiveFile extends AbstractROArchiveFile { private long lastRarFileDate; - public RarArchiveFile(AbstractFile file) throws IOException { + public RarArchiveFile(AbstractFile file) { super(file); } @@ -60,11 +60,11 @@ public RarArchiveFile(AbstractFile file) throws IOException { * or is not implemented. * @throws RarException */ - private void checkRarFile() throws IOException, UnsupportedFileOperationException, RarException { + void check() throws IOException, UnsupportedFileOperationException, RarException { long currentDate = file.getDate(); - if (rarFile==null || currentDate != lastRarFileDate) { - rarFile = new RarFile(file); + if (rarFile == null || !Objects.equals(rarFile.getPassword(), password) || currentDate != lastRarFileDate) { + rarFile = new RarFile(file, password); declareRarFileUpToDate(currentDate); } } @@ -84,13 +84,12 @@ private void declareRarFileUpToDate(long currentFileDate) { * @return an ArchiveEntry whose attributes are fetched from the given FileHeader */ private ArchiveEntry createArchiveEntry(FileHeader header) { - return new ArchiveEntry( - header.getFileNameString().replace('\\', '/'), - header.isDirectory(), - header.getMTime().getTime(), - header.getFullUnpackSize(), - true - ); + return new ArchiveEntry( + header.getFileName().replace('\\', '/'), + header.isDirectory(), + header.getMTime().getTime(), + header.getFullUnpackSize(), + true); } @@ -101,30 +100,23 @@ private ArchiveEntry createArchiveEntry(FileHeader header) { @Override public synchronized ArchiveEntryIterator getEntryIterator() throws IOException, UnsupportedFileOperationException { try { - checkRarFile(); - } catch (RarException e) { - throw new IOException(); - } - - Vector entries = new Vector(); - for (Object o : rarFile.getEntries()) - entries.add(createArchiveEntry((FileHeader)o)); - - return new WrapperArchiveEntryIterator(entries.iterator()); + check(); + } catch (RarException e) { + throw new IOException(e); + } + var iterator = rarFile.getEntries().stream() + .map(this::createArchiveEntry) + .iterator(); + return new WrapperArchiveEntryIterator(iterator); } @Override public synchronized InputStream getEntryInputStream(ArchiveEntry entry, ArchiveEntryIterator entryIterator) throws IOException, UnsupportedFileOperationException { - try { - checkRarFile(); - } catch (RarException e) { - throw new IOException(); - } - - try { - return rarFile.getEntryInputStream(entry.getPath().replace('/', '\\')); - } catch (RarException e) { - throw new IOException(); - } - } + try { + check(); + return rarFile.getEntryInputStream(entry.getPath().replace('/', '\\')); + } catch (RarException e) { + throw new IOException(e); + } + } } diff --git a/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarFile.java b/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarFile.java index 256b4ae0e5..d39e02217d 100644 --- a/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarFile.java +++ b/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarFile.java @@ -28,18 +28,25 @@ import com.mucommander.commons.util.CircularByteBuffer; /** + * RAR 4 and lower * @author Arik Hadas */ public class RarFile { /** Interface to junrar library */ private Archive archive; - - public RarFile(AbstractFile file) throws IOException, UnsupportedFileOperationException, RarException { + public RarFile(AbstractFile file, String password) throws IOException, UnsupportedFileOperationException, RarException { try (InputStream fileIn = file.getInputStream()) { - archive = new Archive(fileIn); + archive = new Archive(fileIn, password); } + + if (archive.isPasswordProtected() && password == null) + throw new IOException("RAR archive is password-protected and no password was specified"); + } + + public String getPassword() { + return archive.getPassword(); } public Collection getEntries() { @@ -48,7 +55,7 @@ public Collection getEntries() { public InputStream getEntryInputStream(String path) throws IOException, RarException { final FileHeader header = archive.getFileHeaders().stream() - .filter(h -> h.getFileNameString().equals(path)) + .filter(h -> h.getFileName().equals(path)) .findFirst() .orElse(null); diff --git a/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarFormatProvider.java b/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarFormatProvider.java index af2abcb51b..a25c4d65eb 100644 --- a/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarFormatProvider.java +++ b/mucommander-format-rar/src/main/java/com/mucommander/commons/file/archive/rar/RarFormatProvider.java @@ -18,6 +18,14 @@ package com.mucommander.commons.file.archive.rar; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.junrar.exception.UnsupportedRarV5Exception; import com.mucommander.commons.file.AbstractFile; import com.mucommander.commons.file.archive.AbstractArchiveFile; import com.mucommander.commons.file.archive.ArchiveFormatProvider; @@ -27,13 +35,6 @@ import net.sf.sevenzipjbinding.ArchiveFormat; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * This class is the provider for the 'Rar' archive format implemented by {@link RarArchiveFile}. * @@ -50,15 +51,17 @@ public class RarFormatProvider implements ArchiveFormatProvider { @Override public AbstractArchiveFile getFile(AbstractFile file) throws IOException { - // trying RAR 5+ first as it has been the default for quite a while - SevenZipJBindingROArchiveFile archive = new SevenZipJBindingROArchiveFile(file, ArchiveFormat.RAR5, RAR5_SIGNATURE); + RarArchiveFile rar4 = new RarArchiveFile(file); + AbstractArchiveFile rar = rar4; try { - return archive.check(); - } catch(Exception e) { - // fall back to older versions (1.5 - 4.0) - LOGGER.info("failed to open archive as RAR 5+, trying older versions"); - return new RarArchiveFile(file); + rar4.check(); + } catch (UnsupportedRarV5Exception e) { + LOGGER.info("failed to open RAR file with junrar, trying as RAR 5+"); + rar = new SevenZipJBindingROArchiveFile(file, ArchiveFormat.RAR5, RAR5_SIGNATURE); + } catch (Exception e) { + // no-op, failures will be thrown when browsing/extracting the file } + return rar; } @Override diff --git a/mucommander-format-rpm/build.gradle b/mucommander-format-rpm/build.gradle index 7609626aa1..d97ebc26cc 100644 --- a/mucommander-format-rpm/build.gradle +++ b/mucommander-format-rpm/build.gradle @@ -23,6 +23,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-sevenzip/build.gradle b/mucommander-format-sevenzip/build.gradle index 588de20f7a..eb4a22ba20 100644 --- a/mucommander-format-sevenzip/build.gradle +++ b/mucommander-format-sevenzip/build.gradle @@ -23,6 +23,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-tar/build.gradle b/mucommander-format-tar/build.gradle index a809dfc869..1ca23deedd 100644 --- a/mucommander-format-tar/build.gradle +++ b/mucommander-format-tar/build.gradle @@ -23,7 +23,7 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml", + 'Build-Url': "https://www.mucommander.com/version/version.xml", 'Bundle-Activator': 'com.mucommander.commons.file.archive.tar.Activator') } diff --git a/mucommander-format-xz/build.gradle b/mucommander-format-xz/build.gradle index 40de3d8594..5ac9218961 100644 --- a/mucommander-format-xz/build.gradle +++ b/mucommander-format-xz/build.gradle @@ -23,6 +23,6 @@ jar { 'Implementation-Vendor': "Giorgos Retsinas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-format-zip/build.gradle b/mucommander-format-zip/build.gradle index 7dd53a4a02..84b38170c4 100644 --- a/mucommander-format-zip/build.gradle +++ b/mucommander-format-zip/build.gradle @@ -24,7 +24,7 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-URL': "https://www.mucommander.com/version/nightly.xml", + 'Build-URL': "https://www.mucommander.com/version/version.xml", 'Bundle-Activator': 'com.mucommander.commons.file.archive.zip.Activator') } diff --git a/mucommander-os-api/build.gradle b/mucommander-os-api/build.gradle index fc815e0702..d1e7076acf 100644 --- a/mucommander-os-api/build.gradle +++ b/mucommander-os-api/build.gradle @@ -39,5 +39,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-os-api/src/main/java/com/mucommander/desktop/ActionShortcuts.java b/mucommander-os-api/src/main/java/com/mucommander/desktop/ActionShortcuts.java index 67accb6e93..7446c11d08 100644 --- a/mucommander-os-api/src/main/java/com/mucommander/desktop/ActionShortcuts.java +++ b/mucommander-os-api/src/main/java/com/mucommander/desktop/ActionShortcuts.java @@ -183,6 +183,8 @@ public KeyStroke getDefaultKeystroke(ActionType actionId) { return KeyStroke.getKeyStroke(KeyEvent.VK_8, KeyEvent.CTRL_DOWN_MASK); case RecallWindow9: return KeyStroke.getKeyStroke(KeyEvent.VK_9, KeyEvent.CTRL_DOWN_MASK); + case Redo: + return KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK); case Refresh: return KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0); case Rename: @@ -261,6 +263,8 @@ public KeyStroke getDefaultKeystroke(ActionType actionId) { return KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0); case Unpack: return KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.CTRL_DOWN_MASK); + case Undo: + return KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_DOWN_MASK); case View: return KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0); default: @@ -284,6 +288,12 @@ public KeyStroke getDefaultAltKeyStroke(ActionType actionId) { return KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0); case GoToRoot: return KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SLASH, KeyEvent.CTRL_DOWN_MASK); + case InvertSelection: + return KeyStroke.getKeyStroke(KeyEvent.VK_8, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); + case MarkExtension: + return KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, KeyEvent.CTRL_DOWN_MASK); + case MarkGroup: + return KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK); case MarkSelectedFile: return KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 0); case NextTab: @@ -300,6 +310,8 @@ public KeyStroke getDefaultAltKeyStroke(ActionType actionId) { return KeyStroke.getKeyStroke(KeyEvent.VK_CONTEXT_MENU, 0); case SwitchActiveTable: return KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK); + case UnmarkGroup: + return KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyEvent.CTRL_DOWN_MASK); default: return null; } diff --git a/mucommander-os-api/src/main/java/com/mucommander/desktop/ActionType.java b/mucommander-os-api/src/main/java/com/mucommander/desktop/ActionType.java index 5c18fb5516..1e61cb39ba 100644 --- a/mucommander-os-api/src/main/java/com/mucommander/desktop/ActionType.java +++ b/mucommander-os-api/src/main/java/com/mucommander/desktop/ActionType.java @@ -121,6 +121,7 @@ public enum ActionType { RecallWindow7("RecallWindow7"), RecallWindow8("RecallWindow8"), RecallWindow9("RecallWindow9"), + Redo("Redo"), Refresh("Refresh"), Rename("Rename"), ReportBug("ReportBug"), @@ -185,6 +186,7 @@ public enum ActionType { UnmarkAll("UnmarkAll"), UnmarkGroup("UnmarkGroup"), Unpack("Unpack"), + Undo("Undo"), View("View"); diff --git a/mucommander-os-linux/build.gradle b/mucommander-os-linux/build.gradle index 31647b2784..9faf276a9d 100644 --- a/mucommander-os-linux/build.gradle +++ b/mucommander-os-linux/build.gradle @@ -36,5 +36,5 @@ 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-os-linux/src/main/java/com/mucommander/desktop/linux/xfce/XfceDesktopAdapter.java b/mucommander-os-linux/src/main/java/com/mucommander/desktop/linux/xfce/XfceDesktopAdapter.java index e7e343b51b..3b03522188 100644 --- a/mucommander-os-linux/src/main/java/com/mucommander/desktop/linux/xfce/XfceDesktopAdapter.java +++ b/mucommander-os-linux/src/main/java/com/mucommander/desktop/linux/xfce/XfceDesktopAdapter.java @@ -32,6 +32,7 @@ abstract class XfceDesktopAdapter extends DefaultDesktopAdapter { private static final String FILE_MANAGER_NAME = "Thunar"; private static final String FILE_OPENER = "exo-open $f"; private static final String EXE_OPENER = "$f"; + private static final String CMD_OPENER_COMMAND = "xfce4-terminal --default-working-directory $f"; @Override public void init(boolean install) throws DesktopInitialisationException { @@ -41,6 +42,7 @@ public void init(boolean install) throws DesktopInitialisationException { CommandManager.registerDefaultCommand(new Command(CommandManager.URL_OPENER_ALIAS, FILE_OPENER, CommandType.SYSTEM_COMMAND, null)); CommandManager.registerDefaultCommand(new Command(CommandManager.EXE_OPENER_ALIAS, EXE_OPENER, CommandType.SYSTEM_COMMAND, null)); CommandManager.registerDefaultCommand(new Command(CommandManager.FILE_MANAGER_ALIAS, FILE_OPENER, CommandType.SYSTEM_COMMAND, FILE_MANAGER_NAME)); + CommandManager.registerDefaultCommand(new Command(CommandManager.CMD_OPENER_ALIAS, CMD_OPENER_COMMAND, CommandType.SYSTEM_COMMAND, null)); } catch(CommandException e) {throw new DesktopInitialisationException(e);} } diff --git a/mucommander-os-macos-java8/build.gradle b/mucommander-os-macos-java8/build.gradle index ac1687d8ca..066145a36b 100644 --- a/mucommander-os-macos-java8/build.gradle +++ b/mucommander-os-macos-java8/build.gradle @@ -61,5 +61,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-os-macos/build.gradle b/mucommander-os-macos/build.gradle index cfce363444..365a5d019d 100644 --- a/mucommander-os-macos/build.gradle +++ b/mucommander-os-macos/build.gradle @@ -61,5 +61,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-os-macos/src/main/java/com/mucommander/desktop/macos/ActionShortcuts.java b/mucommander-os-macos/src/main/java/com/mucommander/desktop/macos/ActionShortcuts.java index e8fa8471c9..bac4df3ebf 100644 --- a/mucommander-os-macos/src/main/java/com/mucommander/desktop/macos/ActionShortcuts.java +++ b/mucommander-os-macos/src/main/java/com/mucommander/desktop/macos/ActionShortcuts.java @@ -119,6 +119,8 @@ public KeyStroke getDefaultKeystroke(ActionType actionId) { return KeyStroke.getKeyStroke(KeyEvent.VK_8, KeyEvent.META_DOWN_MASK); case RecallWindow9: return KeyStroke.getKeyStroke(KeyEvent.VK_9, KeyEvent.META_DOWN_MASK); + case Redo: + return KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.SHIFT_DOWN_MASK | KeyEvent.META_DOWN_MASK); case RevealInDesktop: return KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.META_DOWN_MASK); case RunCommand: @@ -157,6 +159,8 @@ public KeyStroke getDefaultKeystroke(ActionType actionId) { return KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.META_DOWN_MASK); case Unpack: return KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyEvent.META_DOWN_MASK); + case Undo: + return KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK); default: return super.getDefaultKeystroke(actionId); } diff --git a/mucommander-os-openvms/build.gradle b/mucommander-os-openvms/build.gradle index 5cc3fafd79..067eba3c5d 100644 --- a/mucommander-os-openvms/build.gradle +++ b/mucommander-os-openvms/build.gradle @@ -36,5 +36,5 @@ 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-os-win/build.gradle b/mucommander-os-win/build.gradle index 5081fac6f2..f7aef6a3f1 100644 --- a/mucommander-os-win/build.gradle +++ b/mucommander-os-win/build.gradle @@ -37,5 +37,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-preferences/build.gradle b/mucommander-preferences/build.gradle index 4c11774981..f71514d106 100644 --- a/mucommander-preferences/build.gradle +++ b/mucommander-preferences/build.gradle @@ -23,5 +23,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-preferences/src/main/java/com/mucommander/conf/MuPreference.java b/mucommander-preferences/src/main/java/com/mucommander/conf/MuPreference.java index a3296bc9cc..d5f4e69a85 100644 --- a/mucommander-preferences/src/main/java/com/mucommander/conf/MuPreference.java +++ b/mucommander-preferences/src/main/java/com/mucommander/conf/MuPreference.java @@ -72,7 +72,8 @@ public enum MuPreference { SMB_LM_COMPATIBILITY(MuPreferences.SMB_LM_COMPATIBILITY), SMB_USE_EXTENDED_SECURITY(MuPreferences.SMB_USE_EXTENDED_SECURITY), SHOW_TAB_HEADER(MuPreferences.SHOW_SINGLE_TAB_HEADER), - SET_DROP_ACTION_TO_COPY(MuPreferences.SET_DROP_ACTION_TO_COPY); + SET_DROP_ACTION_TO_COPY(MuPreferences.SET_DROP_ACTION_TO_COPY), + QUICK_SEARCH_TIMEOUT(MuPreferences.QUICK_SEARCH_TIMEOUT); private String label; private MuPreference(String label) { diff --git a/mucommander-preferences/src/main/java/com/mucommander/conf/MuPreferences.java b/mucommander-preferences/src/main/java/com/mucommander/conf/MuPreferences.java index 07214fd1e4..1c86744ff5 100644 --- a/mucommander-preferences/src/main/java/com/mucommander/conf/MuPreferences.java +++ b/mucommander-preferences/src/main/java/com/mucommander/conf/MuPreferences.java @@ -225,6 +225,10 @@ public class MuPreferences implements MuPreferencesAPI { public static final String SHOW_SINGLE_TAB_HEADER = FILE_TABLE_SECTION + '.' + "show_single_tab_header"; /** Default value for 'Always show single tab header" */ public static final boolean DEFAULT_SHOW_TAB_HEADER = false; + /** Quick search timeout in seconds */ + public static final String QUICK_SEARCH_TIMEOUT = FILE_TABLE_SECTION + '.' + "quick_search_timeout"; + /** Default value for 'Quick search timeout' */ + public static final int DEFAULT_QUICK_SEARCH_TIMEOUT = 2; /** Name of the root element's attribute that contains the version of muCommander used to write the CONFIGURATION file. */ static final String VERSION_ATTRIBUTE = "version"; diff --git a/mucommander-process/build.gradle b/mucommander-process/build.gradle index 384cd82cf7..bc032d3898 100644 --- a/mucommander-process/build.gradle +++ b/mucommander-process/build.gradle @@ -33,5 +33,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-api/build.gradle b/mucommander-protocol-api/build.gradle index 6fd839ce93..118d99212b 100644 --- a/mucommander-protocol-api/build.gradle +++ b/mucommander-protocol-api/build.gradle @@ -21,5 +21,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-dropbox/build.gradle b/mucommander-protocol-dropbox/build.gradle index f834056072..9a4461bf88 100644 --- a/mucommander-protocol-dropbox/build.gradle +++ b/mucommander-protocol-dropbox/build.gradle @@ -27,5 +27,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-ftp/build.gradle b/mucommander-protocol-ftp/build.gradle index 02abd1b8d9..3cb2483817 100644 --- a/mucommander-protocol-ftp/build.gradle +++ b/mucommander-protocol-ftp/build.gradle @@ -6,7 +6,7 @@ dependencies { api project(':mucommander-encoding') api project(':mucommander-translator') - implementation 'commons-net:commons-net:3.6' + implementation 'commons-net:commons-net:3.8.0' testImplementation 'junit:junit:4.12' testImplementation 'org.testng:testng:6.11' @@ -28,5 +28,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-gdrive/build.gradle b/mucommander-protocol-gdrive/build.gradle index 88d57bf029..5647f547d1 100644 --- a/mucommander-protocol-gdrive/build.gradle +++ b/mucommander-protocol-gdrive/build.gradle @@ -33,5 +33,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-gdrive/src/main/java/com/mucommander/commons/file/protocol/gdrive/GoogleDriveFile.java b/mucommander-protocol-gdrive/src/main/java/com/mucommander/commons/file/protocol/gdrive/GoogleDriveFile.java index e642cee9c2..d67762f514 100644 --- a/mucommander-protocol-gdrive/src/main/java/com/mucommander/commons/file/protocol/gdrive/GoogleDriveFile.java +++ b/mucommander-protocol-gdrive/src/main/java/com/mucommander/commons/file/protocol/gdrive/GoogleDriveFile.java @@ -208,7 +208,7 @@ public boolean isSystem() { public GoogleDriveFile[] ls() throws IOException, UnsupportedFileOperationException { try (GoogleDriveConnHandler connHandler = getConnHandler()) { FileList result = connHandler.getConnection().files().list() - .setFields("files(id,name,parents,size,modifiedTime,mimeType)") + .setFields("files(id,name,parents,size,modifiedTime,mimeType,trashed)") .setQ(String.format("'%s' in parents", getId())) .execute(); List files = result.getFiles(); @@ -219,6 +219,7 @@ public GoogleDriveFile[] ls() throws IOException, UnsupportedFileOperationExcept return files.stream() .filter(file -> file.getSize() != null || isFolder(file)) + .filter(file -> !file.getTrashed()) .map(this::toFile) .toArray(GoogleDriveFile[]::new); } @@ -310,14 +311,17 @@ public RandomAccessOutputStream getRandomAccessOutputStream() @Override public void delete() throws IOException, UnsupportedFileOperationException { - try(GoogleDriveConnHandler connHandler = getConnHandler()) { + try (GoogleDriveConnHandler connHandler = getConnHandler()) { connHandler.getConnection().files().delete(file.getId()).execute(); } } @Override public void renameTo(AbstractFile destFile) throws IOException, UnsupportedFileOperationException { - + try (GoogleDriveConnHandler connHandler = getConnHandler()) { + connHandler.getConnection().files().update(file.getId(), new File().setName(destFile.getName())).execute(); + file.setName(destFile.getName()); + } } @Override diff --git a/mucommander-protocol-hadoop/build.gradle b/mucommander-protocol-hadoop/build.gradle index de433cdabf..4fe3b63e01 100644 --- a/mucommander-protocol-hadoop/build.gradle +++ b/mucommander-protocol-hadoop/build.gradle @@ -28,5 +28,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-http/build.gradle b/mucommander-protocol-http/build.gradle index 6cd6637a35..d0322f4c6f 100644 --- a/mucommander-protocol-http/build.gradle +++ b/mucommander-protocol-http/build.gradle @@ -24,5 +24,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-URL': "https://www.mucommander.com/version/nightly.xml") + 'Build-URL': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-nfs/build.gradle b/mucommander-protocol-nfs/build.gradle index 0d68d305cd..45459f5db4 100644 --- a/mucommander-protocol-nfs/build.gradle +++ b/mucommander-protocol-nfs/build.gradle @@ -2,8 +2,7 @@ dependencies { api project(':mucommander-commons-file') api project(':mucommander-protocol-api') api project(':mucommander-translator') - - implementation files('libs/yanfs-1.4.jar') + api project(':sun-net-www') // Use JUnit test framework testImplementation 'junit:junit:4.12' @@ -30,5 +29,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-nfs/libs/yanfs-1.4.jar b/mucommander-protocol-nfs/libs/yanfs-1.4.jar deleted file mode 100644 index 58a68fa34e..0000000000 Binary files a/mucommander-protocol-nfs/libs/yanfs-1.4.jar and /dev/null differ diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/file/XFileAccessor.java b/mucommander-protocol-nfs/src/main/java/com/sun/file/XFileAccessor.java new file mode 100644 index 0000000000..c26084250b --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/file/XFileAccessor.java @@ -0,0 +1,386 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + * + */ + +package com.sun.file; + +import com.sun.xfile.*; +import java.io.*; + +/** + * The XFileAccessor interface is implemented by filesystems that + * need to be accessed via the XFile API. + * + * @author Brent Callaghan + * @version 1.0, 04/08/98 + * @see com.sun.xfile.XFile + */ +public class XFileAccessor implements com.sun.xfile.XFileAccessor { + + private XFile xf; + private File file; + private RandomAccessFile raf; + private boolean readOnly; + private long fp; // file pointer + + char sep = System.getProperty("file.separator").charAt(0); + + /** + * Open this file object + * + * @param xf the XFile for this file + * @param serial true if serial access + * @param readOnly true if read only + */ + public boolean open(XFile xf, boolean serial, boolean readOnly) { + this.xf = xf; + this.readOnly = readOnly; + + file = new File(unEscape(xf.getPath().replace('/', sep))); + + return file.exists(); + } + + /* + * Find any of "%nn" escapes in the string + * (where nn are hex digits) and convert to the + * equivalent ASCII character, e.g. "%3f" -> "?" + * See RFC 1738. + */ + private String unEscape(String s) { + + String hD = "0123456789abcdef"; + int p2; + String ns = ""; + int len = s.length(); + + for (int p = 0; p < len; p = p2 + 1) { + p2 = s.indexOf("%", p); + if (p2 < 0) // not found + p2 = len; + + ns += s.substring(p, p2); + + if (p2 == len) + break; + + /* + * Check for %nn where nn are hex digits + */ + if (p2 < (len - 2)) { + int d1 = hD.indexOf(s.toLowerCase().charAt(p2 + 1)); + int d2 = hD.indexOf(s.toLowerCase().charAt(p2 + 2)); + if (d1 > 0 && d2 > 0) { + ns += new String(new byte[] {(byte)(d1 << 4 | d2)}); + p2 += 2; + continue; + } + } + + ns += "%"; + } + + return ns; + } + + /** + * Get the XFile for this Accessor + * + * @return XFile for this object + */ + public XFile getXFile() { + return xf; + } + + /** + * Tests if this XFileAccessor object exists. + * + * @return true if the file specified by this object + * exists; false otherwise. + */ + public boolean exists() { + return file.exists(); + } + + + /** + * Tests if the application can write to this file. + * + * @return true if the application is allowed to + * write to a file whose name is specified by this + * object; false otherwise. + */ + public boolean canWrite() { + return file.canWrite(); + } + + + /** + * Tests if the application can read from the specified file. + * + * @return true if the file specified by this + * object exists and the application can read the file; + * false otherwise. + */ + public boolean canRead() { + return file.canRead(); + } + + /** + * Tests if the file represented by this + * object is a "normal" file. + *

+ * A file is "normal" if it is not a directory and, in + * addition, satisfies other system-dependent criteria. Any + * non-directory file created by a Java application is + * guaranteed to be a normal file. + * + * @return true if the file specified by this + * XFile object exists and is a "normal" + * file; false otherwise. + */ + public boolean isFile() { + return file.isFile(); + } + + + /** + * Tests if the file represented by this XFileAccessor + * object is a directory. + * + * @return true if this XFileAccessor object + * exists and is a directory; false + * otherwise. + */ + public boolean isDirectory() { + return file.isDirectory(); + } + + + /** + * Returns the time that the file represented by this + * XFile object was last modified. + *

+ * The return value is system dependent and should only be + * used to compare with other values returned by last modified. + * It should not be interpreted as an absolute time. + * + * @return the time the file specified by this object was last + * modified, or 0L if the specified file + * does not exist. + */ + public long lastModified() { + return file.lastModified(); + } + + + /** + * Returns the length of the file represented by this + * XFileAccessor object. + * + * @return the length, in bytes, of the file specified by + * this object, or 0L if the specified + * file does not exist. + */ + public long length() { + return file.length(); + } + + + /** + * Creates a file whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the file could be created; + * false otherwise. + */ + public boolean mkfile() { + try { + + // This little maneuver creates a zero length file + + FileOutputStream of = new FileOutputStream(file); + of.getFD().sync(); + of.close(); + return true; + + } catch (IOException e) { + return false; + } + } + + + /** + * Creates a directory whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the directory could be created; + * false otherwise. + */ + public boolean mkdir() { + return file.mkdir(); + } + + + /** + * Renames the file specified by this XFileAccessor object to + * have the pathname given by the XFileAccessor object argument. + * + * @param dest the new filename. + * @return true if the renaming succeeds; + * false otherwise. + */ + public boolean renameTo(XFile dest) { + return file.renameTo(new File(dest.getPath())); + } + + + /** + * Returns a list of the files in the directory specified by + * this XFileAccessor object. + * + * @return an array of file names in the specified directory. + * This list does not include the current directory or + * the parent directory ("." and + * ".." on Unix systems). + */ + public String[] list() { + return file.list(); + } + + + /** + * Deletes the file specified by this object. If the target + * file to be deleted is a directory, it must be empty for + * deletion to succeed. + * + * @return true if the file is successfully deleted; + * false otherwise. + */ + public boolean delete() { + return file.delete(); + } + + + /** + * Reads a subarray as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param foff the offset into the file + * @return number of bytes read; -1 if EOF + * @exception IOException If an I/O error has occurred. + */ + public int read(byte b[], int off, int len, long foff) + throws IOException { + + if (raf == null) + raf = new RandomAccessFile(file, readOnly ? "r" : "rw"); + + if (foff != fp) { + fp = foff; + raf.seek(foff); + } + + int c = raf.read(b, off, len); + if (c > 0) + fp += c; + + return (c); + } + + + /** + * Writes a sub array as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param foff the offset into the file + * @exception IOException If an I/O error has occurred. + */ + public void write(byte b[], int off, int len, long foff) + throws IOException { + + if (raf == null) + raf = new RandomAccessFile(file, readOnly ? "r" : "rw"); + + if (foff != fp) { + fp = foff; + raf.seek(foff); + } + + raf.write(b, off, len); + + fp += len; + } + + + /** + * Forces any buffered output bytes to be written out. + *

+ * Since RandomAccessFile has no corresponding method + * this does nothing. + * + * @exception IOException if an I/O error occurs. + */ + public void flush() throws IOException { + } + + + /** + * Close the file + * + * @exception IOException If an I/O error has occurred. + */ + public void close() throws IOException { + + if (raf != null) + raf.close(); + } + + + /** + * Returns a string representation of this object. + * + * @return a string giving the pathname of this object. + */ + public String toString() { + return file.toString(); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/C018FE95.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/C018FE95.java new file mode 100644 index 0000000000..bb4b3bccf8 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/C018FE95.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.io.InputStream; +import java.io.OutputStream; + + +/** + * An object of this class implements the functionality of a GSSContext + * for a specific mechanism. + * A C018FE95 object can be thought of having 3 states: + * -before initialization + * -during initialization with its peer + * -after it is established + *

+ * The context options can only be requested in state 1. In state 3, + * the per message operations are available to the callers. The get + * methods for the context options will return the requested options + * while in state 1 and 2, and the established values in state 3. + * Some mechanisms may allow the access to the per-message operations + * and the context flags before the context is fully established. The + * isProtReady method is used to indicate that these services are + * available. + */ + +public interface C018FE95 { + + /** + * Sets the mechanism options to be used during context + * creation on the initiator's side. This is used to + * initialize a new C018FE95 object. + * + * @param myCred the principal's credentials; may be null + * @param targName the context peer + * @param desLifetime the requested lifetime; 0 indicates use + * default + * @param mechOptions ORed GSSContext options + * @exception GSSException may be thrown + */ + public void _S235D9C1 (GSSCredSpi myCred, GSSNameSpi targName, + int desLifetime, int ctxtOptions) throws GSSException; + + + /** + * Sets the mechanism options to be used during context + * creation on the acceptor's side. This is used to initialize + * a new C018FE95 object. + * + * @param myCred the principal's credentials; may be null + * @exception GSSException may be thrown + */ + public void _S90010CC (GSSCredSpi myCred) throws GSSException; + + + /** + * Sets the channel bindings to be used during context + * establishment. This method is only called if the application + * wishes to use channel bindings with this context. + * + * @param chb channel bindings to be set + * @exception GSSException may be thrown + */ + public void _S9B00AB2 (ChannelBinding chb) throws GSSException; + + + /** + * Retrieves the mechanism options. + * + * @return int GSSContext options ORed together + */ + public int _S00027C3 (); + + + /** + * Inquire the remaining lifetime. + * + * @return the lifetime in seconds. May return reserved + * value GSSContext.INDEFINITE for an indefinite lifetime. + */ + public int _S4080EED (); + + + /** + * Returns the mechanism oid. + * + * @return the Oid for this context + */ + public Oid _S0200735 (); + + + /** + * Returns the context initiator name. + * + * @return initiator name + * @exception GSSException may be thrown + */ + public GSSNameSpi _S000EEFF () throws GSSException; + + + /** + * Returns the context acceptor name. + * + * @return context acceptor(target) name + * @exception GSSException may be thrown + */ + public GSSNameSpi _S011CEF9 () throws GSSException; + + + /** + * Returns the delegated credential for the context. This + * is an optional feature of contexts which not all + * mechanisms will support. A context can be requested to + * support credential delegation by using the CRED_DELEG. + * This is only valid on the acceptor side of the context. + * @return GSSCredSpi object for the delegated credential + * @exception GSSException may be thrown + * @see GSSContext#getDelegCredState + */ + public GSSCredSpi _S0293FFA () throws GSSException; + + + /** + * Tests if this is the initiator side of the context. + * + * @return boolean indicating if this is initiator (true) + * or target (false) + */ + public boolean _S123049E (); + + + /** + * Tests if the context can be used for per-message service. + * Context may allow the calls to the per-message service + * functions before being fully established. + * + * @return boolean indicating if per-message methods can + * be called. + */ + public boolean _S1116FAA (); + + + /** + * Initiator context establishment call. This method may be + * required to be called several times. A CONTINUE_NEEDED return + * call indicates that more calls are needed after the next token + * is received from the peer. + * + * @param is contains the token received from the peer. On the + * first call it will be ignored. + * @param os to which any tokens required to be sent to the peer + * will be written. It is responsibility of the caller + * to send the token to its peer for processing. + * @return integer indicating if more calls are needed. Possible + * values are COMPLETE and CONTINUE_NEEDED. + * @exception GSSException may be thrown + */ + public int _S0E039DB (InputStream is, OutputStream os) + throws GSSException; + + + /** + * Acceptor's context establishment call. This method may be + * required to be called several times. A CONTINUE_NEEDED return + * call indicates that more calls are needed after the next token + * is received from the peer. + * + * @param is contains the token received from the peer. + * @param os to which any tokens required to be sent to the peer + * will be written. It is responsibility of the caller + * to send the token to its peer for processing. + * @return integer indicating if more calls are needed. Possible + * values are COMPLETE and CONTINUE_NEEDED. + * @exception GSSException may be thrown + */ + public int _S80A2F2C (InputStream is, OutputStream os) + throws GSSException; + + + /** + * Queries the context for largest data size to accomodate + * the specified protection and for the token to remain less then + * maxTokSize. + * + * @param qop the quality of protection that the context will be + * asked to provide. + * @param confReq a flag indicating whether confidentiality will be + * requested or not + * @param outputSize the maximum size of the output token + * @return the maximum size for the input message that can be + * provided to the wrap() method in order to guarantee that these + * requirements are met. + * @exception GSSException may be thrown + */ + public int _S808028B (int qop, boolean confReq, int maxTokSize) + throws GSSException; + + + /** + * Provides per-message token encapsulation. + * + * @param is the user-provided message to be protected + * @param os the token to be sent to the peer. It includes + * the message from is with the requested protection. + * @param msgPro on input it contains the requested qop and + * confidentiality state, on output, the applied values + * @exception GSSException may be thrown + * @see MessageInfo + * @see unwrap + */ + public void _S1309AFD (InputStream is, OutputStream os, MessageProp msgProp) + throws GSSException; + + + /** + * Retrieves the message token previously encapsulated in the wrap + * call. + * + * @param is the token from the peer + * @param os unprotected message data + * @param msgProp will contain the applied qop and confidentiality + * of the input token and any informatory status values + * @exception GSSException may be thrown + * @see MessageInfo + * @see wrap + */ + public void _S1576D09 (InputStream is, OutputStream os, + MessageProp msgProp) throws GSSException; + + + /** + * Applies per-message integrity services. + * + * @param is the user-provided message + * @param os the token to be sent to the peer along with the + * message token. The message token is not encapsulated. + * @param msgProp on input the desired QOP and output the applied QOP + * @exception GSSException + */ + public void _S1513DBA (InputStream is, OutputStream os, + MessageProp msgProp) + throws GSSException; + + + /** + * Checks the integrity of the supplied tokens. + * This token was previously generated by getMIC. + * + * @param is token generated by getMIC + * @param msgStr the message to check integrity for + * @param msgProp will contain the applied QOP and confidentiality + * states of the token as well as any informatory status codes + * @exception GSSException may be thrown + */ + public void _S00256CF (InputStream is, InputStream msgStr, + MessageProp mProp) throws GSSException; + + + /** + * Produces a token representing this context. After this call + * the context will no longer be usable until an import is + * performed on the returned token. + * + * @return exported context token + * @exception GSSException may be thrown + */ + public byte []_S725B2DA () throws GSSException; + + + /** + * Imports a previously exported context. This will be called + * for newly created objects. + * + * @param is the previously exported token + * @exception GSSException may be thrown + * @see export + */ + public void _S0AC8F9E (byte []token) throws GSSException; + + + /** + * Releases context resources and terminates the + * context between 2 peer. + * + * @exception GSSException may be thrown + */ + public void _S020B957 () throws GSSException; +} + + diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/ChannelBinding.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/ChannelBinding.java new file mode 100644 index 0000000000..b30c754dad --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/ChannelBinding.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.net.InetAddress; + +/** + * The JGSS accommodates the concept of caller-provided channel + * binding information. Channel bindings are used to strengthen + * the quality with which peer entity authentication is provided + * during context establishment. They enable the JGSS callers to + * bind the establishment of the a security context to relevant + * characteristics like addresses or to application specific data. + *

+ * The caller initiating the security context must determine the + * appropriate channel binding values to set in the GSSContext + * object. The acceptor must provide identical binding in order + * to validate that received tokens possess correct + * channel-related characteristics. + *

+ * Use of channel bindings is optional in JGSS. Since channel- + * binding information may be transmitted in context establishment + * tokens, applications should therefore not use confidential data + * as channel-binding components. + * @see GSSContext#setChannelBinding + * @see java.net.InetAddress + */ + +public class ChannelBinding { + + private InetAddress m_initiator; + private InetAddress m_acceptor; + + private byte[] m_appData; + + /** + * Construct a channel bindings object that contains all the user + * specified tags. + * + * @param initAddr the address of the context initiator + * @param acceptAddr address of the context acceptor + * @param appData a byte array of application data to be used as + * part of the channel-binding + */ + public ChannelBinding(InetAddress initAddr, InetAddress acceptAddr, + byte[] appData) { + + m_initiator = initAddr; + m_acceptor = acceptAddr; + + if (appData != null) { + m_appData = new byte[appData.length]; + java.lang.System.arraycopy(appData, 0, m_appData, 0, + m_appData.length); + } + } + + + /** + * Construct a channel bindings object without any addressing + * information. + * + * @param appData a byte array of application data to be used as + * part of the channel-binding + */ + public ChannelBinding(byte[] appData) { + + m_initiator = null; + m_acceptor = null; + m_appData = new byte[appData.length]; + java.lang.System.arraycopy(appData, 0, m_appData, 0, + m_appData.length); + } + + /** + * Get the initiator's address for this channel binding. + * + * @return the initiator's address. null if no address + * information is contained + */ + public InetAddress getInitiatorAddress() { + + return m_initiator; + } + + /** + * Get the acceptor's address for this channel binding. + * + * @return the acceptor's address. null if no address + * information is contained + */ + public InetAddress getAcceptorAddress() { + + return m_acceptor; + } + + + /** + * Get the application specified data for this channel binding. + * The byte array is not copied. + * + * @return byte[] the application data that comprises this + * channel-binding + */ + public byte[] getApplicationData() { + + return m_appData; + } + + + /** + * Compares two instances of ChannelBinding + * + * @return true if objects are the same + * @overrides java.lang.Object#equals + */ + public boolean equals(Object obj) { + + if (! (obj instanceof ChannelBinding)) + return false; + + ChannelBinding cb = (ChannelBinding)obj; + + //check for application data being null in one but not the other + if ((getApplicationData() == null && + cb.getApplicationData() != null) || + (getApplicationData() != null && + cb.getApplicationData() == null)) + return (false); + + return (this.m_initiator.equals(cb.getInitiatorAddress()) && + this.m_acceptor.equals(cb.getAcceptorAddress()) && + (this.getApplicationData() == null || + this.m_appData.equals(cb.getApplicationData()))); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/DERParser.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/DERParser.java new file mode 100644 index 0000000000..8f1f4092a6 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/DERParser.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.io.ByteArrayOutputStream; +import java.util.Vector; + +/** + * This is a package private class used to decode/encode ASN.1 DER + * oids. + */ +class DERParser { + + /** + * Returns the DER encoded length from the InputStream. + */ + static int readLength(InputStream is) throws GSSException { + + int length, tmp; + + //get the length of Oid - check if short form + try { + if (((tmp = is.read()) & 0x080) == 0) + length = tmp; + else { + //must be long form + tmp &= 0x7f; + for (length = 0; tmp > 0; tmp--) { + length <<= 8; + length += (0xff & is.read()); + } + } + } catch (IOException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + + return (length); + } + + + /** + * Decodes a DER encoding of an Oid object into vector components. + */ + static Vector decodeOid(InputStream is) throws GSSException { + + //check the tag first + try { + if (is.read() != 0x06) + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } catch (IOException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + + return (decodeOidOctets(is, readLength(is))); + } + + + /** + * Decodes the specified number of oid octets. + * Returns a vector of integer components. + */ + + static Vector decodeOidOctets(InputStream is, int numOfOctets) + throws GSSException { + + Vector v = new Vector(9, 3); + + //first octet is combination of first two numbers + try { + int comp, tmp = is.read(); + if (tmp < 40) + comp = 0; + else if (tmp < 80) + comp = 1; + else + comp = 2; + + v.addElement(new Integer(comp)); + v.addElement(new Integer(tmp - (40 * comp))); + + //get the rest of the octets + for (int i = 1; i < numOfOctets; i++) { + comp = 0; + + //assume that at most 4 octets make up each component + for (int j=0; j < 4; j++) { + comp <<= 7; + tmp = is.read(); + comp |= (tmp & 0x7f); + if ((tmp & 0x80) == 0) + break; + i++; + } + v.addElement(new Integer(comp)); + } + + } catch (IOException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + + return (v); + } + + /** + * Encodes DER length. + */ + static void writeLength(OutputStream os, int len) throws IOException { + + //encode the length - for all practical purposes, the length + //should always be less then 0x80 (128) + if (len < 0x80) + os.write(len); + else if (len < 0x100) { + os.write(0x081); + os.write(len); + } else if (len < 0x80000) { + os.write(0x082); + os.write(len >> 8); + os.write(len & 0xff); + } else if (len < 0x1000000) { + os.write(0x083); + os.write(len >> 16); + os.write((len >> 8) & 0xff); + os.write(len & 0xff); + } else { + os.write(0x084); + os.write(len >>> 24); + os.write((len >> 16) & 0xff); + os.write((len >> 8) & 0xff); + os.write(len & 0xff); + } + } + + + /** + * Produces ASN.1 DER encoding for the object. + * @return byte[] DER encoding for the object + */ + static byte[] encodeOid(Vector v) throws GSSException { + + //use byte array output stream - 32 initial bytes should be enough + ByteArrayOutputStream o = new ByteArrayOutputStream(); + + int length = 1; + + try { + //start with Oid tag + o.write(0x06); + + //figure our the length - must have at least 2 elements X.208 + if (v.size() < 2) + throw new IllegalArgumentException(); + + for (int i = 2; i < v.size(); i++) { + int compLen = 0; + int nextComp = ((Integer)v.elementAt(i)).intValue(); + + //count # of 7 bit octets this will occupy + for (compLen = 0; nextComp > 0; nextComp >>= 7, compLen++) + ;//nothing to do + + //must have at least 1 octet + if (compLen == 0) + length += 1; + else + length += compLen; + } + + writeLength(o, length); + + //now write the components + writeOidOctets(o, v); + } catch (IOException e) { + + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + return (o.toByteArray()); + } + + + /** + * Encodes the oid octets onto the stream. + */ + static void writeOidOctets(OutputStream o, Vector v) throws IOException { + + //first 2 components occupy 1 octet + o.write(((Integer)v.elementAt(0)).intValue() * 40 + + ((Integer)v.elementAt(1)).intValue()); + + for (int i = 2; i < v.size(); i++) { + + int tmp, nextComp = ((Integer)v.elementAt(i)).intValue(); + + //each component may be at most 4 octets long + for (int c = 0; c < 4; c++) { + tmp = (nextComp & 0x7f); + nextComp >>>= 7; + + //every octet except for last has bit 8 on + if (nextComp > 0) + o.write(tmp | 0x80); + else { + o.write(tmp); + break; + } + } + } + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSContext.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSContext.java new file mode 100644 index 0000000000..cb1bba73b8 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSContext.java @@ -0,0 +1,1591 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + + +/** + * This class represents the JGSS security context and its associated + * operations. JGSS security contexts are established between + * peers using locally established credentials. Multiple contexts + * may exist simultaneously between a pair of peers, using the same + * or different set of credentials. The JGSS is independent of + * the underlying transport protocols and depends on its callers to + * transport the tokens between peers. + *

+ * The context object can be thought of as having 3 implicit states: + * before it is established, during its context establishment, and + * after a fully established context exists. + *

+ * Before the context establishment phase is initiated, the context + * initiator may request specific characteristics desired of the + * established context. These can be set using the set methods. After the + * context is established, the caller can check the actual characteristic + * and services offered by the context using the query methods. + *

+ * The context establishment phase begins with the first call to the init + * method by the context initiator. During this phase the init and accept + * methods will produce GSS-API authentication tokens which the calling + * application needs to send to its peer. The init and accept methods may + * return a CONTINUE_NEEDED code which indicates that a token is needed + * from its peer in order to continue the context establishment phase. A + * return code of COMPLETE signals that the local end of the context is + * established. This may still require that a token be sent to the peer, + * depending if one is produced by GSS-API. The isEstablished method can + * also be used to determine if the local end of the context has been + * fully established. During the context establishment phase, the + * isProtReady method may be called to determine if the context can be + * used for the per-message operations. This allows implementation to + * use per-message operations on contexts which aren't fully established. + *

+ * After the context has been established or the isProtReady method + * returns "true", the query routines can be invoked to determine the actual + * characteristics and services of the established context. The + * application can also start using the per-message methods of wrap and + * getMIC to obtain cryptographic operations on application supplied data. + *

+ * When the context is no longer needed, the application should call + * dispose to release any system resources the context may be using. + *

RFC 2078 + *
This class corresponds to the context level calls together with + * the per message calls of RFC 2078. The gss_init_sec_context and + * gss_accept_sec_context calls have been made simpler by only taking + * required parameters. The context can have its properties set before + * the first call to init. The supplementary status codes for the per-message + * operations are returned in an instance of the MessageProp class, which is + * used as an argument in these calls.
+ */ +public class GSSContext { + + /** + * Indefinite lifetime value for a context. Set to the + * largest value for an int in Java. + * @see #getLifetime + */ + public static final int INDEFINITE = Integer.MAX_VALUE; + + /** + * Return value from either accept or init stating that + * the context creation phase is complete for this peer. + * @see #init + * @see #accept + */ + public static final int COMPLETE = 0; + + /** + * Return value from either accept or init stating that + * another token is required from the peer to continue context + * creation. This may be returned several times indicating + * multiple token exchanges. + * @see #init + * @see #accept + */ + public static final int CONTINUE_NEEDED = 1; + + /** + * Context option flag - credential delegation. + */ + public static final int CRED_DELEG = 0x1; + + /** + * Context option flag - mutual authentication. + */ + public static final int MUTUAL_AUTH = 0x02; + + /** + * Context option flag - replay detection. + */ + public static final int REPLAY_DET = 0x04; + + /** + * Context option flag - sequence detection. + */ + public static final int SEQUENCE_DET = 0x08; + + /** + * Context option flag - anonymity. + */ + public static final int ANON = 0x10; + + /** + * Context option flag - confidentiality. + */ + public static final int CONF = 0x20; + + /** + * Context option flag - integrity. + */ + public static final int INTG = 0x40; + + /** + * Context option flag - transferability (output flag only). + * Indicates if context may be transferred by using export(). + * @see #export + */ + public static final int TRANS = 0x80; + + + /** + * Constructor for creating a context on the initiator's side. + * Context flags may be modified through the set methods prior + * to calling init(). + * + * @param peer Name of the target peer. + * @param mechOid Oid of the desired mechanism; + * may be null to indicate the default mechanism + * @param myCred the credentials for the initiator; may be + * null to indicate desire to use the default credentials + * @param lifetime the request lifetime, in seconds, for the context + * @exception GSSException with possible major codes of BAD_NAME, + * BAD_MECH, BAD_NAMETYPE. + * @see #init + */ + public GSSContext(GSSName peer, Oid mechOid, GSSCredential myCred, int + lifetime) throws GSSException { + + initialize(); + + m_myCred = myCred; + m_reqLifetime = lifetime; + m_targName = peer; + + if (mechOid == null) + m_mechOid = GSSManager.getDefaultMech(); + else + m_mechOid = mechOid; + } + + + /** + * Constructor for creating a context on the acceptor' side. The + * context's properties will be determined from the input token + * supplied to accept(). + * + * @param myCred GSSCredential for the acceptor. Use null to + * request usage of default credentials. + * @exception GSSException with possible major codes of BAD_NAME, + * BAD_MECH, BAD_NAMETYPE. + * @see #accept + */ + public GSSContext(GSSCredential myCred) throws GSSException { + + initialize(); + m_myCred = myCred; + } + + + /** + * Constructor for creating a GSSContext from a previously + * exported context. The context properties will be determined + * from the input token. + *

RFC 2078 + *
equivalent to gss_import_sec_context
+ * @param interProcessToken the token emitted from export routine + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * NO_CONTEXT, DEFECTIVE_TOKEN, UNAVAILABLE, UNAUTHORIZED, FAILURE + * @see #export + */ + public GSSContext(byte [] interProcessToken) throws GSSException { + + initialize(); + + /* + * Strip the mechanism oid from the token + * + * the token encoding is implementation specific, and + * we start by having 4 bytes of length, followed by the + * mechanism oid of the specified length, followed by the + * mechanism part of the token. This is the same as our C + * version. + */ + try { + int length = (interProcessToken[0] & 0xff); + for (int i = 1; i < 4; i++) { + length <<= 8; + length += (interProcessToken[i] & 0xff); + } + + ByteArrayInputStream is = + new ByteArrayInputStream(interProcessToken); + + //ask mechanism to import this context + m_mechCtxt = GSSManager._M4092FBA ( + Oid.getFromDEROctets(is, length)); + m_mechCtxt._S0AC8F9E (interProcessToken); + m_curState = READY; + + } catch (ArrayIndexOutOfBoundsException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + } + + + /** + * Called by the context initiator to start the context creation + * process. This is equivalent to the stream based method except + * that the token buffers are handled as byte arrays instead of + * using stream objects. This method may return an output token + * which the application will need to send to the peer for + * processing by the accept call. "null" return value indicates + * that no token needs to be sent to the peer. The application + * can call isEstablished to determine if the context + * establishment phase is complete for this peer. A return value + * of "false" from isEstablished indicates that more tokens are + * expected to be supplied to the init method. Please note that + * the init method may return a token for the peer, and + * isEstablished return "true" also. This indicates that the token + * needs to be sent to the peer, but the local end of the context + * is now fully established. + *

+ * Upon completion of the context establishment, the available + * context options may be queried through the get methods. + *

RFC 2078 + *
equivalent to gss_init_sec_context; The requested context + * options can be set before the first call, and the available + * options can be obtained after the context is fully established. + *
+ * @param inputBuf token generated by the peer; this parameter is + * ignored on the first call + * @param outputBuf token generated for the peer; this may be empty + * @return establishment state of either COMPLETE or CONTINUE_NEEDED + * @exception GSSException with possible major values of DEFECTIVE_TOKEN, + * DEFECTIVE_CREDENTIAL, BAD_SIG, NO_CRED, CREDENTIALS_EXPIRED, + * BAD_BINDINGS, OLD_TOKEN, DUPLICATE_ELEMENT, BAD_NAMETYPE, BAD_NAME, + * BAD_MECH, and FAILURE + * @see #init(InputStream,OutputStream) + * @see #setChannelBinding + */ + public byte[] init(byte []inputBuf, int offset, int length) + throws GSSException { + + ByteArrayInputStream is = null; + + if (inputBuf != null) + is = new ByteArrayInputStream(inputBuf, offset, length); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + init(is, os); + if (os.size() == 0) + return (null); + + return (os.toByteArray()); + } + + + /** + * Called by the context initiator to start the context creation + * process. This is equivalent to the byte array based method. + * This method may write an output token to the outputBuf, which + * the application will need to send to the peer for processing + * by the accept call. 0 bytes written to the output stream + * indicate that no token needs to be sent to the peer. The + * method will return either COMPLETE or CONTINUE_NEEDED + * indicating the status of the current context. A return value + * of COMPLETE indicates that the context establishment phase is + * complete for this peer, while CONTINUE_NEEDED means that + * another token is expected from the peer. The isEstablished + * method can also be used to determine this state. Note that + * it is possible to have a token for the peer while this method + * returns COMPLETE. This indicates that the local end of the + * context is established, but the token needs to be sent to + * the peer to complete the context establishment. + *

+ * The GSS-API authentication tokens contain a definitive + * start and end. This method will attempt to read one of these + * tokens per invocation, and may block on the stream if only + * part of the token is available. + *

+ * Upon completion of the context establishment, the available + * context options may be queried through the get methods. + *

RFC 2078 + *
equivalent to gss_init_sec_context; The requested context + * options can be set before the first call, and the available + * options can be obtained after the context is fully established. + *
+ * @param inputBuf token generated by the peer; this parameter is + * ignored on the first call + * @param outputBuf token generated for the peer; this may be empty + * @return establishment state of either COMPLETE or CONTINUE_NEEDED + * @exception GSSException with possible major values of DEFECTIVE_TOKEN, + * DEFECTIVE_CREDENTIAL, BAD_SIG, NO_CRED, CREDENTIALS_EXPIRED, + * BAD_BINDINGS, OLD_TOKEN, DUPLICATE_ELEMENT, BAD_NAMETYPE, BAD_NAME, + * BAD_MECH, and FAILURE + * @see #init(byte[],int,int) + * @see #accept(byte[],int,int) + * @see #setChannelBinding + */ + public int init(InputStream inputBuf, OutputStream outputBuf) + throws GSSException { + + if (m_mechCtxt == null) { + m_mechCtxt = GSSManager._M4092FBA (m_mechOid); + GSSCredSpi mechCred = null; + if (m_myCred != null) + mechCred = m_myCred.getMechCred(m_mechOid, true); + + m_mechCtxt._S235D9C1 (mechCred, + m_targName.canonicalizeInPlace(m_mechOid), + m_reqLifetime, m_reqFlags); + + if (m_chB != null) + m_mechCtxt._S9B00AB2 (m_chB); + + m_curState = IN_PROGRESS; + } + + //debug code + if (m_curState != IN_PROGRESS) { + throw new GSSException(GSSException.FAILURE, -1, + "wrong status in init"); + } + + int retStatus = m_mechCtxt._S0E039DB (inputBuf, outputBuf); + if (retStatus == COMPLETE) + m_curState = READY; + + return (retStatus); + } + + + /** + * Called by the context acceptor upon receiving a token from + * the peer. This call is equivalent to the stream based method + * except that the token buffers are handled as byte arrays + * instead of using stream objects. + *

+ * This method may return an output token which the application + * will need to send to the peer for further processing by the + * init call. "null" return value indicates that no token needs + * to be sent to the peer. The application can call isEstablished + * to determine if the context establishment phase is complete + * for this peer. A return value of "false" from isEstablished + * indicates that more tokens are expected to be supplied to this + * method. + *

+ * Please note that the accept method may return a token for the + * peer, and isEstablished return "true" also. This indicates that + * the token needs to be sent to the peer, but the local end of the + * context is now fully established. + *

+ * Upon completion of the context establishment, the available + * context options may be queried through the get methods. + * Called by the context acceptor upon receiving a token from + * the peer. May need to be called again if returns CONTINUE_NEEDED. + * + *

RFC 2078 + *
equivalent to gss_accept_sec_context; context options can + * obtained through the query methods + *
+ * @param inputToken token that was received from the initiator + * @param outputBut token generated for the peer; may be empty + * @return creation state of either COMPLETE or CONTINUE_NEEDED + * @exception GSSException may be thrown with major status values of + * DEFECTIVE_TOKEN, DEFECTIVE_CREDENTIAL, BAD_SIG, NO_CRED, + * CREDENTIALS_EXPIRED, BAD_BINDINGS, OLD_TOKEN, DUPLICATE_ELEMENT, + * BAD_MECH, and FAILURE + * @see #init(byte[],int,int) + * @see #accept(InputStream,OutputStream) + * @see #setChannelBinding + */ + public byte[] accept(byte[] inTok, int offset, int length) + throws GSSException { + + ByteArrayInputStream is = new ByteArrayInputStream(inTok, + offset, length); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + accept(is, os); + + //check if token is available for the peer + if (os.size() == 0) + return (null); + + return (os.toByteArray()); + } + + + /** + * Called by the context acceptor upon receiving a token from + * the peer. This call is equivalent to the byte array method. + * It may write an output token to the outputBuf, which the + * application will need to send to the peer for processing + * by its init method. 0 bytes written to the output stream + * indicate that no token needs to be sent to the peer. The + * method will return either COMPLETE or CONTINUE_NEEDED + * indicating the status of the current context. A return + * value of COMPLETE indicates that the context establishment + * phase is complete for this peer, while CONTINUE_NEEDED means + * that another token is expected from the peer. The isEstablished + * method can also be used to determine this state. Note that it + * is possible to have a token for the peer while this method + * returns COMPLETE. This indicates that the local end of the + * context is established, but the token needs to be sent to + * the peer to complete the context establishment. + *

+ * The GSS-API authentication tokens contain a definitive start + * and end. This method will attempt to read one of these tokens + * per invocation, and may block on the stream if only part of the + * token is available. + *

+ * Upon completion of the context establishment, the available + * context options may be queried through the get methods. + * + *

RFC 2078 + *
equivalent to gss_accept_sec_context; context options can + * obtained through the query methods
+ * @param inputToken token that was received from the initiator + * @param outputBut token generated for the peer; may be empty + * @return creation state of either COMPLETE or CONTINUE_NEEDED + * @exception GSSException may be thrown with major status values of + * DEFECTIVE_TOKEN, DEFECTIVE_CREDENTIAL, BAD_SIG, NO_CRED, + * CREDENTIALS_EXPIRED, BAD_BINDINGS, OLD_TOKEN, DUPLICATE_ELEMENT, + * BAD_MECH, and FAILURE + * @see #accept(byte[],int,int) + * @see #init(InputStream,OutputStream) + * @see #setChannelBinding + */ + public int accept(InputStream inputBuf, OutputStream outputBuf) + throws GSSException { + + if (m_mechCtxt == null) { + + //get the mechanism oid from the inputBuf + Oid mechOid = getTokenMech(inputBuf); + m_mechCtxt = GSSManager._M4092FBA (mechOid); + if (m_myCred != null) + m_mechCtxt._S90010CC ( + m_myCred.getMechCred (mechOid, true)); + if (m_chB != null) + m_mechCtxt._S9B00AB2 (m_chB); + + m_curState = IN_PROGRESS; + } + + //debug code + if (m_curState != IN_PROGRESS) { + throw new GSSException(GSSException.FAILURE, -1, + "wrong status in accept"); + } + + int retStatus = m_mechCtxt._S80A2F2C (inputBuf, outputBuf); + if (retStatus == COMPLETE) + m_curState = READY; + + return (retStatus); + } + + + /** + * Returns true is this is a fully established context. Used after + * the init and accept methods to check if more tokens are needed + * from the peer. + * + * @return boolean indicating if this side of the context is + * fully established. + */ + public boolean isEstablished() { + + return (m_curState == READY); + } + + + /** + * Release any system resources and cryptographic information + * stored in the context object. This will invalidate the + * context. + *

RFC 2078 + *
equivalent to gss_delete_sec_context
+ * @exception GSSException with major codes NO_CONTEXT or FAILURE + */ + public void dispose() throws GSSException { + + checkState(IN_PROGRESS); + m_mechCtxt._S020B957 (); + m_curState = DELETED; + } + + + /** + * Returns the maximum message size that, if presented to the + * wrap method with the same confReq and qop parameters will + * result in an output token containing no more then maxTokenSize + * bytes. + *

RFC 2078 + *
equivalent to gss_wrap_size_limit
+ * @param qop quality of protection to apply to the message + * @param confReq boolean indicating if privacy should be applied + * @param maxTokenSize the maximum size of the token to be emitted + * from wrap + * @return maximum input buffer size for encapsulation by wrap + * using the specified QOP and confReq without exceeding + * the maxTokenSize + * @exception GSSException with the possible major codes of BAD_QOP, + * CONTEXT_EXPIRED, and FAILURE. + * @see #wrap + */ + public int getWrapSizeLimit(int qop, boolean confReq, int maxTokenSize) + throws GSSException { + + checkState(READY); + return (m_mechCtxt._S808028B (qop, confReq, maxTokenSize)); + } + + + /** + * Allows to apply per-message security services over the + * established security context. The method will return a + * token with a cryptographic MIC and may optionally encrypt + * the specified inBuf. This method is equivalent i + * functionality to its stream counterpart. The returned + * byte array will contain both the MIC and the message. + * The msgProp object is used to specify a QOP value which + * selects cryptographic algorithms, and a privacy service, + * if supported by the chosen mechanism. + *

+ * Supports the wrapping and unwrapping of zero-length messages. + *

+ * The application will be responsible for sending the token + * to the peer. + * + *

RFC 2078 + *
equivalent to gss_wrap; MessageProp object is used to + * select QOP and confidentiality
+ * @param inBuf the application data to be protected + * @param offset the offset in the inBuf where the data begins + * @param length the length of the data starting at offset + * @param msgPro indicates the desired QOP and confidentiality state, + * and upon return the actual QOP and message confidentiality state + * @return buffer to be sent to the peer for processing by unwrap + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * CREDENTIALS_EXPIRED, BAD_QOP, FAILURE. + * @see #wrap(InputStream,OutputStream, MessageProp) + * @see #unwrap(byte[],int,int,MessageProp) + * @see MessageProp + */ + public byte[] wrap(byte[] inBuf, int offset, int length, + MessageProp msgProp) throws GSSException { + +/* + * XXX EXPORT DELETE START + * + * Turn off the privacy. Once an export control liscence + * is issued, this routine can be turned back on. + * + ByteArrayInputStream is = new ByteArrayInputStream(inBuf, + offset, length); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + wrap(is, os, msgProp); + + //return output token + return (os.toByteArray()); + * XXX EXPORT DELETE END + */ + +// XXX delete this line once this routine is turned back on. + throw new GSSException(GSSException.FAILURE); + } + + + /** + * Allows to apply per-message security services over the + * established security context. The method will produce + * a token with a cryptographic MIC and may optionally + * encrypt the specified inBuf. The outBuf will contain + * both the MIC and the message. The msgProp object is + * used to specify a QOP value to select cryptographic + * algorithms, and a privacy service, if supported by the + * chosen mechanism. + *

+ * Supports the wrapping and unwrapping of zero-length messages. + *

+ * The application will be responsible for sending the token + * to the peer. + * + *

RFC 2078 + *
equivalent to gss_wrap; MessageProp object is used to + * select QOP and confidentiality
+ * @param inputBuf the application data to be protected + * @param outputBuf the token to be sent to the peer + * @param msgPro indicates the desired QOP and confidentiality state, + * and upon return the actual QOP and message confidentiality state + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * CREDENTIALS_EXPIRED, BAD_QOP, FAILURE. + * @see #wrap(byte,int,int,MessageProp) + * @see #unwrap(InputStream,OutputStream,MessageProp) + * @see MessageProp + */ + public void wrap(InputStream inBuf, OutputStream outBuf, + MessageProp msgProp) throws GSSException { + +/* + * XXX EXPORT DELETE START + * + * Turn off the privacy. Once an export control liscence + * is issued, this routine can be turned back on. + * + //clear status values + msgProp.resetStatusValues(); + + checkState(READY); + m_mechCtxt._S1309AFD (inBuf, outBuf, msgProp); + * XXX EXPORT DELETE END + */ + +// XXX delete this line once this routine is turned back on. + throw new GSSException(GSSException.FAILURE); + } + + + /** + * Used by the peer application to process tokens generated + * with the wrap call. This call is equal in functionality + * to its stream counterpart. The method will return the + * message supplied in the peer application to the wrap call, + * verifying the embedded MIC. The msgProp instance will + * indicate whether the message was encrypted and will contain + * the QOP indicating the strength of protection that was used + * to provide the confidentiality and integrity services. + *

+ * Supports the wrapping and unwrapping of zero-length messages. + * + *

RFC 2078 + *
equivalent to the gss_unwrap
+ * + * @param inBuf token received from peer application which was + * generated by call to wrap + * @param offset within the inBuf where the token begins. + * @param length The length of the token in inBuf. + * @param msgProp Upon return from the this method, will contain + * QOP and privacy state of the supplied message as well as + * any supplementary status values. + * @return the application message used in the wrap call + * @exception GSSException with possible major codes of DEFECTIVE_TOKEN, + * BAD_SIG, CONTEXT_EXPIRED, CREDENTIALS_EXPIRED, and FAILURE. + * @see #unwrap(InputStream,OutputStream,MessageProp) + * @see #wrap(byte[],int,int,MessageProp) + * @see MessageProp + */ + public byte[] unwrap(byte[] inBuf, int offset, int length, + MessageProp msgProp) throws GSSException { + +/* + * XXX EXPORT DELETE START + * + * Turn off the privacy. Once an export control liscence + * is issued, this routine can be turned back on. + * + ByteArrayInputStream is = new ByteArrayInputStream(inBuf, + offset, length); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + unwrap(is, os, msgProp); + + //return output token + if (os.size() > 0) + return (os.toByteArray()); + + return (null); + * XXX EXPORT DELETE END + */ + +// XXX delete this line once this routine is turned back on. + throw new GSSException(GSSException.FAILURE); + } + + + /** + * Used by the peer application to process tokens generated with + * the wrap call. This call is equal in functionality to its byte + * array counterpart. It will produce the message supplied in the + * peer application to the wrap call, verifying the embedded MIC. + * The msgProp parameter will indicate whether the message was + * encrypted and will contain the QOP indicating the strength + * of protection that was used to provide the confidentiality + * and integrity services. The msgProp object will also contain + * the supplementary status information for the token. + *

+ * Supports the wrapping and unwrapping of zero-length messages. + * + *

RFC 2078 + *
equivalent to the gss_unwrap
+ * + * @param inBuf token received from peer application which was + * generated by call to wrap + * @param outBuf original message passed into wrap + * @param msgProp Upon return from the this method, will contain + * QOP and privacy state of the supplied message as well as + * any supplementary status values. + * @exception GSSException with possible major codes of DEFECTIVE_TOKEN, + * BAD_SIG, CONTEXT_EXPIRED, CREDENTIALS_EXPIRED, and FAILURE. + * @see #unwrap(byte[],int,int,MessageProp) + * @see #wrap(InputStream,OutputStream,MessageProp) + * @see MessageProp + */ + public void unwrap(InputStream inBuf, OutputStream outBuf, + MessageProp msgProp) throws GSSException { + +/* + * XXX EXPORT DELETE START + * + * Turn off the privacy. Once an export control liscence + * is issued, this routine can be turned back on. + * + //clear status values + msgProp.resetStatusValues(); + + checkState(READY); + m_mechCtxt._S1576D09 (inBuf, outBuf, msgProp); + * XXX EXPORT DELETE END + */ + +// XXX delete this line once this routine is turned back on. + throw new GSSException(GSSException.FAILURE); + } + + + /** + * Returns a token containing a cryptographic MIC for the + * supplied message, for transfer to the peer application. + * Unlike wrap, which encapsulates the user message in the + * returned token, only the message MIC is returned in the + * output token. This method is identical in functionality + * to its stream counterpart. + *

+ * Note that privacy can only be applied through the wrap call. + *

+ * Supports the derivation of MICs from zero-length messages. + * + *

RFC 2078 + *
equivalent to gss_getMIC
+ * @param inBuf message to apply security service to + * @param offset The offset within the inMsg where the + * token begins. + * @param length the length of the application message + * @param msgProp Indicates the desired QOP to be used. Use QOP of 0 + * to indicate default value. The confidentiality flag + * is ignored. Upon return from this method, this object + * will contain the actual QOP applied (in case 0 was selected). + * @return token containing cryptographic information for the + * requested security service over the passed in message + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * BAD_QOP, FAILURE. + * @see #getMIC(InputStream,OutputStream,MessageProp) + * @see #verifyMIC(byte[],int,int,MessageProp) + * @see MessageProp + */ + public byte[] getMIC(byte[] inMsg, int offset, int length, + MessageProp msgProp) throws GSSException { + + ByteArrayInputStream is = new ByteArrayInputStream(inMsg, + offset, length); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + getMIC(is, os, msgProp); + + //return output token + return (os.toByteArray()); + } + + + /** + * Produces a token containing a cryptographic MIC for the + * supplied message, for transfer to the peer application. + * Unlike wrap, which encapsulates the user message in the + * returned token, only the message MIC is produced in the + * output token. This method is identical in functionality + * to its byte array counterpart. + *

+ * Note that privacy can only be applied through the wrap call. + *

+ * Supports the derivation of MICs from zero-length messages. + * + *

RFC 2078 + *
equivalent to gss_getMIC
+ * @param inBuf Buffer containing the message to generate MIC over. + * @param outBuf The buffer to write the GSS-API output token into. + * @param msgProp Indicates the desired QOP to be used. Use QOP of 0 + * to indicate default value. The confidentiality flag + * is ignored. Upon return from this method, this object + * will contain the actual QOP applied (in case 0 was selected). + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * BAD_QOP, FAILURE. + * @see #getMIC(byte[],int,int,MessageProp) + * @see #verifyMIC(byte[],int,int,byte[],int,int,MessageProp) + * @see MessageProp + */ + public void getMIC(InputStream inBuf, OutputStream outBuf, + MessageProp msgProp) throws GSSException { + + //clear status values + msgProp.resetStatusValues(); + + checkState(READY); + m_mechCtxt._S1513DBA (inBuf, outBuf, msgProp); + } + + + /** + * Verifies the cryptographic MIC, contained in the token + * parameter, over the supplied message. The msgProp parameter + * will contain the QOP indicating the strength of protection + * that was applied to the message and any supplementary status + * values for the token. This method is equivalent in + * functionality to its stream counterpart. + * + *

RFC 2078 + *
equivalent to gss_verifyMIC
+ * @param inTok token generated by peer's getMIC method + * @param tokOffset the offset within the inTok where the token begins + * @param tokLen the length of the token + * @param inMsg Application message to verify the Cryptographic MIC + * over. + * @param msgOffset the offset within the inMsg where the message + * begins + * @param msgLen the length of the message + * @param msgProp upon return from this method, this object + * will contain the applied QOP and supplementary status + * values for the supplied token. The privacy state will + * always be set to false. + * @exception GSSException with possible major codes DEFECTIVE_TOKEN, + * BAD_SIG, CONTEXT_EXPIRED + * @see #verifyMIC(InputStream,InputStream,MessageProp) + * @see #wrap(byte[],int,int,MessageProp) + * @see MessageProp + */ + public void verifyMIC(byte []inTok, int tokOffset, int tokLen, + byte[] inMsg, int msgOffset, int msgLen, + MessageProp msgProp) throws GSSException { + + ByteArrayInputStream sTok = new ByteArrayInputStream(inTok, + tokOffset, tokLen); + ByteArrayInputStream sMsg = new ByteArrayInputStream(inMsg, + msgOffset, msgLen); + verifyMIC(sTok, sMsg, msgProp); + } + + + /** + * Verifies the cryptographic MIC, contained in the token + * parameter, over the supplied message. The msgProp parameter + * will contain the QOP indicating the strength of protection + * that was applied to the message. This method is equivalent + * in functionality to its byte array counterpart. + * + *

RFC 2078 + *
equivalent to gss_verifyMIC
+ * @param inputTok Contains the token generated by peer's getMIC + * method. + * @param inputMsg Contains application message to verify the + * cryptographic MIC over. + * @param msgProp upon return from this method, this object + * will contain the applied QOP and supplementary statustatus + * values for the supplied token. The privacy state will + * always be set to false. + * @exception GSSException with possible major codes DEFECTIVE_TOKEN, + * BAD_SIG, CONTEXT_EXPIRED + * @see #verifyMIC(byte[],int,int,byte[],int,int,MessageProp) + * @see #wrap(InputStream,OutputStream) + * @see MessageProp + */ + public void verifyMIC(InputStream inTok, InputStream inMsg, + MessageProp msgProp) throws GSSException { + + //clear status values + msgProp.resetStatusValues(); + + checkState(READY); + m_mechCtxt._S00256CF (inTok, inMsg, msgProp); + } + + + /** + * Provided to support the sharing of work between multiple + * processes. This routine will typically be used by the + * context-acceptor, in an application where a single process + * receives incoming connection requests and accepts security + * contexts over them, then passes the established context to + * one or more other processes for message exchange. + *

+ * This method deactivates the security context and creates an + * interprocess token which, when passed to the byte array + * constructor of the GSSContext class in another process, + * will re-activate the context in the second process. + *

+ * Only a single instantiation of a given context may be active + * at any one time; a subsequent attempt by a context exporter + * to access the exported security context will fail. + * + *

RFC 2078 + *
equivalent to gss_export_sec_context
+ * @return inter-process token representing the context + * in export form + * @exception GSSException with possible major codes of UNAVAILABLE, + * CONTEXT_EXPIRED, NO_CONTEXT, FAILURE. + * @see GSSContext#GSSContext(byte[]) + * @see #isTransferable + */ + public byte [] export() throws GSSException { + + checkState(READY); + byte [] outTok = m_mechCtxt._S725B2DA (); + dispose(); + + return (outTok); + } + + + /** + * Sets the request state of the mutual authentication flag + * for the context. This method is only valid before the + * context creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the mutual_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if mutual authentication + * should be requested during context establishment. + * @exception GSSException may be thrown + * @see #getMutualAuthState + */ + public void requestMutualAuth(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= MUTUAL_AUTH; + else + m_reqFlags ^= MUTUAL_AUTH; + } + + + /** + * Sets the request state of the replay detection service + * for the context. This method is only valid before the + * context creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the replay_det_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if replay detection is desired + * over the established context. + * @exception GSSException may be thrown + * @see #getReplayDetState + */ + public void requestReplayDet(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= REPLAY_DET; + else + m_reqFlags ^= REPLAY_DET; + } + + + /** + * Sets the request state of the sequence checking service + * for the context. This method is only valid before the + * context creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the sequence_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if sequence checking service + * is desired over the established context. + * @exception GSSException may be thrown + * @see #getSequenceDetState + */ + public void requestSequenceDet(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= SEQUENCE_DET; + else + m_reqFlags ^= SEQUENCE_DET; + } + + + /** + * Sets the request state of the credential delegation flag + * for the context. This method is only valid before the + * context creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the deleg_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if credential delegation is desired. + * @exception GSSException may be thrown + * @see #getDelegCredState + */ + public void requestCredDeleg(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= CRED_DELEG; + else + m_reqFlags ^= CRED_DELEG; + + } + + + /** + * Requests anonymous support over the context. This method is + * only valid before the context creation process begins and + * only for the initiator. + * + *

RFC 2078 + *
equivalent to anon_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if anonymity support is desired. + * @exception GSSException may be thrown + * @see #getAnonymityState + */ + public void requestAnonymity(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= ANON; + else + m_reqFlags ^= ANON; + } + + + /** + * Requests that confidentiality service be available over + * the context. This method is only valid before the context + * creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the conf_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean indicating if confidentiality services are to + * be requested for the context. + * @exception GSSException may be thrown + * @see #getConfState + */ + public void requestConf(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= CONF; + else + m_reqFlags ^= CONF; + } + + + /** + * Requests that integrity service be available over + * the context. This method is only valid before the context + * creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the integ_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean indicating if integrity services are to + * be requested for the context. + * @exception GSSException may be thrown + * @see #getIntegState + */ + public void requestInteg(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= INTG; + else + m_reqFlags ^= INTG; + } + + + /** + * Sets the desired lifetime for the context in seconds. + * This method is only valid before the context creation + * process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the lifetime_req parameter in + * gss_init_sec_context
+ * @param The desired context lifetime in seconds. + * @exception GSSException may be thrown + * @see #getLifetime + */ + public void requestLifetime(int lifetime) throws GSSException { + + checkState(PRE_INIT); + + m_reqLifetime = lifetime; + } + + + /** + * Sets the channel bindings to be used during context + * establishment. This method is only valid before the + * context creation process begins. + * + *

RFC 2078 + *
equivalent to the chan_bindings parameter in + * gss_init_sec_context and gss_accept_sec_context
+ * @param Channel binding to be used. + * @exception GSSException may be thrown + * @see ChannelBinding + */ + public void setChannelBinding(ChannelBinding cb) throws GSSException { + + checkState(PRE_INIT); + m_chB = cb; + } + + + /** + * Returns the state of the delegated credentials for the context. + * When issued before context establishment completes or + * when the isProtReady method returns false, it returns the + * desired state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the deleg_state flag output parameter in + * gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating if delegated credentials are available + * @see #requestCredDeleg + * @see #isProtReady + */ + public boolean getDelegCredState() { + + if (m_curState < READY) + return ((m_reqFlags & CRED_DELEG) == CRED_DELEG); + + return ((m_mechCtxt._S00027C3 () & CRED_DELEG) == CRED_DELEG); + } + + + /** + * Returns the state of the mutual authentication option for + * the context. When issued before context establishment completes + * or when the isProtReady method returns false, it returns the + * desired state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the mutual_state flag output parameter + * in gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating state of mutual authentication option + * @see #requestMutualAuth + * @see #isProtReady + */ + public boolean getMutualAuthState() { + + if (m_curState < READY) + return ((m_reqFlags & MUTUAL_AUTH) == MUTUAL_AUTH); + + return ((m_mechCtxt._S00027C3 () & MUTUAL_AUTH) == MUTUAL_AUTH); + } + + + /** + * Returns the state of the replay detection service for + * the context. When issued before context establishment completes + * or when the isProtReady method returns false, it returns the + * desired state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the replay_det_state flag output + * parameter in gss_init_sec_context, gss_accept_sec_context + * and gss_inquire_context
+ * @return boolean indicating replay detection state + * @see #requestReplayDet + * @see #isProtReady + */ + public boolean getReplayDetState() { + + if (m_curState < READY) + return ((m_reqFlags & REPLAY_DET) == REPLAY_DET); + + return ((m_mechCtxt._S00027C3 () & REPLAY_DET) == REPLAY_DET); + } + + + /** + * Returns the state of the sequence detection service for + * the context. When issued before context establishment completes + * or when the isProtReady method returns false, it returns the + * desired state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the sequence_state flag output parameter + * in gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating sequence detection state + * @see #requestSequenceDet + * @see #isProtReady + */ + public boolean getSequenceDetState() { + + if (m_curState < READY) + return ((m_reqFlags & SEQUENCE_DET) == SEQUENCE_DET); + + return ((m_mechCtxt._S00027C3 () & SEQUENCE_DET) == SEQUENCE_DET); + } + + + /** + * Returns true if this is an anonymous context. When issued + * before context establishment completes or when the + * isProtReady method returns false, it returns the desired + * state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the anon_state flag output parameter in + * gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating anonymity state + * @see #requestAnonymity + * @see #isProtReady + */ + public boolean getAnonymityState() { + + if (m_curState < READY) + return ((m_reqFlags & ANON) == ANON); + + return ((m_mechCtxt._S00027C3 () & ANON) == ANON); + } + + + /** + * Indicates if the context is transferable to other processes + * through the use of the export method. This call is only valid + * on fully established contexts. + * + *

RFC 2078 + *
equivalent to the trans_state flag output parameter in + * gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating the transferability of the context + * @exception GSSException may be thrown + * @see #export + */ + public boolean isTransferable() throws GSSException { + + checkState(READY); + return ((m_mechCtxt._S00027C3 () & TRANS) == TRANS); + } + + + /** + * Indicates if the per message operations can be applied over + * the context. Some mechanisms may allow to apply per-message + * operations before the context is fully established. This will + * also indicate that the get methods will return actual context + * state characteristics instead of the desired ones. + * + *

RFC 2078 + *
equivalent to the prot_ready_state flag output + * parameter in gss_init_sec_context and + * gss_accept_sec_context
+ * @return boolean indicating if per message operations are available + */ + public boolean isProtReady() { + + if (m_mechCtxt == null) + return false; + + return (m_mechCtxt._S1116FAA ()); + } + + + /** + * Returns the confidentiality service state over the context. + * When issued before context establishment completes or when + * the isProtReady method returns false, it returns the desired + * state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the conf_avail flag output parameter + * in gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating confidentiality state + * @see #requestConf + * @see #isProtReady + */ + public boolean getConfState() { + + if (m_curState < READY) + return ((m_reqFlags & CONF) == CONF); + + return ((m_mechCtxt._S00027C3 () & CONF) == CONF); + } + + + /** + * Returns the integrity service state over the context. + * When issued before context establishment completes or when + * the isProtReady method returns false, it returns the desired + * state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the integ_avail flag output parameter + * in gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating integrity state + * @see #requestInteg + * @see #isProtReady + */ + public boolean getIntegState() { + + if (m_curState < READY) + return ((m_reqFlags & INTG) == INTG); + + return ((m_mechCtxt._S00027C3 () & INTG) == INTG); + } + + + /** + * Returns the context lifetime in seconds. + * When issued before context establishment completes or when + * the isProtReady method returns false, it returns the desired + * lifetime, otherwise it will indicate the actual lifetime over + * the established context. + * + *

RFC 2078 + *
equivalent to the lifetime_rec output parameter in + * gss_init_sec_context, gss_accept_sec_context, + * gss_inquire_context and to gss_context_time call
+ * @return lifetime in seconds + * @see #requestLifetime + * @see #isProtReady + */ + public int getLifetime() { + + if (m_curState < READY) + return (m_reqLifetime); + + return (m_mechCtxt._S4080EED ()); + } + + + /** + * Retrieves the name of the context initiator. + * This call is valid only after context has been fully established + * or when the isProtReady methods returns true. + * + *

RFC 2078 + *
equivalent to the src_name parameter in + * gss_accept_sec_context and gss_inquire_context
+ * @return name of the context initiator + * @exception GSSException with possible major codes of CONTEXT_EXPIRED + * and FAILURE + * @see #isProtReady + */ + public GSSName getSrcName() throws GSSException { + + checkState(IN_PROGRESS); + return (new GSSName(m_mechCtxt._S000EEFF ())); + } + + + /** + * Retrieves the name of the context target (acceptor). + * This call is only valid on fully established contexts + * or when the isProtReady methods returns true. + * + *

RFC 2078 + *
equivalent to the targ_name parameter in + * gss_inquire_context
+ * @return name of the context target (acceptor) + * @exception GSSException with possible major codes of + * CONTEXT_EXPIRED and FAILURE + * @see #isProtReady + */ + public GSSName getTargName() throws GSSException { + + checkState(IN_PROGRESS); + return (new GSSName(m_mechCtxt._S011CEF9 ())); + } + + + /** + * Returns the mechanism oid for the context. + * + *

RFC 2078 + *
equivalent to the mech_type parameter in + * gss_accept_sec_context and gss_inquire_context
+ * @return Oid object for the context's mechanism + * @exception GSSException may be thrown when the mechanism + * oid can't be determined + * + */ + public Oid getMech() throws GSSException { + + checkState(IN_PROGRESS); + return (m_mechCtxt._S0200735 ()); + } + + + /** + * Returns the delegated credential object on the acceptor's side. + * To check for availability of delegated credentials call + * getDelegCredState. This call is only valid on fully established + * contexts. + * + *

RFC 2078 + *
equivalent to delegated_cred_handle parameter + * in gss_accept_sec_context
+ * @return delegated credential object for the context + * @exception GSSException with possible major codes of + * CONTEXT_EXPIRED and FAILURE + * @see #getDelegCredState + */ + public GSSCredential getDelegCred() throws GSSException { + + checkState(IN_PROGRESS); + return (new GSSCredential(m_mechCtxt._S0293FFA ())); + } + + + /** + * Returns true if this is the initiator of the context. + * This call is only valid after the context creation process + * has started. + * + *

RFC 2078 + *
equivalent to locally_initiated output parameter + * in gss_inquire_context
+ * @return true if this is the context initiator + * @exception GSSException with possible major codes of + * CONTEXT_EXPIRED and FAILURE + */ + public boolean isInitiator() throws GSSException { + + checkState(IN_PROGRESS); + return (m_mechCtxt._S123049E ()); + } + + + /** + * Ensures the object is in the required state. + * + * @param minimumState the minimum required state. + * @exception GSSException is thrown when the state is incorrect. + */ + private void checkState(int minimumState) throws GSSException { + + if (m_curState < minimumState) + throw new GSSException(GSSException.NO_CONTEXT); + + //this is just temporary for debugging + if (minimumState > PRE_INIT && m_mechCtxt == null) + throw new GSSException(GSSException.NO_CONTEXT, -1, + "error in checkState"); + } + + + /** + * Private initializer of context variables + */ + private void initialize() { + + m_reqFlags = MUTUAL_AUTH | SEQUENCE_DET | REPLAY_DET; + m_myCred = null; + m_reqLifetime = INDEFINITE; + m_curState = PRE_INIT; + m_mechOid = null; + m_targName = null; + m_chB = null; + } + + + /** + * Reads the token header as defined in RFC 2078 and + * returns the mechanism oid. Currently this requires that + * the stream support mark/reset operations. As an + * alternative we can strip this header, and pass the information + * into the mechanism. + */ + private Oid getTokenMech(InputStream is) throws GSSException { + + try { + is.mark(100); + + if (is.read() != 0x60) + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + + //we can skip the token length + DERParser.readLength(is); + + //next we have the full der encoding of the oid + Oid res = new Oid(is); + is.reset(); + + return (res); + } catch (IOException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + + } + + + //private flags for the context state + private static final int PRE_INIT = 1; + private static final int IN_PROGRESS = 2; + private static final int READY = 3; + private static final int DELETED = 4; + + + //instance variables + private C018FE95 m_mechCtxt; + private int m_reqFlags; + private GSSCredential m_myCred; + private int m_reqLifetime; + private int m_curState; + private Oid m_mechOid; + private GSSName m_targName; + private ChannelBinding m_chB; +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSContext.m4 b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSContext.m4 new file mode 100644 index 0000000000..bc48c7a0d2 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSContext.m4 @@ -0,0 +1,1591 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + + +/** + * This class represents the JGSS security context and its associated + * operations. JGSS security contexts are established between + * peers using locally established credentials. Multiple contexts + * may exist simultaneously between a pair of peers, using the same + * or different set of credentials. The JGSS is independent of + * the underlying transport protocols and depends on its callers to + * transport the tokens between peers. + *

+ * The context object can be thought of as having 3 implicit states: + * before it is established, during its context establishment, and + * after a fully established context exists. + *

+ * Before the context establishment phase is initiated, the context + * initiator may request specific characteristics desired of the + * established context. These can be set using the set methods. After the + * context is established, the caller can check the actual characteristic + * and services offered by the context using the query methods. + *

+ * The context establishment phase begins with the first call to the init + * method by the context initiator. During this phase the init and accept + * methods will produce GSS-API authentication tokens which the calling + * application needs to send to its peer. The init and accept methods may + * return a CONTINUE_NEEDED code which indicates that a token is needed + * from its peer in order to continue the context establishment phase. A + * return code of COMPLETE signals that the local end of the context is + * established. This may still require that a token be sent to the peer, + * depending if one is produced by GSS-API. The isEstablished method can + * also be used to determine if the local end of the context has been + * fully established. During the context establishment phase, the + * isProtReady method may be called to determine if the context can be + * used for the per-message operations. This allows implementation to + * use per-message operations on contexts which aren't fully established. + *

+ * After the context has been established or the isProtReady method + * returns "true", the query routines can be invoked to determine the actual + * characteristics and services of the established context. The + * application can also start using the per-message methods of wrap and + * getMIC to obtain cryptographic operations on application supplied data. + *

+ * When the context is no longer needed, the application should call + * dispose to release any system resources the context may be using. + *

RFC 2078 + *
This class corresponds to the context level calls together with + * the per message calls of RFC 2078. The gss_init_sec_context and + * gss_accept_sec_context calls have been made simpler by only taking + * required parameters. The context can have its properties set before + * the first call to init. The supplementary status codes for the per-message + * operations are returned in an instance of the MessageProp class, which is + * used as an argument in these calls.
+ */ +public class GSSContext { + + /** + * Indefinite lifetime value for a context. Set to the + * largest value for an int in Java. + * @see #getLifetime + */ + public static final int INDEFINITE = Integer.MAX_VALUE; + + /** + * Return value from either accept or init stating that + * the context creation phase is complete for this peer. + * @see #init + * @see #accept + */ + public static final int COMPLETE = 0; + + /** + * Return value from either accept or init stating that + * another token is required from the peer to continue context + * creation. This may be returned several times indicating + * multiple token exchanges. + * @see #init + * @see #accept + */ + public static final int CONTINUE_NEEDED = 1; + + /** + * Context option flag - credential delegation. + */ + public static final int CRED_DELEG = 0x1; + + /** + * Context option flag - mutual authentication. + */ + public static final int MUTUAL_AUTH = 0x02; + + /** + * Context option flag - replay detection. + */ + public static final int REPLAY_DET = 0x04; + + /** + * Context option flag - sequence detection. + */ + public static final int SEQUENCE_DET = 0x08; + + /** + * Context option flag - anonymity. + */ + public static final int ANON = 0x10; + + /** + * Context option flag - confidentiality. + */ + public static final int CONF = 0x20; + + /** + * Context option flag - integrity. + */ + public static final int INTG = 0x40; + + /** + * Context option flag - transferability (output flag only). + * Indicates if context may be transferred by using export(). + * @see #export + */ + public static final int TRANS = 0x80; + + + /** + * Constructor for creating a context on the initiator's side. + * Context flags may be modified through the set methods prior + * to calling init(). + * + * @param peer Name of the target peer. + * @param mechOid Oid of the desired mechanism; + * may be null to indicate the default mechanism + * @param myCred the credentials for the initiator; may be + * null to indicate desire to use the default credentials + * @param lifetime the request lifetime, in seconds, for the context + * @exception GSSException with possible major codes of BAD_NAME, + * BAD_MECH, BAD_NAMETYPE. + * @see #init + */ + public GSSContext(GSSName peer, Oid mechOid, GSSCredential myCred, int + lifetime) throws GSSException { + + initialize(); + + m_myCred = myCred; + m_reqLifetime = lifetime; + m_targName = peer; + + if (mechOid == null) + m_mechOid = GSSManager.getDefaultMech(); + else + m_mechOid = mechOid; + } + + + /** + * Constructor for creating a context on the acceptor' side. The + * context's properties will be determined from the input token + * supplied to accept(). + * + * @param myCred GSSCredential for the acceptor. Use null to + * request usage of default credentials. + * @exception GSSException with possible major codes of BAD_NAME, + * BAD_MECH, BAD_NAMETYPE. + * @see #accept + */ + public GSSContext(GSSCredential myCred) throws GSSException { + + initialize(); + m_myCred = myCred; + } + + + /** + * Constructor for creating a GSSContext from a previously + * exported context. The context properties will be determined + * from the input token. + *

RFC 2078 + *
equivalent to gss_import_sec_context
+ * @param interProcessToken the token emitted from export routine + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * NO_CONTEXT, DEFECTIVE_TOKEN, UNAVAILABLE, UNAUTHORIZED, FAILURE + * @see #export + */ + public GSSContext(byte [] interProcessToken) throws GSSException { + + initialize(); + + /* + * Strip the mechanism oid from the token + * + * the token encoding is implementation specific, and + * we start by having 4 bytes of length, followed by the + * mechanism oid of the specified length, followed by the + * mechanism part of the token. This is the same as our C + * version. + */ + try { + int length = (interProcessToken[0] & 0xff); + for (int i = 1; i < 4; i++) { + length <<= 8; + length += (interProcessToken[i] & 0xff); + } + + ByteArrayInputStream is = + new ByteArrayInputStream(interProcessToken); + + //ask mechanism to import this context + m_mechCtxt = GSSManager.getCtxtInstance ( + Oid.getFromDEROctets(is, length)); + m_mechCtxt._importSecCtxt (interProcessToken); + m_curState = READY; + + } catch (ArrayIndexOutOfBoundsException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + } + + + /** + * Called by the context initiator to start the context creation + * process. This is equivalent to the stream based method except + * that the token buffers are handled as byte arrays instead of + * using stream objects. This method may return an output token + * which the application will need to send to the peer for + * processing by the accept call. "null" return value indicates + * that no token needs to be sent to the peer. The application + * can call isEstablished to determine if the context + * establishment phase is complete for this peer. A return value + * of "false" from isEstablished indicates that more tokens are + * expected to be supplied to the init method. Please note that + * the init method may return a token for the peer, and + * isEstablished return "true" also. This indicates that the token + * needs to be sent to the peer, but the local end of the context + * is now fully established. + *

+ * Upon completion of the context establishment, the available + * context options may be queried through the get methods. + *

RFC 2078 + *
equivalent to gss_init_sec_context; The requested context + * options can be set before the first call, and the available + * options can be obtained after the context is fully established. + *
+ * @param inputBuf token generated by the peer; this parameter is + * ignored on the first call + * @param outputBuf token generated for the peer; this may be empty + * @return establishment state of either COMPLETE or CONTINUE_NEEDED + * @exception GSSException with possible major values of DEFECTIVE_TOKEN, + * DEFECTIVE_CREDENTIAL, BAD_SIG, NO_CRED, CREDENTIALS_EXPIRED, + * BAD_BINDINGS, OLD_TOKEN, DUPLICATE_ELEMENT, BAD_NAMETYPE, BAD_NAME, + * BAD_MECH, and FAILURE + * @see #init(InputStream,OutputStream) + * @see #setChannelBinding + */ + public byte[] init(byte []inputBuf, int offset, int length) + throws GSSException { + + ByteArrayInputStream is = null; + + if (inputBuf != null) + is = new ByteArrayInputStream(inputBuf, offset, length); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + init(is, os); + if (os.size() == 0) + return (null); + + return (os.toByteArray()); + } + + + /** + * Called by the context initiator to start the context creation + * process. This is equivalent to the byte array based method. + * This method may write an output token to the outputBuf, which + * the application will need to send to the peer for processing + * by the accept call. 0 bytes written to the output stream + * indicate that no token needs to be sent to the peer. The + * method will return either COMPLETE or CONTINUE_NEEDED + * indicating the status of the current context. A return value + * of COMPLETE indicates that the context establishment phase is + * complete for this peer, while CONTINUE_NEEDED means that + * another token is expected from the peer. The isEstablished + * method can also be used to determine this state. Note that + * it is possible to have a token for the peer while this method + * returns COMPLETE. This indicates that the local end of the + * context is established, but the token needs to be sent to + * the peer to complete the context establishment. + *

+ * The GSS-API authentication tokens contain a definitive + * start and end. This method will attempt to read one of these + * tokens per invocation, and may block on the stream if only + * part of the token is available. + *

+ * Upon completion of the context establishment, the available + * context options may be queried through the get methods. + *

RFC 2078 + *
equivalent to gss_init_sec_context; The requested context + * options can be set before the first call, and the available + * options can be obtained after the context is fully established. + *
+ * @param inputBuf token generated by the peer; this parameter is + * ignored on the first call + * @param outputBuf token generated for the peer; this may be empty + * @return establishment state of either COMPLETE or CONTINUE_NEEDED + * @exception GSSException with possible major values of DEFECTIVE_TOKEN, + * DEFECTIVE_CREDENTIAL, BAD_SIG, NO_CRED, CREDENTIALS_EXPIRED, + * BAD_BINDINGS, OLD_TOKEN, DUPLICATE_ELEMENT, BAD_NAMETYPE, BAD_NAME, + * BAD_MECH, and FAILURE + * @see #init(byte[],int,int) + * @see #accept(byte[],int,int) + * @see #setChannelBinding + */ + public int init(InputStream inputBuf, OutputStream outputBuf) + throws GSSException { + + if (m_mechCtxt == null) { + m_mechCtxt = GSSManager.getCtxtInstance (m_mechOid); + GSSCredSpi mechCred = null; + if (m_myCred != null) + mechCred = m_myCred.getMechCred(m_mechOid, true); + + m_mechCtxt._setInitOptions (mechCred, + m_targName.canonicalizeInPlace(m_mechOid), + m_reqLifetime, m_reqFlags); + + if (m_chB != null) + m_mechCtxt._setChannelBinding (m_chB); + + m_curState = IN_PROGRESS; + } + + //debug code + if (m_curState != IN_PROGRESS) { + throw new GSSException(GSSException.FAILURE, -1, + "wrong status in init"); + } + + int retStatus = m_mechCtxt._initSecCtxt (inputBuf, outputBuf); + if (retStatus == COMPLETE) + m_curState = READY; + + return (retStatus); + } + + + /** + * Called by the context acceptor upon receiving a token from + * the peer. This call is equivalent to the stream based method + * except that the token buffers are handled as byte arrays + * instead of using stream objects. + *

+ * This method may return an output token which the application + * will need to send to the peer for further processing by the + * init call. "null" return value indicates that no token needs + * to be sent to the peer. The application can call isEstablished + * to determine if the context establishment phase is complete + * for this peer. A return value of "false" from isEstablished + * indicates that more tokens are expected to be supplied to this + * method. + *

+ * Please note that the accept method may return a token for the + * peer, and isEstablished return "true" also. This indicates that + * the token needs to be sent to the peer, but the local end of the + * context is now fully established. + *

+ * Upon completion of the context establishment, the available + * context options may be queried through the get methods. + * Called by the context acceptor upon receiving a token from + * the peer. May need to be called again if returns CONTINUE_NEEDED. + * + *

RFC 2078 + *
equivalent to gss_accept_sec_context; context options can + * obtained through the query methods + *
+ * @param inputToken token that was received from the initiator + * @param outputBut token generated for the peer; may be empty + * @return creation state of either COMPLETE or CONTINUE_NEEDED + * @exception GSSException may be thrown with major status values of + * DEFECTIVE_TOKEN, DEFECTIVE_CREDENTIAL, BAD_SIG, NO_CRED, + * CREDENTIALS_EXPIRED, BAD_BINDINGS, OLD_TOKEN, DUPLICATE_ELEMENT, + * BAD_MECH, and FAILURE + * @see #init(byte[],int,int) + * @see #accept(InputStream,OutputStream) + * @see #setChannelBinding + */ + public byte[] accept(byte[] inTok, int offset, int length) + throws GSSException { + + ByteArrayInputStream is = new ByteArrayInputStream(inTok, + offset, length); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + accept(is, os); + + //check if token is available for the peer + if (os.size() == 0) + return (null); + + return (os.toByteArray()); + } + + + /** + * Called by the context acceptor upon receiving a token from + * the peer. This call is equivalent to the byte array method. + * It may write an output token to the outputBuf, which the + * application will need to send to the peer for processing + * by its init method. 0 bytes written to the output stream + * indicate that no token needs to be sent to the peer. The + * method will return either COMPLETE or CONTINUE_NEEDED + * indicating the status of the current context. A return + * value of COMPLETE indicates that the context establishment + * phase is complete for this peer, while CONTINUE_NEEDED means + * that another token is expected from the peer. The isEstablished + * method can also be used to determine this state. Note that it + * is possible to have a token for the peer while this method + * returns COMPLETE. This indicates that the local end of the + * context is established, but the token needs to be sent to + * the peer to complete the context establishment. + *

+ * The GSS-API authentication tokens contain a definitive start + * and end. This method will attempt to read one of these tokens + * per invocation, and may block on the stream if only part of the + * token is available. + *

+ * Upon completion of the context establishment, the available + * context options may be queried through the get methods. + * + *

RFC 2078 + *
equivalent to gss_accept_sec_context; context options can + * obtained through the query methods
+ * @param inputToken token that was received from the initiator + * @param outputBut token generated for the peer; may be empty + * @return creation state of either COMPLETE or CONTINUE_NEEDED + * @exception GSSException may be thrown with major status values of + * DEFECTIVE_TOKEN, DEFECTIVE_CREDENTIAL, BAD_SIG, NO_CRED, + * CREDENTIALS_EXPIRED, BAD_BINDINGS, OLD_TOKEN, DUPLICATE_ELEMENT, + * BAD_MECH, and FAILURE + * @see #accept(byte[],int,int) + * @see #init(InputStream,OutputStream) + * @see #setChannelBinding + */ + public int accept(InputStream inputBuf, OutputStream outputBuf) + throws GSSException { + + if (m_mechCtxt == null) { + + //get the mechanism oid from the inputBuf + Oid mechOid = getTokenMech(inputBuf); + m_mechCtxt = GSSManager.getCtxtInstance (mechOid); + if (m_myCred != null) + m_mechCtxt._setAcceptOptions ( + m_myCred.getMechCred (mechOid, true)); + if (m_chB != null) + m_mechCtxt._setChannelBinding (m_chB); + + m_curState = IN_PROGRESS; + } + + //debug code + if (m_curState != IN_PROGRESS) { + throw new GSSException(GSSException.FAILURE, -1, + "wrong status in accept"); + } + + int retStatus = m_mechCtxt._acceptSecCtxt (inputBuf, outputBuf); + if (retStatus == COMPLETE) + m_curState = READY; + + return (retStatus); + } + + + /** + * Returns true is this is a fully established context. Used after + * the init and accept methods to check if more tokens are needed + * from the peer. + * + * @return boolean indicating if this side of the context is + * fully established. + */ + public boolean isEstablished() { + + return (m_curState == READY); + } + + + /** + * Release any system resources and cryptographic information + * stored in the context object. This will invalidate the + * context. + *

RFC 2078 + *
equivalent to gss_delete_sec_context
+ * @exception GSSException with major codes NO_CONTEXT or FAILURE + */ + public void dispose() throws GSSException { + + checkState(IN_PROGRESS); + m_mechCtxt._dispose (); + m_curState = DELETED; + } + + + /** + * Returns the maximum message size that, if presented to the + * wrap method with the same confReq and qop parameters will + * result in an output token containing no more then maxTokenSize + * bytes. + *

RFC 2078 + *
equivalent to gss_wrap_size_limit
+ * @param qop quality of protection to apply to the message + * @param confReq boolean indicating if privacy should be applied + * @param maxTokenSize the maximum size of the token to be emitted + * from wrap + * @return maximum input buffer size for encapsulation by wrap + * using the specified QOP and confReq without exceeding + * the maxTokenSize + * @exception GSSException with the possible major codes of BAD_QOP, + * CONTEXT_EXPIRED, and FAILURE. + * @see #wrap + */ + public int getWrapSizeLimit(int qop, boolean confReq, int maxTokenSize) + throws GSSException { + + checkState(READY); + return (m_mechCtxt._getWrapSizeLimit (qop, confReq, maxTokenSize)); + } + + + /** + * Allows to apply per-message security services over the + * established security context. The method will return a + * token with a cryptographic MIC and may optionally encrypt + * the specified inBuf. This method is equivalent i + * functionality to its stream counterpart. The returned + * byte array will contain both the MIC and the message. + * The msgProp object is used to specify a QOP value which + * selects cryptographic algorithms, and a privacy service, + * if supported by the chosen mechanism. + *

+ * Supports the wrapping and unwrapping of zero-length messages. + *

+ * The application will be responsible for sending the token + * to the peer. + * + *

RFC 2078 + *
equivalent to gss_wrap; MessageProp object is used to + * select QOP and confidentiality
+ * @param inBuf the application data to be protected + * @param offset the offset in the inBuf where the data begins + * @param length the length of the data starting at offset + * @param msgPro indicates the desired QOP and confidentiality state, + * and upon return the actual QOP and message confidentiality state + * @return buffer to be sent to the peer for processing by unwrap + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * CREDENTIALS_EXPIRED, BAD_QOP, FAILURE. + * @see #wrap(InputStream,OutputStream, MessageProp) + * @see #unwrap(byte[],int,int,MessageProp) + * @see MessageProp + */ + public byte[] wrap(byte[] inBuf, int offset, int length, + MessageProp msgProp) throws GSSException { + +/* + * XXX EXPORT DELETE START + * + * Turn off the privacy. Once an export control liscence + * is issued, this routine can be turned back on. + * + ByteArrayInputStream is = new ByteArrayInputStream(inBuf, + offset, length); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + wrap(is, os, msgProp); + + //return output token + return (os.toByteArray()); + * XXX EXPORT DELETE END + */ + +// XXX delete this line once this routine is turned back on. + throw new GSSException(GSSException.FAILURE); + } + + + /** + * Allows to apply per-message security services over the + * established security context. The method will produce + * a token with a cryptographic MIC and may optionally + * encrypt the specified inBuf. The outBuf will contain + * both the MIC and the message. The msgProp object is + * used to specify a QOP value to select cryptographic + * algorithms, and a privacy service, if supported by the + * chosen mechanism. + *

+ * Supports the wrapping and unwrapping of zero-length messages. + *

+ * The application will be responsible for sending the token + * to the peer. + * + *

RFC 2078 + *
equivalent to gss_wrap; MessageProp object is used to + * select QOP and confidentiality
+ * @param inputBuf the application data to be protected + * @param outputBuf the token to be sent to the peer + * @param msgPro indicates the desired QOP and confidentiality state, + * and upon return the actual QOP and message confidentiality state + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * CREDENTIALS_EXPIRED, BAD_QOP, FAILURE. + * @see #wrap(byte,int,int,MessageProp) + * @see #unwrap(InputStream,OutputStream,MessageProp) + * @see MessageProp + */ + public void wrap(InputStream inBuf, OutputStream outBuf, + MessageProp msgProp) throws GSSException { + +/* + * XXX EXPORT DELETE START + * + * Turn off the privacy. Once an export control liscence + * is issued, this routine can be turned back on. + * + //clear status values + msgProp.resetStatusValues(); + + checkState(READY); + m_mechCtxt._wrap (inBuf, outBuf, msgProp); + * XXX EXPORT DELETE END + */ + +// XXX delete this line once this routine is turned back on. + throw new GSSException(GSSException.FAILURE); + } + + + /** + * Used by the peer application to process tokens generated + * with the wrap call. This call is equal in functionality + * to its stream counterpart. The method will return the + * message supplied in the peer application to the wrap call, + * verifying the embedded MIC. The msgProp instance will + * indicate whether the message was encrypted and will contain + * the QOP indicating the strength of protection that was used + * to provide the confidentiality and integrity services. + *

+ * Supports the wrapping and unwrapping of zero-length messages. + * + *

RFC 2078 + *
equivalent to the gss_unwrap
+ * + * @param inBuf token received from peer application which was + * generated by call to wrap + * @param offset within the inBuf where the token begins. + * @param length The length of the token in inBuf. + * @param msgProp Upon return from the this method, will contain + * QOP and privacy state of the supplied message as well as + * any supplementary status values. + * @return the application message used in the wrap call + * @exception GSSException with possible major codes of DEFECTIVE_TOKEN, + * BAD_SIG, CONTEXT_EXPIRED, CREDENTIALS_EXPIRED, and FAILURE. + * @see #unwrap(InputStream,OutputStream,MessageProp) + * @see #wrap(byte[],int,int,MessageProp) + * @see MessageProp + */ + public byte[] unwrap(byte[] inBuf, int offset, int length, + MessageProp msgProp) throws GSSException { + +/* + * XXX EXPORT DELETE START + * + * Turn off the privacy. Once an export control liscence + * is issued, this routine can be turned back on. + * + ByteArrayInputStream is = new ByteArrayInputStream(inBuf, + offset, length); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + unwrap(is, os, msgProp); + + //return output token + if (os.size() > 0) + return (os.toByteArray()); + + return (null); + * XXX EXPORT DELETE END + */ + +// XXX delete this line once this routine is turned back on. + throw new GSSException(GSSException.FAILURE); + } + + + /** + * Used by the peer application to process tokens generated with + * the wrap call. This call is equal in functionality to its byte + * array counterpart. It will produce the message supplied in the + * peer application to the wrap call, verifying the embedded MIC. + * The msgProp parameter will indicate whether the message was + * encrypted and will contain the QOP indicating the strength + * of protection that was used to provide the confidentiality + * and integrity services. The msgProp object will also contain + * the supplementary status information for the token. + *

+ * Supports the wrapping and unwrapping of zero-length messages. + * + *

RFC 2078 + *
equivalent to the gss_unwrap
+ * + * @param inBuf token received from peer application which was + * generated by call to wrap + * @param outBuf original message passed into wrap + * @param msgProp Upon return from the this method, will contain + * QOP and privacy state of the supplied message as well as + * any supplementary status values. + * @exception GSSException with possible major codes of DEFECTIVE_TOKEN, + * BAD_SIG, CONTEXT_EXPIRED, CREDENTIALS_EXPIRED, and FAILURE. + * @see #unwrap(byte[],int,int,MessageProp) + * @see #wrap(InputStream,OutputStream,MessageProp) + * @see MessageProp + */ + public void unwrap(InputStream inBuf, OutputStream outBuf, + MessageProp msgProp) throws GSSException { + +/* + * XXX EXPORT DELETE START + * + * Turn off the privacy. Once an export control liscence + * is issued, this routine can be turned back on. + * + //clear status values + msgProp.resetStatusValues(); + + checkState(READY); + m_mechCtxt._unwrap (inBuf, outBuf, msgProp); + * XXX EXPORT DELETE END + */ + +// XXX delete this line once this routine is turned back on. + throw new GSSException(GSSException.FAILURE); + } + + + /** + * Returns a token containing a cryptographic MIC for the + * supplied message, for transfer to the peer application. + * Unlike wrap, which encapsulates the user message in the + * returned token, only the message MIC is returned in the + * output token. This method is identical in functionality + * to its stream counterpart. + *

+ * Note that privacy can only be applied through the wrap call. + *

+ * Supports the derivation of MICs from zero-length messages. + * + *

RFC 2078 + *
equivalent to gss_getMIC
+ * @param inBuf message to apply security service to + * @param offset The offset within the inMsg where the + * token begins. + * @param length the length of the application message + * @param msgProp Indicates the desired QOP to be used. Use QOP of 0 + * to indicate default value. The confidentiality flag + * is ignored. Upon return from this method, this object + * will contain the actual QOP applied (in case 0 was selected). + * @return token containing cryptographic information for the + * requested security service over the passed in message + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * BAD_QOP, FAILURE. + * @see #getMIC(InputStream,OutputStream,MessageProp) + * @see #verifyMIC(byte[],int,int,MessageProp) + * @see MessageProp + */ + public byte[] getMIC(byte[] inMsg, int offset, int length, + MessageProp msgProp) throws GSSException { + + ByteArrayInputStream is = new ByteArrayInputStream(inMsg, + offset, length); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + getMIC(is, os, msgProp); + + //return output token + return (os.toByteArray()); + } + + + /** + * Produces a token containing a cryptographic MIC for the + * supplied message, for transfer to the peer application. + * Unlike wrap, which encapsulates the user message in the + * returned token, only the message MIC is produced in the + * output token. This method is identical in functionality + * to its byte array counterpart. + *

+ * Note that privacy can only be applied through the wrap call. + *

+ * Supports the derivation of MICs from zero-length messages. + * + *

RFC 2078 + *
equivalent to gss_getMIC
+ * @param inBuf Buffer containing the message to generate MIC over. + * @param outBuf The buffer to write the GSS-API output token into. + * @param msgProp Indicates the desired QOP to be used. Use QOP of 0 + * to indicate default value. The confidentiality flag + * is ignored. Upon return from this method, this object + * will contain the actual QOP applied (in case 0 was selected). + * @exception GSSException with possible major codes of CONTEXT_EXPIRED, + * BAD_QOP, FAILURE. + * @see #getMIC(byte[],int,int,MessageProp) + * @see #verifyMIC(byte[],int,int,byte[],int,int,MessageProp) + * @see MessageProp + */ + public void getMIC(InputStream inBuf, OutputStream outBuf, + MessageProp msgProp) throws GSSException { + + //clear status values + msgProp.resetStatusValues(); + + checkState(READY); + m_mechCtxt._getMIC (inBuf, outBuf, msgProp); + } + + + /** + * Verifies the cryptographic MIC, contained in the token + * parameter, over the supplied message. The msgProp parameter + * will contain the QOP indicating the strength of protection + * that was applied to the message and any supplementary status + * values for the token. This method is equivalent in + * functionality to its stream counterpart. + * + *

RFC 2078 + *
equivalent to gss_verifyMIC
+ * @param inTok token generated by peer's getMIC method + * @param tokOffset the offset within the inTok where the token begins + * @param tokLen the length of the token + * @param inMsg Application message to verify the Cryptographic MIC + * over. + * @param msgOffset the offset within the inMsg where the message + * begins + * @param msgLen the length of the message + * @param msgProp upon return from this method, this object + * will contain the applied QOP and supplementary status + * values for the supplied token. The privacy state will + * always be set to false. + * @exception GSSException with possible major codes DEFECTIVE_TOKEN, + * BAD_SIG, CONTEXT_EXPIRED + * @see #verifyMIC(InputStream,InputStream,MessageProp) + * @see #wrap(byte[],int,int,MessageProp) + * @see MessageProp + */ + public void verifyMIC(byte []inTok, int tokOffset, int tokLen, + byte[] inMsg, int msgOffset, int msgLen, + MessageProp msgProp) throws GSSException { + + ByteArrayInputStream sTok = new ByteArrayInputStream(inTok, + tokOffset, tokLen); + ByteArrayInputStream sMsg = new ByteArrayInputStream(inMsg, + msgOffset, msgLen); + verifyMIC(sTok, sMsg, msgProp); + } + + + /** + * Verifies the cryptographic MIC, contained in the token + * parameter, over the supplied message. The msgProp parameter + * will contain the QOP indicating the strength of protection + * that was applied to the message. This method is equivalent + * in functionality to its byte array counterpart. + * + *

RFC 2078 + *
equivalent to gss_verifyMIC
+ * @param inputTok Contains the token generated by peer's getMIC + * method. + * @param inputMsg Contains application message to verify the + * cryptographic MIC over. + * @param msgProp upon return from this method, this object + * will contain the applied QOP and supplementary statustatus + * values for the supplied token. The privacy state will + * always be set to false. + * @exception GSSException with possible major codes DEFECTIVE_TOKEN, + * BAD_SIG, CONTEXT_EXPIRED + * @see #verifyMIC(byte[],int,int,byte[],int,int,MessageProp) + * @see #wrap(InputStream,OutputStream) + * @see MessageProp + */ + public void verifyMIC(InputStream inTok, InputStream inMsg, + MessageProp msgProp) throws GSSException { + + //clear status values + msgProp.resetStatusValues(); + + checkState(READY); + m_mechCtxt._verifyMIC (inTok, inMsg, msgProp); + } + + + /** + * Provided to support the sharing of work between multiple + * processes. This routine will typically be used by the + * context-acceptor, in an application where a single process + * receives incoming connection requests and accepts security + * contexts over them, then passes the established context to + * one or more other processes for message exchange. + *

+ * This method deactivates the security context and creates an + * interprocess token which, when passed to the byte array + * constructor of the GSSContext class in another process, + * will re-activate the context in the second process. + *

+ * Only a single instantiation of a given context may be active + * at any one time; a subsequent attempt by a context exporter + * to access the exported security context will fail. + * + *

RFC 2078 + *
equivalent to gss_export_sec_context
+ * @return inter-process token representing the context + * in export form + * @exception GSSException with possible major codes of UNAVAILABLE, + * CONTEXT_EXPIRED, NO_CONTEXT, FAILURE. + * @see GSSContext#GSSContext(byte[]) + * @see #isTransferable + */ + public byte [] export() throws GSSException { + + checkState(READY); + byte [] outTok = m_mechCtxt._export (); + dispose(); + + return (outTok); + } + + + /** + * Sets the request state of the mutual authentication flag + * for the context. This method is only valid before the + * context creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the mutual_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if mutual authentication + * should be requested during context establishment. + * @exception GSSException may be thrown + * @see #getMutualAuthState + */ + public void requestMutualAuth(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= MUTUAL_AUTH; + else + m_reqFlags ^= MUTUAL_AUTH; + } + + + /** + * Sets the request state of the replay detection service + * for the context. This method is only valid before the + * context creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the replay_det_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if replay detection is desired + * over the established context. + * @exception GSSException may be thrown + * @see #getReplayDetState + */ + public void requestReplayDet(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= REPLAY_DET; + else + m_reqFlags ^= REPLAY_DET; + } + + + /** + * Sets the request state of the sequence checking service + * for the context. This method is only valid before the + * context creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the sequence_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if sequence checking service + * is desired over the established context. + * @exception GSSException may be thrown + * @see #getSequenceDetState + */ + public void requestSequenceDet(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= SEQUENCE_DET; + else + m_reqFlags ^= SEQUENCE_DET; + } + + + /** + * Sets the request state of the credential delegation flag + * for the context. This method is only valid before the + * context creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the deleg_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if credential delegation is desired. + * @exception GSSException may be thrown + * @see #getDelegCredState + */ + public void requestCredDeleg(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= CRED_DELEG; + else + m_reqFlags ^= CRED_DELEG; + + } + + + /** + * Requests anonymous support over the context. This method is + * only valid before the context creation process begins and + * only for the initiator. + * + *

RFC 2078 + *
equivalent to anon_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean representing if anonymity support is desired. + * @exception GSSException may be thrown + * @see #getAnonymityState + */ + public void requestAnonymity(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= ANON; + else + m_reqFlags ^= ANON; + } + + + /** + * Requests that confidentiality service be available over + * the context. This method is only valid before the context + * creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the conf_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean indicating if confidentiality services are to + * be requested for the context. + * @exception GSSException may be thrown + * @see #getConfState + */ + public void requestConf(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= CONF; + else + m_reqFlags ^= CONF; + } + + + /** + * Requests that integrity service be available over + * the context. This method is only valid before the context + * creation process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the integ_req_flag parameter in + * gss_init_sec_context
+ * @param Boolean indicating if integrity services are to + * be requested for the context. + * @exception GSSException may be thrown + * @see #getIntegState + */ + public void requestInteg(boolean state) throws GSSException { + + checkState(PRE_INIT); + + if (state) + m_reqFlags |= INTG; + else + m_reqFlags ^= INTG; + } + + + /** + * Sets the desired lifetime for the context in seconds. + * This method is only valid before the context creation + * process begins and only for the initiator. + * + *

RFC 2078 + *
equivalent to the lifetime_req parameter in + * gss_init_sec_context
+ * @param The desired context lifetime in seconds. + * @exception GSSException may be thrown + * @see #getLifetime + */ + public void requestLifetime(int lifetime) throws GSSException { + + checkState(PRE_INIT); + + m_reqLifetime = lifetime; + } + + + /** + * Sets the channel bindings to be used during context + * establishment. This method is only valid before the + * context creation process begins. + * + *

RFC 2078 + *
equivalent to the chan_bindings parameter in + * gss_init_sec_context and gss_accept_sec_context
+ * @param Channel binding to be used. + * @exception GSSException may be thrown + * @see ChannelBinding + */ + public void setChannelBinding(ChannelBinding cb) throws GSSException { + + checkState(PRE_INIT); + m_chB = cb; + } + + + /** + * Returns the state of the delegated credentials for the context. + * When issued before context establishment completes or + * when the isProtReady method returns false, it returns the + * desired state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the deleg_state flag output parameter in + * gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating if delegated credentials are available + * @see #requestCredDeleg + * @see #isProtReady + */ + public boolean getDelegCredState() { + + if (m_curState < READY) + return ((m_reqFlags & CRED_DELEG) == CRED_DELEG); + + return ((m_mechCtxt._getOptions () & CRED_DELEG) == CRED_DELEG); + } + + + /** + * Returns the state of the mutual authentication option for + * the context. When issued before context establishment completes + * or when the isProtReady method returns false, it returns the + * desired state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the mutual_state flag output parameter + * in gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating state of mutual authentication option + * @see #requestMutualAuth + * @see #isProtReady + */ + public boolean getMutualAuthState() { + + if (m_curState < READY) + return ((m_reqFlags & MUTUAL_AUTH) == MUTUAL_AUTH); + + return ((m_mechCtxt._getOptions () & MUTUAL_AUTH) == MUTUAL_AUTH); + } + + + /** + * Returns the state of the replay detection service for + * the context. When issued before context establishment completes + * or when the isProtReady method returns false, it returns the + * desired state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the replay_det_state flag output + * parameter in gss_init_sec_context, gss_accept_sec_context + * and gss_inquire_context
+ * @return boolean indicating replay detection state + * @see #requestReplayDet + * @see #isProtReady + */ + public boolean getReplayDetState() { + + if (m_curState < READY) + return ((m_reqFlags & REPLAY_DET) == REPLAY_DET); + + return ((m_mechCtxt._getOptions () & REPLAY_DET) == REPLAY_DET); + } + + + /** + * Returns the state of the sequence detection service for + * the context. When issued before context establishment completes + * or when the isProtReady method returns false, it returns the + * desired state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the sequence_state flag output parameter + * in gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating sequence detection state + * @see #requestSequenceDet + * @see #isProtReady + */ + public boolean getSequenceDetState() { + + if (m_curState < READY) + return ((m_reqFlags & SEQUENCE_DET) == SEQUENCE_DET); + + return ((m_mechCtxt._getOptions () & SEQUENCE_DET) == SEQUENCE_DET); + } + + + /** + * Returns true if this is an anonymous context. When issued + * before context establishment completes or when the + * isProtReady method returns false, it returns the desired + * state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the anon_state flag output parameter in + * gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating anonymity state + * @see #requestAnonymity + * @see #isProtReady + */ + public boolean getAnonymityState() { + + if (m_curState < READY) + return ((m_reqFlags & ANON) == ANON); + + return ((m_mechCtxt._getOptions () & ANON) == ANON); + } + + + /** + * Indicates if the context is transferable to other processes + * through the use of the export method. This call is only valid + * on fully established contexts. + * + *

RFC 2078 + *
equivalent to the trans_state flag output parameter in + * gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating the transferability of the context + * @exception GSSException may be thrown + * @see #export + */ + public boolean isTransferable() throws GSSException { + + checkState(READY); + return ((m_mechCtxt._getOptions () & TRANS) == TRANS); + } + + + /** + * Indicates if the per message operations can be applied over + * the context. Some mechanisms may allow to apply per-message + * operations before the context is fully established. This will + * also indicate that the get methods will return actual context + * state characteristics instead of the desired ones. + * + *

RFC 2078 + *
equivalent to the prot_ready_state flag output + * parameter in gss_init_sec_context and + * gss_accept_sec_context
+ * @return boolean indicating if per message operations are available + */ + public boolean isProtReady() { + + if (m_mechCtxt == null) + return false; + + return (m_mechCtxt._isProtReady ()); + } + + + /** + * Returns the confidentiality service state over the context. + * When issued before context establishment completes or when + * the isProtReady method returns false, it returns the desired + * state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the conf_avail flag output parameter + * in gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating confidentiality state + * @see #requestConf + * @see #isProtReady + */ + public boolean getConfState() { + + if (m_curState < READY) + return ((m_reqFlags & CONF) == CONF); + + return ((m_mechCtxt._getOptions () & CONF) == CONF); + } + + + /** + * Returns the integrity service state over the context. + * When issued before context establishment completes or when + * the isProtReady method returns false, it returns the desired + * state, otherwise it will indicate the actual state over + * the established context. + * + *

RFC 2078 + *
equivalent to the integ_avail flag output parameter + * in gss_init_sec_context, gss_accept_sec_context and + * gss_inquire_context
+ * @return boolean indicating integrity state + * @see #requestInteg + * @see #isProtReady + */ + public boolean getIntegState() { + + if (m_curState < READY) + return ((m_reqFlags & INTG) == INTG); + + return ((m_mechCtxt._getOptions () & INTG) == INTG); + } + + + /** + * Returns the context lifetime in seconds. + * When issued before context establishment completes or when + * the isProtReady method returns false, it returns the desired + * lifetime, otherwise it will indicate the actual lifetime over + * the established context. + * + *

RFC 2078 + *
equivalent to the lifetime_rec output parameter in + * gss_init_sec_context, gss_accept_sec_context, + * gss_inquire_context and to gss_context_time call
+ * @return lifetime in seconds + * @see #requestLifetime + * @see #isProtReady + */ + public int getLifetime() { + + if (m_curState < READY) + return (m_reqLifetime); + + return (m_mechCtxt._getLifetime ()); + } + + + /** + * Retrieves the name of the context initiator. + * This call is valid only after context has been fully established + * or when the isProtReady methods returns true. + * + *

RFC 2078 + *
equivalent to the src_name parameter in + * gss_accept_sec_context and gss_inquire_context
+ * @return name of the context initiator + * @exception GSSException with possible major codes of CONTEXT_EXPIRED + * and FAILURE + * @see #isProtReady + */ + public GSSName getSrcName() throws GSSException { + + checkState(IN_PROGRESS); + return (new GSSName(m_mechCtxt._getSrcName ())); + } + + + /** + * Retrieves the name of the context target (acceptor). + * This call is only valid on fully established contexts + * or when the isProtReady methods returns true. + * + *

RFC 2078 + *
equivalent to the targ_name parameter in + * gss_inquire_context
+ * @return name of the context target (acceptor) + * @exception GSSException with possible major codes of + * CONTEXT_EXPIRED and FAILURE + * @see #isProtReady + */ + public GSSName getTargName() throws GSSException { + + checkState(IN_PROGRESS); + return (new GSSName(m_mechCtxt._getTargName ())); + } + + + /** + * Returns the mechanism oid for the context. + * + *

RFC 2078 + *
equivalent to the mech_type parameter in + * gss_accept_sec_context and gss_inquire_context
+ * @return Oid object for the context's mechanism + * @exception GSSException may be thrown when the mechanism + * oid can't be determined + * + */ + public Oid getMech() throws GSSException { + + checkState(IN_PROGRESS); + return (m_mechCtxt._getMech ()); + } + + + /** + * Returns the delegated credential object on the acceptor's side. + * To check for availability of delegated credentials call + * getDelegCredState. This call is only valid on fully established + * contexts. + * + *

RFC 2078 + *
equivalent to delegated_cred_handle parameter + * in gss_accept_sec_context
+ * @return delegated credential object for the context + * @exception GSSException with possible major codes of + * CONTEXT_EXPIRED and FAILURE + * @see #getDelegCredState + */ + public GSSCredential getDelegCred() throws GSSException { + + checkState(IN_PROGRESS); + return (new GSSCredential(m_mechCtxt._getDelegCred ())); + } + + + /** + * Returns true if this is the initiator of the context. + * This call is only valid after the context creation process + * has started. + * + *

RFC 2078 + *
equivalent to locally_initiated output parameter + * in gss_inquire_context
+ * @return true if this is the context initiator + * @exception GSSException with possible major codes of + * CONTEXT_EXPIRED and FAILURE + */ + public boolean isInitiator() throws GSSException { + + checkState(IN_PROGRESS); + return (m_mechCtxt._isInitiator ()); + } + + + /** + * Ensures the object is in the required state. + * + * @param minimumState the minimum required state. + * @exception GSSException is thrown when the state is incorrect. + */ + private void checkState(int minimumState) throws GSSException { + + if (m_curState < minimumState) + throw new GSSException(GSSException.NO_CONTEXT); + + //this is just temporary for debugging + if (minimumState > PRE_INIT && m_mechCtxt == null) + throw new GSSException(GSSException.NO_CONTEXT, -1, + "error in checkState"); + } + + + /** + * Private initializer of context variables + */ + private void initialize() { + + m_reqFlags = MUTUAL_AUTH | SEQUENCE_DET | REPLAY_DET; + m_myCred = null; + m_reqLifetime = INDEFINITE; + m_curState = PRE_INIT; + m_mechOid = null; + m_targName = null; + m_chB = null; + } + + + /** + * Reads the token header as defined in RFC 2078 and + * returns the mechanism oid. Currently this requires that + * the stream support mark/reset operations. As an + * alternative we can strip this header, and pass the information + * into the mechanism. + */ + private Oid getTokenMech(InputStream is) throws GSSException { + + try { + is.mark(100); + + if (is.read() != 0x60) + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + + //we can skip the token length + DERParser.readLength(is); + + //next we have the full der encoding of the oid + Oid res = new Oid(is); + is.reset(); + + return (res); + } catch (IOException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + + } + + + //private flags for the context state + private static final int PRE_INIT = 1; + private static final int IN_PROGRESS = 2; + private static final int READY = 3; + private static final int DELETED = 4; + + + //instance variables + private GSSCtxtSpi m_mechCtxt; + private int m_reqFlags; + private GSSCredential m_myCred; + private int m_reqLifetime; + private int m_curState; + private Oid m_mechOid; + private GSSName m_targName; + private ChannelBinding m_chB; +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSCredSpi.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSCredSpi.java new file mode 100644 index 0000000000..5a234ef906 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSCredSpi.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ +package com.sun.gssapi; + + +/** + * This interface is implemented by each mechanism to provide the + * functionality of a credential. Each GSSCredential uses provider + * objects implementing this interface. A GSSCredential may have + * several credential elements underneath it, but each GSSCredSpi + * object can represent at most 1 credential element. + */ +public interface GSSCredSpi { + + /** + * Initialized the credential object. Called after the + * object is first instantiated. + * + * @param desiredName - desired name of the principal + * @param initLifetime - desired lifetime for the init + * credential; 0 signals use mechanism default + * @param acceptLifetime - desired lifetime for the accept + * credential; 0 signals use mechanism default + * @param usage - the desired usage for this credential + * @exception - GSSException may be thrown + */ + public void init(GSSNameSpi desiredName, int initLifetime, + int acceptLifetime, int usage) throws GSSException; + + + /** + * Called to invalidate this credential element and release + * any system recourses and cryptographic information owned + * by the credential. + * + * @exception GSSException with major codes NO_CRED and FAILURE + */ + public void dispose() throws GSSException; + + + /** + * Returns the principal name for this credential. The name + * is in mechanism specific format. + * + * @return GSSNameSpi representing principal name of this credential + * @exception GSSException may be thrown + */ + public GSSNameSpi getName() throws GSSException; + + + /** + * Returns the init lifetime remaining. + * + * @return the init lifetime remaining in seconds + * @exception GSSException may be thrown + */ + public int getInitLifetime() throws GSSException; + + + /** + * Returns the accept lifetime remaining. + * + * @return the accept lifetime remaining in seconds + * @exception GSSException may be thrown + */ + public int getAcceptLifetime() throws GSSException; + + + /** + * Returns the lifetime remaining. This should take + * into account the credential usage, and return the + * appropriate lifetime. See RFC 2078 for details. + * + * @return the lifetime remaining in seconds + * @exception GSSException may be thrown + */ + public int getLifetime() throws GSSException; + + + /** + * Returns the credential usage. This must be one + * GSSCredential.ACCEPT_ONLY, GSSCredential.INITIATE_ONLY, + * or GSSCredential.INITIATE_AND_ACCEPT. + * + * @return the credential usage + * @exception GSSException may be thrown + */ + public int getUsage() throws GSSException; + + + /** + * Returns the oid representing the underlying credential + * mechanism oid. + * + * @return the Oid for this credential mechanism + * @exception GSSException may be thrown + */ + public Oid getMechanism(); +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSCredential.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSCredential.java new file mode 100644 index 0000000000..beb4e4154f --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSCredential.java @@ -0,0 +1,575 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.util.Vector; +import java.util.Enumeration; + + +/** + * This class manages GSS-API credentials and their associated + * operations. A credential contains all the necessary cryptographic + * information to enable the creation of a context on behalf of the + * entity that it represents. It may contain multiple distinct mechanism + * specific credential elements, each containing mechanism specific + * information, and all referring to the same entity. + *

+ * A credential may be used to perform context initiation, acceptance, + * or both. + *

RFC 2078 + *
This class represents the credential management GSS-API calls, + * which are:
  • gs_acquire_cred + *
  • gss_release_cred + *
  • gss_inquire_cred + *
  • gss_add_cred + *
  • gss_inquire_cred_by_mech
+ * The gss_inquire_cred and gss_inquire_cred_by_mech calls have been + * distributed over several property querying methods each returning + * specific GSSCredential information. + *
+ */ +public class GSSCredential { + + /** + * Credential usage flag requesting that it be able to be used + * for both context initiation and acceptance. + */ + public static final int INITIATE_AND_ACCEPT = 0; + + + /** + * Credential usage flag requesting that it be able to be used + * for context initiation only. + */ + public static final int INITIATE_ONLY = 1; + + + /** + * Credential usage flag requesting that it be able to be used + * for context acceptance only. + */ + public static final int ACCEPT_ONLY = 2; + + + /** + * Indefinite lifetime for a credential. It is set to the + * largest value for an int in Java. + * @see #getRemainingLifetime + **/ + public static final int INDEFINITE = Integer.MAX_VALUE; + + + /** + * Constructor for default credentials. + * This will use the default mechanism, default mechanism name, + * and an INDEFINITE lifetime. + *
RFC 2078 + *
equivalent to gss_acquire_cred
+ * @param usage - the intended usage for this credential; this + * must be one of the constants defined in this class. + * @exception GSSException with possible major code of FAILURE + **/ + public GSSCredential(int usage) throws GSSException { + + add((GSSName)null, INDEFINITE, INDEFINITE, (Oid)null, usage); + } + + + /** + * Constructor for default mechanism credential. + * Uses default mechanism and INDEFINITE lifetime. + *
RFC 2078 + *
equivalent to gss_acquire_cred
+ * @param aName - name of the principal for whom this credential + * is to be acquired + * @param usage - the intended usage for this credential; this + * must be one of the constants defined in this class + * @exception GSSException with possible major codes of FAILURE and + * BAD_NAME + **/ + public GSSCredential(GSSName aName, int usage) throws GSSException { + + add(aName, INDEFINITE, INDEFINITE, (Oid)null, usage); + } + + + /** + * Constructor for a single mechanism credential. + * null values can be specified for name and mechanism to obtain + * system specific defaults. + *
RFC 2078 + *
equivalent to gss_acquire_cred
+ * @param aName - name of the principal for whom this credential + * is to be acquired; use null for system specific default + * principal + * @param lifetime - the duration of this credential + * @param mechOid - mechanism over which this credential is to + * be acquired + * @param usage - the intended usage for this credential; this + * must be one of the constants defined in this class + * @exception GSSException with possible major codes of FAILURE, + * BAD_MECH, and BAD_NAME + **/ + public GSSCredential(GSSName aName, int lifetime, Oid mechOid, + int usage) throws GSSException { + + add(aName, lifetime, lifetime, mechOid, usage); + } + + /** + * Constructor for a credential over a set of mechanisms. + * Acquires credentials for each of the mechanisms specified + * in mechs array. null value can be used for Name to obtain + * system specific default. To determine for which mechanisms + * acquiring of the credential was successful use the getMechs + * method. Note that this call is equivalent to creating a + * single mechanism credential and using addCred to extend the + * credential over other mechanisms. + *
RFC 2078 + *
equivalent to gss_acquire_cred
+ * @param aName - name of the principal for whom this credential + * is to be acquired; use null for system specific default + * principal + * @param lifetime - the desired duration of this credential + * @param mechs - mechanisms over which this credential is to + * be acquired + * @param usage - the intended usage for this credential; this + * must be one of the constants defined in this class + * @exception GSSException with possible major codes of FAILURE, + * BAD_MECH, and BAD_NAME + */ + public GSSCredential(GSSName aName, int lifetime, Oid [] mechs, + int usage) throws GSSException { + + for (int i = 0; i < mechs.length; i++) + add(aName, lifetime, lifetime, mechs[i], usage); + } + + + /** + * Package private constructor used to create a credential + * object using the supplied mechanism credential element. + * + * @param GSSCredSpi mechanism specific credential object + */ + GSSCredential(GSSCredSpi mechCred) { + + m_mechCreds.addElement(mechCred); + } + + + /** + * Used to dispose of any sensitive information that the + * GSSCredential may be containing. Should be called as soon + * as the credential is no longer needed to minimize the time + * sensitive information is maintained. + *
RFC 2078 + *
equivalent to gss_release_cred
+ * @exception GSSException with possible major code of FAILURE + */ + public void dispose() throws GSSException { + + for (Enumeration e = m_mechCreds.elements(); e.hasMoreElements();) { + ((GSSCredSpi)e.nextElement()).dispose(); + } + m_mechCreds.removeAllElements(); + } + + /** + * Retrieves the name of the entity that the credential has been + * acquired for. + *
RFC 2078 + *
equivalent to obtaining the cred_name parameter + * from gss_inquire_cred
+ * @return GSSName for the credential's principal + * @exception GSSException with possible major codes of FAILURE, + * NO_CRED, DEFECTIVE_CREDENTIAL, CREDENTIAL_EXPIRED + */ + public GSSName getGSSName() throws GSSException { + + /* + * will return name containing mechanism elements for + * all mechs this credential supports + */ + if (m_mechCreds.size() < 1) + throw new GSSException(GSSException.NO_CRED); + + GSSName aName = new GSSName(); + for (Enumeration e = m_mechCreds.elements(); e.hasMoreElements(); ) { + + aName.addMechName(((GSSCredSpi)e.nextElement()).getName()); + } + + return (aName); + } + + /** + * Queries the selected mechanism for the principal name of the + * credential. The mechanism must be one of the mechanisms over + * which the credential is acquired. + *
RFC 2078 + *
equivalent to obtaining the cred_name parameter from + * gss_inquire_cred_by_mech
+ * @param mechOID the credential mechanism to be queried + * @Return GSSName for the credential's principal; this GSSName + * object will be an MN + * @exception GSSException with possible major codes of NO_CRED, + * DEFECTIVE_CREDENTIAL, CREDENTIALS_EXPIRED, FAILURE and + * BAD_MECH + */ + public GSSName getGSSName(Oid mechOID) throws GSSException { + + GSSName aName = new GSSName(); + aName.addMechName(getMechCred(mechOID, true).getName()); + return (aName); + } + + + /** + * Obtains the remaining lifetime for a credential. The remaining + * lifetime is the minimum lifetime for any of the credential + * elements. Return of 0 indicates the credential is already + * expired. + *
RFC 2078 + *
equivalent to lifetime parameter in gss_inquire_cred + *
+ * @return lifetime in seconds + * @exception GSSException with possible major codes of NO_CRED, + * DEFECTIVE_CREDENTIAL, FAILURE. + */ + public int getRemainingLifetime() throws GSSException { + + int lifetime = GSSCredential.INDEFINITE; + GSSCredSpi aCred; + + if (m_mechCreds.size() < 0) + throw new GSSException(GSSException.NO_CRED); + + /* find the minimum lifetime */ + for (Enumeration e = m_mechCreds.elements(); e.hasMoreElements();) { + + aCred = (GSSCredSpi)e.nextElement(); + if (aCred.getLifetime() < lifetime) + lifetime = aCred.getLifetime(); + } + return (lifetime); + } + + /** + * Returns the remaining lifetime in seconds for the credential + * to remain capable of initiating security context under the + * specified mechanism. Return of 0 indicates that the + * credential is already expired. + *
RFC 2078 + *
equivalent to lifetime_init parameter in + * gss_inquire_cred_by_mech
+ * @param mech Oid for the credential mechanism to be queried + * @return the remaining initiation lifetime in seconds + * @exception GSSException with possible major codes of NO_CRED, + * DEFECTIVE_CREDENTIAL, FAILURE and BAD_MECH + */ + public int getRemainingInitLifetime(Oid mech) throws GSSException { + + GSSCredSpi aCred = getMechCred(mech, true); + return (aCred.getInitLifetime()); + } + + + /** + * Returns the remaining lifetime in seconds for the credential + * to remain capable of accepting security context under the + * specified mechanism. Return of 0 indicates that the + * credential is already expired. + *
RFC 2078 + *
equivalent to lifetime_accept parameter in + * gss_inquire_cred_by_mech
+ * @param mech Oid for the credential mechanism to be queried + * @return the remaining acceptance lifetime in seconds + * @exception GSSException with possible major codes of NO_CRED, + * DEFECTIVE_CREDENTIAL, FAILURE and BAD_MECH + */ + public int getRemainingAcceptLifetime(Oid mech) throws GSSException { + + GSSCredSpi aCred = getMechCred(mech, true); + return (aCred.getAcceptLifetime()); + } + + + /** + * Retrieve the credential usage flag, which is one of + * INITIATE_ONLY, ACCEPT_ONLY, INITIATE_AND_ACCEPT. + *
RFC 2078 + *
equivalent to usage parameter in gss_inquire_cred
+ * @return credential usage which will be only of + * INITIATE_ONLY, ACCEPT_ONLY, or INITIATE_AND_ACCEPT + * @exception GSSException with possible major codes of NO_CRED, + * DEFECTIVE_CREDENTIAL, CREDENTIALS_EXPIRED, FAILURE. + */ + public int getUsage() throws GSSException { + + boolean init = false, accept = false; + GSSCredSpi aCred; + + if (m_mechCreds.size() < 0) + throw new GSSException(GSSException.NO_CRED); + + /* find the usage for the credential */ + for (Enumeration e = m_mechCreds.elements(); e.hasMoreElements();) { + + aCred = (GSSCredSpi)e.nextElement(); + if (aCred.getUsage() == GSSCredential.INITIATE_AND_ACCEPT) + return (GSSCredential.INITIATE_AND_ACCEPT); + else if (aCred.getUsage() == GSSCredential.INITIATE_ONLY) + init = true; + else if (aCred.getUsage() == GSSCredential.ACCEPT_ONLY) + accept = true; + + //if both are set, then we are done.... + if (init && accept) + return (GSSCredential.INITIATE_AND_ACCEPT); + } + + //can only be a single use credential + if (init) + return (GSSCredential.INITIATE_ONLY); + + return (GSSCredential.ACCEPT_ONLY); + } + + + /** + * Retrieve the credential usage flag, which is one of + * INITIATE_ONLY, ACCEPT_ONLY, INITIATE_AND_ACCEPT, for a + * specific credential mechanism. + *
RFC 2078 + *
equivalent to usage parameter in + * gss_inquire_cred_by_mech
+ * @param oid for the credential mechanism to query + * @return credential usage which will be only of + * INITIATE_ONLY, ACCEPT_ONLY, or INITIATE_AND_ACCEPT + * @exception GSSException with possible major codes of NO_CRED, + * DEFECTIVE_CREDENTIAL, CREDENTIALS_EXPIRED, FAILURE. + */ + public int getUsage(Oid mechOID) throws GSSException { + + GSSCredSpi aCred = getMechCred(mechOID, true); + return (aCred.getUsage()); + } + + + /** + * Returns the mechanism oids over which the credential has been + * acquired. + *
RFC 2078 + *
equivalent to mech_set parameter of gss_inquire_cred
+ * @return the array of mechanism oid's over which this credential + * has been acquired + * @exception GSSException with possible major codes of FAILURE, + * NO_CRED, DEFECTIVE_CREDENTIAL, CREDENTIAL_EXPIRED + */ + public Oid [] getMechs() throws GSSException { + + Oid [] oids = new Oid[m_mechCreds.size()]; + int i = 0; + + if (m_mechCreds.size() < 1) + throw new GSSException(GSSException.NO_CRED); + + for (Enumeration e = m_mechCreds.elements(); e.hasMoreElements();) + oids[i++] = ((GSSCredSpi)e.nextElement()).getMechanism(); + + return (oids); + } + + + /** + * This method enables the construction of credentials one + * mechanism at a time. A single mechanism credential will + * be added as specified by the mech parameter. This is + * equivalent to using the constructor for multiple mechanism + * but gives finer control and feedback. + *
RFC 2078 + *
equivalent to gss_add_cred
+ * to obtain a new credential as in gss_add_cred, first call + * clone and then addCred
+ * @param aName - name of the principal for whom this credential + * is to be acquired; use null for system specific default + * principal + * @param initLifetime - the desired duration of this credential + * initiation lifetime; value in seconds + * @param acceptLifetime - the desired duration of this credential + * accept lifetime; value in seconds + * @param mechs - mechanism over which this credential is to + * be acquired + * @param usage - the intended usage for this credential; this + * must be one of the constants defined in this class + * @exception GSSException with possible major codes of + * DUPLICATE_ELEMENT, BAD_MECH, BAD_NAME, BAD_NAME, NO_CRED, + * or FAILURE. + */ + public synchronized void add(GSSName aName, int initLifetime, + int acceptLifetime, Oid mech, int usage) throws GSSException { + + if (mech == null) + mech = GSSManager.getDefaultMech(); + + //check if this cred already exists + if (getMechCred(mech, false) != null) + throw new GSSException(GSSException.DUPLICATE_ELEMENT); + + //ok, go ahead create new one....... + GSSCredSpi newCred = GSSManager.getCredInstance(mech); + + newCred.init(aName.canonicalizeInPlace(mech), initLifetime, + acceptLifetime, usage); + + //mechanism credential created successfully, so add + m_mechCreds.addElement(newCred); + } + + + /** + * Tests if this GSSCredential refers to the same entity as the + * supplied object. The two GSSCredentials must be acquired over + * the same mechanisms. + * @return true if the two GSSCredentials refer to the same + * entity; false otherwise. + * @override java.lang.Object#equals + */ + public boolean equals(Object another) { + + if ( !(another instanceof GSSCredential)) + return (false); + + GSSCredential aCred = (GSSCredential)another; + + if (aCred.m_mechCreds.size() != m_mechCreds.size()) + return (false); + + GSSCredSpi intCred, anotherIntCred; + + try { + for (Enumeration e = m_mechCreds.elements(); + e.hasMoreElements();) { + + intCred = (GSSCredSpi)e.nextElement(); + anotherIntCred = aCred.getMechCred( + intCred.getMechanism(), false); + if (anotherIntCred == null) + return (false); + + //ask internal creds to compare themselves + if (intCred.equals(anotherIntCred) == false) + return (false); + + } + } catch (GSSException e) { + return (false); + } + + //all internal creds are equal, so we are equal too... + return (true); + } + + + /** + * Debugging aid. Returns string with information about + * this credential object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer(150); + + sb.append(super.toString()); + sb.append("\nOver mechs:\t"); + try { + Oid [] mechs = getMechs(); + for (int i = 0; i < mechs.length; i++) + sb.append(mechs[i].toString() + " "); + + sb.append("\nFor principal:\t" + getGSSName().toString()); + sb.append("\nUsage:\t" + getUsage()); + if (getUsage() == ACCEPT_ONLY) + sb.append(" (ACCEPT_ONLY)"); + else if (getUsage() == INITIATE_ONLY) + sb.append(" (INITIATE_ONLY)"); + else + sb.append(" (INITIATE and ACCEPT)"); + + sb.append("\nRemaining Lifetime:\t" + getRemainingLifetime()); + + } catch (GSSException e) { + sb.append("\n***ERROR getting info:\t" + e.toString()); + } + + return (sb.toString()); + } + + + /** + * Returns the specified mechanism's credential-element. + * + * @param mechOid - the oid for mechanism to retrieve + * @param throwExcep - boolean indicating if the function is + * to throw exception or return null when element is not + * found. + * @return mechanism credential object + * @exception GSSException of invalid mechanism + */ + GSSCredSpi getMechCred(Oid mechOid, boolean throwExcep) + throws GSSException { + + for (Enumeration e = m_mechCreds.elements(); e.hasMoreElements();) { + + GSSCredSpi aCred = (GSSCredSpi)e.nextElement(); + if (aCred.getMechanism().equals(mechOid)) + return (aCred); + } + + /* not found */ + if (throwExcep == true) + throw new GSSException(GSSException.BAD_MECH); + else + return (null); + } + + + /* private instance variables */ + Vector m_mechCreds = new Vector(3, 3); +} + diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSCtxtSpi.m4 b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSCtxtSpi.m4 new file mode 100644 index 0000000000..735659d644 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSCtxtSpi.m4 @@ -0,0 +1,325 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.io.InputStream; +import java.io.OutputStream; + + +/** + * An object of this class implements the functionality of a GSSContext + * for a specific mechanism. + * A GSSCtxtSpi object can be thought of having 3 states: + * -before initialization + * -during initialization with its peer + * -after it is established + *

+ * The context options can only be requested in state 1. In state 3, + * the per message operations are available to the callers. The get + * methods for the context options will return the requested options + * while in state 1 and 2, and the established values in state 3. + * Some mechanisms may allow the access to the per-message operations + * and the context flags before the context is fully established. The + * isProtReady method is used to indicate that these services are + * available. + */ + +public interface GSSCtxtSpi { + + /** + * Sets the mechanism options to be used during context + * creation on the initiator's side. This is used to + * initialize a new GSSCtxtSpi object. + * + * @param myCred the principal's credentials; may be null + * @param targName the context peer + * @param desLifetime the requested lifetime; 0 indicates use + * default + * @param mechOptions ORed GSSContext options + * @exception GSSException may be thrown + */ + public void _setInitOptions (GSSCredSpi myCred, GSSNameSpi targName, + int desLifetime, int ctxtOptions) throws GSSException; + + + /** + * Sets the mechanism options to be used during context + * creation on the acceptor's side. This is used to initialize + * a new GSSCtxtSpi object. + * + * @param myCred the principal's credentials; may be null + * @exception GSSException may be thrown + */ + public void _setAcceptOptions (GSSCredSpi myCred) throws GSSException; + + + /** + * Sets the channel bindings to be used during context + * establishment. This method is only called if the application + * wishes to use channel bindings with this context. + * + * @param chb channel bindings to be set + * @exception GSSException may be thrown + */ + public void _setChannelBinding (ChannelBinding chb) throws GSSException; + + + /** + * Retrieves the mechanism options. + * + * @return int GSSContext options ORed together + */ + public int _getOptions (); + + + /** + * Inquire the remaining lifetime. + * + * @return the lifetime in seconds. May return reserved + * value GSSContext.INDEFINITE for an indefinite lifetime. + */ + public int _getLifetime (); + + + /** + * Returns the mechanism oid. + * + * @return the Oid for this context + */ + public Oid _getMech (); + + + /** + * Returns the context initiator name. + * + * @return initiator name + * @exception GSSException may be thrown + */ + public GSSNameSpi _getSrcName () throws GSSException; + + + /** + * Returns the context acceptor name. + * + * @return context acceptor(target) name + * @exception GSSException may be thrown + */ + public GSSNameSpi _getTargName () throws GSSException; + + + /** + * Returns the delegated credential for the context. This + * is an optional feature of contexts which not all + * mechanisms will support. A context can be requested to + * support credential delegation by using the CRED_DELEG. + * This is only valid on the acceptor side of the context. + * @return GSSCredSpi object for the delegated credential + * @exception GSSException may be thrown + * @see GSSContext#getDelegCredState + */ + public GSSCredSpi _getDelegCred () throws GSSException; + + + /** + * Tests if this is the initiator side of the context. + * + * @return boolean indicating if this is initiator (true) + * or target (false) + */ + public boolean _isInitiator (); + + + /** + * Tests if the context can be used for per-message service. + * Context may allow the calls to the per-message service + * functions before being fully established. + * + * @return boolean indicating if per-message methods can + * be called. + */ + public boolean _isProtReady (); + + + /** + * Initiator context establishment call. This method may be + * required to be called several times. A CONTINUE_NEEDED return + * call indicates that more calls are needed after the next token + * is received from the peer. + * + * @param is contains the token received from the peer. On the + * first call it will be ignored. + * @param os to which any tokens required to be sent to the peer + * will be written. It is responsibility of the caller + * to send the token to its peer for processing. + * @return integer indicating if more calls are needed. Possible + * values are COMPLETE and CONTINUE_NEEDED. + * @exception GSSException may be thrown + */ + public int _initSecCtxt (InputStream is, OutputStream os) + throws GSSException; + + + /** + * Acceptor's context establishment call. This method may be + * required to be called several times. A CONTINUE_NEEDED return + * call indicates that more calls are needed after the next token + * is received from the peer. + * + * @param is contains the token received from the peer. + * @param os to which any tokens required to be sent to the peer + * will be written. It is responsibility of the caller + * to send the token to its peer for processing. + * @return integer indicating if more calls are needed. Possible + * values are COMPLETE and CONTINUE_NEEDED. + * @exception GSSException may be thrown + */ + public int _acceptSecCtxt (InputStream is, OutputStream os) + throws GSSException; + + + /** + * Queries the context for largest data size to accomodate + * the specified protection and for the token to remain less then + * maxTokSize. + * + * @param qop the quality of protection that the context will be + * asked to provide. + * @param confReq a flag indicating whether confidentiality will be + * requested or not + * @param outputSize the maximum size of the output token + * @return the maximum size for the input message that can be + * provided to the wrap() method in order to guarantee that these + * requirements are met. + * @exception GSSException may be thrown + */ + public int _getWrapSizeLimit (int qop, boolean confReq, int maxTokSize) + throws GSSException; + + + /** + * Provides per-message token encapsulation. + * + * @param is the user-provided message to be protected + * @param os the token to be sent to the peer. It includes + * the message from is with the requested protection. + * @param msgPro on input it contains the requested qop and + * confidentiality state, on output, the applied values + * @exception GSSException may be thrown + * @see MessageInfo + * @see unwrap + */ + public void _wrap (InputStream is, OutputStream os, MessageProp msgProp) + throws GSSException; + + + /** + * Retrieves the message token previously encapsulated in the wrap + * call. + * + * @param is the token from the peer + * @param os unprotected message data + * @param msgProp will contain the applied qop and confidentiality + * of the input token and any informatory status values + * @exception GSSException may be thrown + * @see MessageInfo + * @see wrap + */ + public void _unwrap (InputStream is, OutputStream os, + MessageProp msgProp) throws GSSException; + + + /** + * Applies per-message integrity services. + * + * @param is the user-provided message + * @param os the token to be sent to the peer along with the + * message token. The message token is not encapsulated. + * @param msgProp on input the desired QOP and output the applied QOP + * @exception GSSException + */ + public void _getMIC (InputStream is, OutputStream os, + MessageProp msgProp) + throws GSSException; + + + /** + * Checks the integrity of the supplied tokens. + * This token was previously generated by getMIC. + * + * @param is token generated by getMIC + * @param msgStr the message to check integrity for + * @param msgProp will contain the applied QOP and confidentiality + * states of the token as well as any informatory status codes + * @exception GSSException may be thrown + */ + public void _verifyMIC (InputStream is, InputStream msgStr, + MessageProp mProp) throws GSSException; + + + /** + * Produces a token representing this context. After this call + * the context will no longer be usable until an import is + * performed on the returned token. + * + * @return exported context token + * @exception GSSException may be thrown + */ + public byte []_export () throws GSSException; + + + /** + * Imports a previously exported context. This will be called + * for newly created objects. + * + * @param is the previously exported token + * @exception GSSException may be thrown + * @see export + */ + public void _importSecCtxt (byte []token) throws GSSException; + + + /** + * Releases context resources and terminates the + * context between 2 peer. + * + * @exception GSSException may be thrown + */ + public void _dispose () throws GSSException; +} + + diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSException.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSException.java new file mode 100644 index 0000000000..5a09976344 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSException.java @@ -0,0 +1,382 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +/** + * This exception is thrown whenever a fatal GSS-API error occurs + * including mechanism specific errors. It contains + * both the major and minor JGSS status codes. The mechanism + * implementers are responsible for setting appropriate minor status + * codes when throwing this exception. Methods are included to retrieve + * the error string representation for both major and minor codes. + *

RFC 2078 + *
GSS-API major status codes are divided into fatal and + * informatory status codes. In JGSS, fatal codes are represented using + * exceptions of this class, and informatory codes are returned through + * instances of the MesssageProp class used in the GSSContext methods. + * This class also provides the functionality of gss_display_status.
+ * @see MessageProp + * @see GSSContext#unwrap + * @see GSSContext#verifyMIC + */ +public class GSSException extends Exception { + + /** + * Channel bindings mismatch error. + */ + public static final int BAD_BINDINGS = 1; //start with 1 + + /** + * Unsupported mechanism requested error. + */ + public static final int BAD_MECH = 2; + + /** + * Invalid name provided error. + */ + public static final int BAD_NAME = 3; + + /** + * Name of unsupported type provided error. + */ + public static final int BAD_NAMETYPE = 4; + + /** + * Invalid status code error - this is the default status value. + */ + public static final int BAD_STATUS = 5; + + /** + * Token had invalid integrity check error. + */ + public static final int BAD_MIC = 6; + + /** + * Specified security context expired error. + */ + public static final int CONTEXT_EXPIRED = 7; + + /** + * Expired credentials detected error. + */ + public static final int CREDENTIALS_EXPIRED = 8; + + /** + * Defective credential error. + */ + public static final int DEFECTIVE_CREDENTIAL = 9; + + /** + * Defective token error. + */ + public static final int DEFECTIVE_TOKEN = 10; + + /** + * General failure, unspecified at GSS-API level. + */ + public static final int FAILURE = 11; + + /** + * Invalid security context error. + */ + public static final int NO_CONTEXT = 12; + + /** + * Invalid credentials error. + */ + public static final int NO_CRED = 13; + + /** + * Unsupported QOP value error. + */ + public static final int BAD_QOP = 14; + + /** + * Operation unauthorized error. + */ + public static final int UNAUTHORIZED = 15; + + /** + * Operation unavailable error. + */ + public static final int UNAVAILABLE = 16; + + /** + * Duplicate credential element requested error. + */ + public static final int DUPLICATE_ELEMENT = 17; + + /** + * Name contains multi-mechanism elements error. + */ + public static final int NAME_NOT_MN = 18; + + + /** + * The token was a duplicate of an earlier token. + * This is a fatal error code that may occur during + * context establishment. It is not used to indicate + * supplementary status values. The MessageProp object is + * used for that purpose. + */ + public static final int DUPLICATE_TOKEN = 19; + + + /** + * The token's validity period has expired. This is a + * fatal error code that may occur during context establishment. + * It is not used to indicate supplementary status values. + * The MessageProp object is used for that purpose. + */ + public static final int OLD_TOKEN = 20; + + + /** + * A later token has already been processed. This is a + * fatal error code that may occur during context establishment. + * It is not used to indicate supplementary status values. + * The MessageProp object is used for that purpose. + */ + public static final int UNSEQ_TOKEN = 21; + + + /** + * An expected per-message token was not received. This is a + * fatal error code that may occur during context establishment. + * It is not used to indicate supplementary status values. + * The MessageProp object is used for that purpose. + */ + public static final int GAP_TOKEN = 22; + + + private static String[] messages = { + "channel binding mismatch", // BAD_BINDINGS + "unsupported mechanism requested", // BAD_MECH + "invalid name provided", // BAD_NAME + "name of unsupported type provided", //BAD_NAMETYPE + "invalid input status selector", // BAD_STATUS + "token had invalid integrity check", // BAD_SIG + "specified security context expired", // CONTEXT_EXPIRED + "expired credentials detected", // CREDENTIALS_EXPIRED + "defective credential detected", // DEFECTIVE_CREDENTIAL + "defective token detected", // DEFECTIVE_TOKEN + "failure, unspecified at GSS-API level", // FAILURE + "security context init/accept not yet called or context deleted", + // NO_CONTEXT + "no valid credentials provided", // NO_CRED + "unsupported QOP value", // BAD_QOP + "operation unauthorized", // UNAUTHORIZED + "operation unavailable", // UNAVAILABLE + "duplicate credential element requested", //DUPLICATE_ELEMENT + "name contains multi-mechanism elements", // NAME_NOT_MN + "the token was a duplicate of an earlier token", //DUPLICATE_TOKEN + "the token's validity period has expired", //OLD_TOKEN + "a later token has already been processed", //UNSEQ_TOKEN + "an expected per-message token was not received", //GAP_TOKEN + }; + + private int m_major; // the major code for this exception + private int m_minor = 0; // the minor code for this exception + private String m_minorMessage = null; //text string for minor code + + + /** + * Construct a GSSException object with a specified major code. + * + * @param majorCode the fatal error code causing this exception. + * This value should be one of the ones defined in this + * class. Invalid error codes get mapped to BAD_STATUS value. + */ + public GSSException (int majorCode) { + + if (validateMajor(majorCode)) + m_major = majorCode; + else + m_major = BAD_STATUS; + } + + /** + * Construct a GSSException object with a specified major and + * minor codes and minor explanation string. + * + * @param majorCode the fatal error code causing this exception. + * This value should be one of the ones defined in this class. + * Invalid error codes get mapped to BAD_STATUS value. + * @param minorCode the mechanism specific error code. + * @param minorString explanation of the minorCode. + */ + public GSSException (int majorCode, int minorCode, String minorString) { + + if (validateMajor(majorCode)) + m_major = majorCode; + else + m_major = BAD_STATUS; + + m_minor = minorCode; + m_minorMessage = minorString; + } + + /** + * Returns the major code representing the error that caused this + * exception to be thrown. + * + *
RFC 2078 + *
equivalent to major code being returned from function + *
+ * @return int the fatal error code causing this exception + * @see #getMajorString + */ + public int getMajor() { + + return m_major; + } + + /** + * Returns the mechanism error that caused this exception. The + * minor code is set by the underlying mechanism. Value of 0 + * indicates that mechanism error code is not set. + * + *
RFC 2078 + *
equivalent to minor status codes in GSS-API functions + *
+ * + * @return int the mechanism error code; 0 indicates that it has + * not been set. + * @see #setMinor + * @see #getMinorString + */ + public int getMinor(){ + + return m_minor; + } + + + /** + * Returns a string explaining the major code in this exception. + * + *
RFC 2078 + *
equivalent to gss_display_status for the major error + * code.
+ * @return String explanation string for the major error code + * @see #getMajor + * @see #toString + */ + public String getMajorString() { + + return messages[m_major - 1]; + } + + + /** + * Returns a string explaining the mechanism specific error code. + * Can be used with the getMajorString call to provide mechanism + * specific error details. If the minor status code is 0, then + * no other error details will be available. + * + *
RFC 2078 + *
equivalent to gss_display_status for the minor code. + *
+ * @return String a textual explanation of mechanism error code + * @see #getMinor + * @see #getMajorString + * @see #toString + */ + public String getMinorString() { + + if (m_minorMessage == null) + m_minorMessage = ""; + + return m_minorMessage; + } + + + /** + * Used by the exception thrower to set the mechanism error code + * and its string explanation. This is used by mechanism + * providers to indicate error details. + * + * @param minorCode the mechanism specific error code + * @param message textual explanation of the mechanism error code + */ + public void setMinor(int minorCode, String message) { + + m_minor = minorCode; + m_minorMessage = message; + } + + + /** + * Returns string representing both the major and minor status + * codes. + * + * @return a String with the error descriptions + * @overrides Object#toString + */ + public String toString() { + + if (m_minor == 0) + return (getMajorString()); + + return (getMajorString() + "(" + getMinorString() + ")"); + } + + + /** + * Returns string representing both the major and minor status + * codes. + * + * @return a String with the error descriptions + * @overrides Throwable#geMessage + */ + public String getMessage() { + + return (toString()); + } + + + /* + * Validates the major code in the proper range. + */ + private boolean validateMajor(int major) { + + if (m_major > 0 && m_major <= messages.length) + return (true); + + return (false); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSManager.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSManager.java new file mode 100644 index 0000000000..7278cae45f --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSManager.java @@ -0,0 +1,725 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.io.*; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; +import java.util.Hashtable; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.Enumeration; +import java.util.ResourceBundle; + +/** + * This class implements functionality common to the entire GSS-API + * package. This includes the management of the gss mechanisms + * and their providers. + *

RFC 2078 + *
A side from JGSS provider management, this class + * implements the equivalent of the following GSS-API routines: + *
  • gss_indicate_mechs + *
  • gss_inquire_mechs_for_name + *
  • gss_inquire_name_for_mech
+ */ + +public class GSSManager { + + static { + initialize(); + } + + private static void initialize() { + int i = 1; + + try { + ResourceBundle props = ResourceBundle.getBundle( + "com.sun.gssapi.mechs"); + + while (true) { + + String name = props.getString("gss.provider." + i++); + if (name == null) { + break; + } else { + Class cl = Class.forName(name); + Object instance = cl.newInstance(); + if (instance instanceof Provider) { + Security.addProvider((Provider)instance); + } else { + // This is not a valid Provider + } + } + } + } catch (Exception e) { + // no-op + } + } + + /** + * Indicates which mechanisms are configured within JGSS. + *

RFC 2078 + *
equivalent to gss_indicate_mechs
+ * + * @return array of Oids indicating available mechanisms; + * null when no mechanism are available + */ + public static Oid[] getMechs() { + + /* + * Go through all the providers and retrieve jgss ones + * note we skip the ProviderTable, because we want all + * jgss providers not just ones loaded. + */ + Provider [] p = java.security.Security.getProviders(); + Vector aV = new Vector(5, 3); + + for (int i = 0; i < p.length; i++) { + String []mechs = MechInfo.getMechsForProvider(p[i]); + + if (mechs == null) + continue; + + for (int j=0; j < mechs.length; j++) { + try { + addUniqueOid(aV, new Oid(mechs[j])); + } catch (GSSException e) {} + } + } + + if (aV.size() == 0) + return (null); + + Oid []mechs = new Oid[aV.size()]; + aV.copyInto(mechs); + return (mechs); + } + + + /** + * Returns name types (Oids) supported by the selected mechanism. + * Note that in cases where several providers implement the same + * mechanism, only the first provider implementing the mechanism + * is queried. + *

RFC 2078 + *
equivalent to gss_inquire_names_for_mech
+ * + * @param mech the Oid for mechanism to be queried + * @return names array of Oids indicating names supported by the + * requested mechanism; or null if the mech is not supported + * @exception GSSException with major code of BAD_MECH will be thrown + * for invalid mechanism oids + */ + public static Oid[] getNamesForMech(Oid mech) throws GSSException { + + MechInfo aMech = getMechInfo(mech, false); + + return (aMech.getNames()); + } + + + /** + * Returns all the mechanisms that support the specific name type. + *

+ *

RFC 2078 + *
equivalent to gss_inquire_mechs_for_name
+ * + * @param nameType the Oid of the name type to be queried + * @return mechs an array of mechanism Oids supporting the + * requested name type; null if no mechanism supports the + * requested name type + */ + public static Oid[] getMechsForName(Oid nameType) { + + Provider []p = java.security.Security.getProviders(); + Vector v = new Vector(5,3); + + for (int i = 0; i < p.length; i++) { + MechInfo [] mechs = MechInfo.getInfoForAllMechs(p[i]); + + if (mechs == null) + continue; + + for (int j = 0; j < mechs.length; j++) { + + if (mechs[j].supportsName(nameType)) + addUniqueOid(v, mechs[j].getOid()); + } + } + + if (v.size() == 0) + return (null); + + Oid [] oids = new Oid[v.size()]; + v.copyInto(oids); + return (oids); + } + + + /** + * Determines the default mechanism. The default mechanism is + * determined through the setting in the security properties file + * when the provider is installed or through dynamic configuration + * of the providers.. The default mech is the first mechanism in + * the first jgss provider. + * @return the Oid for the default mechanism + * @exception GSSException with major code set to BAD_MECH if + * no jgss providers exist. + */ + public static Oid getDefaultMech() throws GSSException { + + if (m_defaultMech != null) + return (m_defaultMech.getOid()); + + Provider []p = java.security.Security.getProviders(); + + //check each provider + for (int i = 0; i < p.length; i++) { + String []mechs = MechInfo.getMechsForProvider(p[i]); + + if (mechs == null) + continue; + + m_defaultMech = new MechInfo(p[i], mechs[0]); + return (m_defaultMech.getOid()); + } + + throw new GSSException(GSSException.BAD_MECH); + } + + + /** + * Adds only unique values to the specified vector. + * @param v - vector to add to + * @param oid - the oid to add + */ + private static void addUniqueOid(Vector v, Oid anOid) { + + for (Enumeration e = v.elements(); e.hasMoreElements();) { + if ( ((Oid)e.nextElement()).equals(anOid)) + return; + } + v.addElement(anOid); + } + + + /** + * Returns a provider specific implementation of the credential + * object. + */ + static GSSCredSpi getCredInstance(Oid mech) throws GSSException { + + //get mech out of the mech table, and if need be load it + MechInfo aMech = getMechInfo(mech, true); + return (aMech.getCredInstance()); + } + + + /** + * Returns a provider specific implementation of the name + * object. + */ + static GSSNameSpi getNameInstance(Oid mech) throws GSSException { + + //get mech out of the mech table, and if need be load it + MechInfo aMech = getMechInfo(mech, true); + return (aMech.getNameInstance()); + } + + + /** + * Returns a provider specific implementation of the C018FE95 + * object. + */ + static C018FE95 _M4092FBA (Oid mech) throws GSSException { + + //get mech out of the mech table, and if need be load it + MechInfo aMech = getMechInfo(mech, true); + return (aMech._M4092FBA ()); + } + + + /** + * Obtains the MechInfo object for the specified mechanism. + * + * @param installMech this boolean indicates if the mechanism + * should be loaded if it isn't already + */ + private static synchronized MechInfo getMechInfo(Oid oid, + boolean installMech) throws GSSException { + + //look in the hash table first + MechInfo aMech = MechTable.getMechInfo(oid); + if (aMech != null) { + if (installMech) + MechTable.putMechInfo(aMech); + return (aMech); + } + + //need to search all providers + Provider [] p = java.security.Security.getProviders(); + String mechString = oid.toString(); + + for (int i=0; i < p.length; i++) { + + if (MechInfo.implementsMech(p[i], mechString)) { + + try { + aMech = new MechInfo(p[i], mechString); + + if (installMech) + MechTable.putMechInfo(aMech); + + return (aMech); + } catch (GSSException e) { + + //skip over this provider, there might be + //other good ones + continue; + } + } + } + + //this mechanism is not installed on the system + throw new GSSException(GSSException.BAD_MECH); + } + + + /** + * Debug method. + */ + private static void showProviderDetails() { + + Provider [] p = java.security.Security.getProviders(); + MechInfo [] mechs; + boolean foundGSSProv = false; + + for (int i = 0; i < p.length; i++ ) { + mechs = MechInfo.getInfoForAllMechs(p[i]); + if (mechs == null) + continue; + + foundGSSProv = true; + } + } + + //private class variable - default mechanism oid + private static MechInfo m_defaultMech; +} // end of Class GSSManager + + +/** + * Class to store mechanism information extracted from the providers. + * It contains all the provider parsing code. + */ +class MechInfo { + + //hides the default constructor + private MechInfo() { + + } + + /** + * Constructor to populate the object with information from + * the provider. + * @param p - the provider to be queried for mechanism info + * @param oid - the mechanism which the provider is to be + * queried for + * @exception GSSException with major status of BAD_MECH when + * this provider does not implement the specified mechanism + */ + MechInfo(Provider p, String oid) throws GSSException { + + String aStr; + + m_oid = new Oid(oid); + _V510CA83 = p; + updateOidAlias(p, oid); + if ((aStr = _M73F1AC8 (p, oid, "_K872D1AC")) != null) { + StringTokenizer st = new StringTokenizer(aStr, ":"); + m_names = new Oid[st.countTokens()]; + int i = 0; + while (st.hasMoreTokens()) { + m_names[i] = new Oid(st.nextToken()); + i++; + } + } else + throw new GSSException(GSSException.BAD_MECH); + + _V2395ABD = _M73F1AC8 (p, oid, "_K532D1BD"); + _V108CA91 = _M73F1AC8 (p, oid, "_K1000A49"); + _V901D6C2 = _M73F1AC8 (p, oid, "_K2102CC5"); + + if (_V2395ABD == null || _V108CA91 == null + || _V901D6C2 == null) + throw new GSSException(GSSException.BAD_MECH); + } + + + /** + * Checks if this mechanism supports the supplied name oid. + * @param nameOid - the oid for name to be checked + * in dot notation + * @return true if name type is supported, false otherwise + */ + boolean supportsName(Oid nameOid) { + + for (int i = 0; i < m_names.length; i++) { + if (m_names[i].equals(nameOid)) + return (true); + } + return (false); + } + + + /** + * Returns the names supported by this mech. + */ + Oid[] getNames() { + + return (m_names); + } + + + /** + * Returns the oid for this mechanism. + */ + Oid getOid() { + + return (m_oid); + } + + + /** + * Returns an instance of the class implementing the GSSCredSpi + * interface for this mechanism. + */ + GSSCredSpi getCredInstance() throws GSSException { + + try { + if (_V29ED8BF == null) { + + //create the class object + _V29ED8BF = Class.forName(_V901D6C2); + } + + return ((GSSCredSpi)_V29ED8BF.newInstance()); + + } catch (Exception e) { + throw new GSSException(GSSException.UNAVAILABLE); + } + } + + + /** + * Returns an instance of the class implementing the C018FE95 + * interface for this mechanism. + */ + C018FE95 _M4092FBA () throws GSSException { + + try { + if (_V30FDA16 == null) { + + //create the class object + _V30FDA16 = Class.forName(_V108CA91); + } + + return ((C018FE95)_V30FDA16.newInstance()); + + } catch (Exception e) { + throw new GSSException(GSSException.UNAVAILABLE); + } + } + + + /** + * Returns an instance of the class implementing the JGSSNameSpi + * interface for this mechanism. + */ + GSSNameSpi getNameInstance() throws GSSException { + + try { + if (_V80013BE == null) { + + //create the class object + _V29ED8BF = Class.forName(_V2395ABD); + } + + return ((GSSNameSpi)_V29ED8BF.newInstance()); + + } catch (Exception e) { + throw new GSSException(GSSException.UNAVAILABLE); + } + } + + + /** + * Returns the provider for this mechanism. + * + * @return p - provider for this mechanism. + */ + Provider getProvider() { + + return (_V510CA83); + } + + + /** + * Returns a provider value for the given key. + * Both alias and oid is attempted to get the value. + * @param provider to query + * @param mechanism oid to be queried + * @param key for the value to retrieve (JGSS.Mech. is prepended to it) + * @return the value from the provider for the give mechanism and key + */ + private static String _M73F1AC8 (Provider p, String _V0095DCA, + String key) { + + String aStr; + + if ((aStr = p.getProperty("JGSS.Mech." + _V0095DCA + "." + key)) + != null) { + return (aStr); + } + + if ((aStr = oidStrToAlias(_V0095DCA)) == null) + return null; + + return (p.getProperty("JGSS.Mech." + aStr + "." + key)); + } + + + /** + * Returns the alias name for the passed in mechanism oid. + * @param mechanism oid in dot notation + * @return alias name for the oid; null if not found + */ + private static String oidStrToAlias(String _V0095DCA) { + + return M_oidAlias.getProperty(_V0095DCA); + } + + + /** + * Returns the oid string for the given alias. + * @return oid str in dot notation for the supplied alias name; + * null if it does net exist + */ + private static String aliasToOidStr(String mechAlias) { + + return M_oidAlias.getProperty(mechAlias); + } + + + /** + * Updates the oid <--> alias mapping. + * If the mapping already exists, it is *not* replaced. + */ + private static synchronized void updateOidAlias(Provider p, + String _V0095DCA) { + + //check if mapping already exists + if (M_oidAlias.getProperty(_V0095DCA) != null) + return; + + String aStr = p.getProperty("JGSS.Mech." + _V0095DCA + ".Alias"); + if (aStr != null) { + M_oidAlias.put(_V0095DCA, aStr); + M_oidAlias.put(aStr, _V0095DCA); + } + } + + + /** + * Queries if this is a JGSS provider implementing the + * specified oid. + */ + static boolean implementsMech(Provider p, String oid) { + + String [] mechs = getMechsForProvider(p); + + if (mechs == null) + return (false); + + for (int i = 0; i < mechs.length; i++) { + if (mechs[i].equals(oid)) + return (true); + } + + return (false); + } + + + /** + * Creates MechInfo objects for all the mechs this + * provider supports. + */ + static MechInfo[] getInfoForAllMechs(Provider p) { + + String mechsStr = p.getProperty("JGSS.Mechs"); + + //does this provider even support JGSS ? + if (mechsStr == null) + return (null); + + StringTokenizer st = new StringTokenizer(mechsStr, ":"); + MechInfo[] mInfo = new MechInfo[st.countTokens()]; + for (int i = 0; i < mInfo.length; i++) { + try { + mInfo[i] = new MechInfo(p, st.nextToken()); + } catch (GSSException e) { + } + } + + return (mInfo); + } + + + /** + * Queries the provider for all the mechanisms it offers + * @return mechs - the mechanism oids this provider offers + */ + static String[] getMechsForProvider(Provider p) { + + String aStr; + if ((aStr = p.getProperty("JGSS.Mechs")) != null ) { + + //get the supported mechs - there may be more then one + StringTokenizer st = new StringTokenizer(aStr,":"); + String[] res = new String[st.countTokens()]; + for (int i = 0; i < res.length; i++) + res[i] = st.nextToken(); + return (res); + } + return (null); + } + + + /** + * Returns string with mechanism information. + */ + public String toString() { + + StringBuffer aBuf = new StringBuffer(100); + + aBuf.append("Mechanism oid:\t").append(m_oid); + aBuf.append("\nMechanism alias:\t").append( + oidStrToAlias(m_oid.toString())); + aBuf.append("\nMy provider: "); + if (_V510CA83 == null) + aBuf.append("null"); + else + aBuf.append(_V510CA83.getInfo()); + aBuf.append("\nSupported Names:\t"); + + for(int i = 0; i < m_names.length; i++) + aBuf.append(m_names[i].toString()).append(" "); + + aBuf.append("\nName Class:\t").append(_V2395ABD); + aBuf.append("\nCred Class:\t").append(_V901D6C2); + aBuf.append("\nCtxt Class:\t").append(_V108CA91); + + return (aBuf.toString()); + } + + //instance variables + private Oid m_oid; //oid for this mech + private Oid []m_names; //oids for names supported by the mech + private String _V2395ABD; //name of the name class + private String _V108CA91; //name of the ctxt class + private String _V901D6C2; //name of the credential class + private Provider _V510CA83; //provider for this mech + private Class _V80013BE; //class implementing name + private Class _V29ED8BF; //class implementing cred + private Class _V30FDA16; //class implementing ctxt + + //class variables + private static Properties M_oidAlias; //oid <-> alias mapping + + static { + M_oidAlias = new Properties(); + } +} + +/* + * Package private class that stores Oid -> MechInfo mapping for jgss + * Only loaded mechanisms are in this table. + */ +class MechTable { + + /** + * Hide constructor + */ + private MechTable() { } + + + /** + * Returns mechanism info for the specified oid. null if + * it does not exit. + */ + static MechInfo getMechInfo(Oid oid) { + + return ((MechInfo)M_table.get(oid)); + } + + + /** + * Puts the mapping for a mechanism into the table. + * If the mechanism is already in the table, it is not + * updated. Returns boolean indicating if the mechanism + * information was stored. + */ + static boolean putMechInfo(MechInfo aMech) { + + if (M_table.containsKey(aMech.getOid())) + return (false); + + M_table.put(aMech.getOid(), aMech); + return (true); + } + + + //private table storing the mapping + private static Hashtable M_table; + + static { + M_table = new Hashtable(13); + } +} //end of Class MechTable diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSManager.m4 b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSManager.m4 new file mode 100644 index 0000000000..d1bdd04069 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSManager.m4 @@ -0,0 +1,725 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.io.*; +import java.security.NoSuchProviderException; +import java.security.Provider; +import java.security.Security; +import java.util.Hashtable; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.Enumeration; +import java.util.ResourceBundle; + +/** + * This class implements functionality common to the entire GSS-API + * package. This includes the management of the gss mechanisms + * and their providers. + *

RFC 2078 + *
A side from JGSS provider management, this class + * implements the equivalent of the following GSS-API routines: + *
  • gss_indicate_mechs + *
  • gss_inquire_mechs_for_name + *
  • gss_inquire_name_for_mech
+ */ + +public class GSSManager { + + static { + initialize(); + } + + private static void initialize() { + int i = 1; + + try { + ResourceBundle props = ResourceBundle.getBundle( + "com.sun.gssapi.mechs"); + + while (true) { + + String name = props.getString("gss.provider." + i++); + if (name == null) { + break; + } else { + Class cl = Class.forName(name); + Object instance = cl.newInstance(); + if (instance instanceof Provider) { + Security.addProvider((Provider)instance); + } else { + // This is not a valid Provider + } + } + } + } catch (Exception e) { + // no-op + } + } + + /** + * Indicates which mechanisms are configured within JGSS. + *

RFC 2078 + *
equivalent to gss_indicate_mechs
+ * + * @return array of Oids indicating available mechanisms; + * null when no mechanism are available + */ + public static Oid[] getMechs() { + + /* + * Go through all the providers and retrieve jgss ones + * note we skip the ProviderTable, because we want all + * jgss providers not just ones loaded. + */ + Provider [] p = java.security.Security.getProviders(); + Vector aV = new Vector(5, 3); + + for (int i = 0; i < p.length; i++) { + String []mechs = MechInfo.getMechsForProvider(p[i]); + + if (mechs == null) + continue; + + for (int j=0; j < mechs.length; j++) { + try { + addUniqueOid(aV, new Oid(mechs[j])); + } catch (GSSException e) {} + } + } + + if (aV.size() == 0) + return (null); + + Oid []mechs = new Oid[aV.size()]; + aV.copyInto(mechs); + return (mechs); + } + + + /** + * Returns name types (Oids) supported by the selected mechanism. + * Note that in cases where several providers implement the same + * mechanism, only the first provider implementing the mechanism + * is queried. + *

RFC 2078 + *
equivalent to gss_inquire_names_for_mech
+ * + * @param mech the Oid for mechanism to be queried + * @return names array of Oids indicating names supported by the + * requested mechanism; or null if the mech is not supported + * @exception GSSException with major code of BAD_MECH will be thrown + * for invalid mechanism oids + */ + public static Oid[] getNamesForMech(Oid mech) throws GSSException { + + MechInfo aMech = getMechInfo(mech, false); + + return (aMech.getNames()); + } + + + /** + * Returns all the mechanisms that support the specific name type. + *

+ *

RFC 2078 + *
equivalent to gss_inquire_mechs_for_name
+ * + * @param nameType the Oid of the name type to be queried + * @return mechs an array of mechanism Oids supporting the + * requested name type; null if no mechanism supports the + * requested name type + */ + public static Oid[] getMechsForName(Oid nameType) { + + Provider []p = java.security.Security.getProviders(); + Vector v = new Vector(5,3); + + for (int i = 0; i < p.length; i++) { + MechInfo [] mechs = MechInfo.getInfoForAllMechs(p[i]); + + if (mechs == null) + continue; + + for (int j = 0; j < mechs.length; j++) { + + if (mechs[j].supportsName(nameType)) + addUniqueOid(v, mechs[j].getOid()); + } + } + + if (v.size() == 0) + return (null); + + Oid [] oids = new Oid[v.size()]; + v.copyInto(oids); + return (oids); + } + + + /** + * Determines the default mechanism. The default mechanism is + * determined through the setting in the security properties file + * when the provider is installed or through dynamic configuration + * of the providers.. The default mech is the first mechanism in + * the first jgss provider. + * @return the Oid for the default mechanism + * @exception GSSException with major code set to BAD_MECH if + * no jgss providers exist. + */ + public static Oid getDefaultMech() throws GSSException { + + if (m_defaultMech != null) + return (m_defaultMech.getOid()); + + Provider []p = java.security.Security.getProviders(); + + //check each provider + for (int i = 0; i < p.length; i++) { + String []mechs = MechInfo.getMechsForProvider(p[i]); + + if (mechs == null) + continue; + + m_defaultMech = new MechInfo(p[i], mechs[0]); + return (m_defaultMech.getOid()); + } + + throw new GSSException(GSSException.BAD_MECH); + } + + + /** + * Adds only unique values to the specified vector. + * @param v - vector to add to + * @param oid - the oid to add + */ + private static void addUniqueOid(Vector v, Oid anOid) { + + for (Enumeration e = v.elements(); e.hasMoreElements();) { + if ( ((Oid)e.nextElement()).equals(anOid)) + return; + } + v.addElement(anOid); + } + + + /** + * Returns a provider specific implementation of the credential + * object. + */ + static GSSCredSpi getCredInstance(Oid mech) throws GSSException { + + //get mech out of the mech table, and if need be load it + MechInfo aMech = getMechInfo(mech, true); + return (aMech.getCredInstance()); + } + + + /** + * Returns a provider specific implementation of the name + * object. + */ + static GSSNameSpi getNameInstance(Oid mech) throws GSSException { + + //get mech out of the mech table, and if need be load it + MechInfo aMech = getMechInfo(mech, true); + return (aMech.getNameInstance()); + } + + + /** + * Returns a provider specific implementation of the GSSCtxtSpi + * object. + */ + static GSSCtxtSpi getCtxtInstance (Oid mech) throws GSSException { + + //get mech out of the mech table, and if need be load it + MechInfo aMech = getMechInfo(mech, true); + return (aMech.getCtxtInstance ()); + } + + + /** + * Obtains the MechInfo object for the specified mechanism. + * + * @param installMech this boolean indicates if the mechanism + * should be loaded if it isn't already + */ + private static synchronized MechInfo getMechInfo(Oid oid, + boolean installMech) throws GSSException { + + //look in the hash table first + MechInfo aMech = MechTable.getMechInfo(oid); + if (aMech != null) { + if (installMech) + MechTable.putMechInfo(aMech); + return (aMech); + } + + //need to search all providers + Provider [] p = java.security.Security.getProviders(); + String mechString = oid.toString(); + + for (int i=0; i < p.length; i++) { + + if (MechInfo.implementsMech(p[i], mechString)) { + + try { + aMech = new MechInfo(p[i], mechString); + + if (installMech) + MechTable.putMechInfo(aMech); + + return (aMech); + } catch (GSSException e) { + + //skip over this provider, there might be + //other good ones + continue; + } + } + } + + //this mechanism is not installed on the system + throw new GSSException(GSSException.BAD_MECH); + } + + + /** + * Debug method. + */ + private static void showProviderDetails() { + + Provider [] p = java.security.Security.getProviders(); + MechInfo [] mechs; + boolean foundGSSProv = false; + + for (int i = 0; i < p.length; i++ ) { + mechs = MechInfo.getInfoForAllMechs(p[i]); + if (mechs == null) + continue; + + foundGSSProv = true; + } + } + + //private class variable - default mechanism oid + private static MechInfo m_defaultMech; +} // end of Class GSSManager + + +/** + * Class to store mechanism information extracted from the providers. + * It contains all the provider parsing code. + */ +class MechInfo { + + //hides the default constructor + private MechInfo() { + + } + + /** + * Constructor to populate the object with information from + * the provider. + * @param p - the provider to be queried for mechanism info + * @param oid - the mechanism which the provider is to be + * queried for + * @exception GSSException with major status of BAD_MECH when + * this provider does not implement the specified mechanism + */ + MechInfo(Provider p, String oid) throws GSSException { + + String aStr; + + m_oid = new Oid(oid); + m_myP = p; + updateOidAlias(p, oid); + if ((aStr = getProvValue (p, oid, "NAMES")) != null) { + StringTokenizer st = new StringTokenizer(aStr, ":"); + m_names = new Oid[st.countTokens()]; + int i = 0; + while (st.hasMoreTokens()) { + m_names[i] = new Oid(st.nextToken()); + i++; + } + } else + throw new GSSException(GSSException.BAD_MECH); + + m_nameClassName = getProvValue (p, oid, "NAME"); + m_ctxtClassName = getProvValue (p, oid, "CONTEXT"); + m_credClassName = getProvValue (p, oid, "CRED"); + + if (m_nameClassName == null || m_ctxtClassName == null + || m_credClassName == null) + throw new GSSException(GSSException.BAD_MECH); + } + + + /** + * Checks if this mechanism supports the supplied name oid. + * @param nameOid - the oid for name to be checked + * in dot notation + * @return true if name type is supported, false otherwise + */ + boolean supportsName(Oid nameOid) { + + for (int i = 0; i < m_names.length; i++) { + if (m_names[i].equals(nameOid)) + return (true); + } + return (false); + } + + + /** + * Returns the names supported by this mech. + */ + Oid[] getNames() { + + return (m_names); + } + + + /** + * Returns the oid for this mechanism. + */ + Oid getOid() { + + return (m_oid); + } + + + /** + * Returns an instance of the class implementing the GSSCredSpi + * interface for this mechanism. + */ + GSSCredSpi getCredInstance() throws GSSException { + + try { + if (m_credClass == null) { + + //create the class object + m_credClass = Class.forName(m_credClassName); + } + + return ((GSSCredSpi)m_credClass.newInstance()); + + } catch (Exception e) { + throw new GSSException(GSSException.UNAVAILABLE); + } + } + + + /** + * Returns an instance of the class implementing the GSSCtxtSpi + * interface for this mechanism. + */ + GSSCtxtSpi getCtxtInstance () throws GSSException { + + try { + if (m_ctxtClass == null) { + + //create the class object + m_ctxtClass = Class.forName(m_ctxtClassName); + } + + return ((GSSCtxtSpi)m_ctxtClass.newInstance()); + + } catch (Exception e) { + throw new GSSException(GSSException.UNAVAILABLE); + } + } + + + /** + * Returns an instance of the class implementing the JGSSNameSpi + * interface for this mechanism. + */ + GSSNameSpi getNameInstance() throws GSSException { + + try { + if (m_nameClass == null) { + + //create the class object + m_credClass = Class.forName(m_nameClassName); + } + + return ((GSSNameSpi)m_credClass.newInstance()); + + } catch (Exception e) { + throw new GSSException(GSSException.UNAVAILABLE); + } + } + + + /** + * Returns the provider for this mechanism. + * + * @return p - provider for this mechanism. + */ + Provider getProvider() { + + return (m_myP); + } + + + /** + * Returns a provider value for the given key. + * Both alias and oid is attempted to get the value. + * @param provider to query + * @param mechanism oid to be queried + * @param key for the value to retrieve (JGSS.Mech. is prepended to it) + * @return the value from the provider for the give mechanism and key + */ + private static String getProvValue (Provider p, String mechOid, + String key) { + + String aStr; + + if ((aStr = p.getProperty("JGSS.Mech." + mechOid + "." + key)) + != null) { + return (aStr); + } + + if ((aStr = oidStrToAlias(mechOid)) == null) + return null; + + return (p.getProperty("JGSS.Mech." + aStr + "." + key)); + } + + + /** + * Returns the alias name for the passed in mechanism oid. + * @param mechanism oid in dot notation + * @return alias name for the oid; null if not found + */ + private static String oidStrToAlias(String mechOid) { + + return M_oidAlias.getProperty(mechOid); + } + + + /** + * Returns the oid string for the given alias. + * @return oid str in dot notation for the supplied alias name; + * null if it does net exist + */ + private static String aliasToOidStr(String mechAlias) { + + return M_oidAlias.getProperty(mechAlias); + } + + + /** + * Updates the oid <--> alias mapping. + * If the mapping already exists, it is *not* replaced. + */ + private static synchronized void updateOidAlias(Provider p, + String mechOid) { + + //check if mapping already exists + if (M_oidAlias.getProperty(mechOid) != null) + return; + + String aStr = p.getProperty("JGSS.Mech." + mechOid + ".Alias"); + if (aStr != null) { + M_oidAlias.put(mechOid, aStr); + M_oidAlias.put(aStr, mechOid); + } + } + + + /** + * Queries if this is a JGSS provider implementing the + * specified oid. + */ + static boolean implementsMech(Provider p, String oid) { + + String [] mechs = getMechsForProvider(p); + + if (mechs == null) + return (false); + + for (int i = 0; i < mechs.length; i++) { + if (mechs[i].equals(oid)) + return (true); + } + + return (false); + } + + + /** + * Creates MechInfo objects for all the mechs this + * provider supports. + */ + static MechInfo[] getInfoForAllMechs(Provider p) { + + String mechsStr = p.getProperty("JGSS.Mechs"); + + //does this provider even support JGSS ? + if (mechsStr == null) + return (null); + + StringTokenizer st = new StringTokenizer(mechsStr, ":"); + MechInfo[] mInfo = new MechInfo[st.countTokens()]; + for (int i = 0; i < mInfo.length; i++) { + try { + mInfo[i] = new MechInfo(p, st.nextToken()); + } catch (GSSException e) { + } + } + + return (mInfo); + } + + + /** + * Queries the provider for all the mechanisms it offers + * @return mechs - the mechanism oids this provider offers + */ + static String[] getMechsForProvider(Provider p) { + + String aStr; + if ((aStr = p.getProperty("JGSS.Mechs")) != null ) { + + //get the supported mechs - there may be more then one + StringTokenizer st = new StringTokenizer(aStr,":"); + String[] res = new String[st.countTokens()]; + for (int i = 0; i < res.length; i++) + res[i] = st.nextToken(); + return (res); + } + return (null); + } + + + /** + * Returns string with mechanism information. + */ + public String toString() { + + StringBuffer aBuf = new StringBuffer(100); + + aBuf.append("Mechanism oid:\t").append(m_oid); + aBuf.append("\nMechanism alias:\t").append( + oidStrToAlias(m_oid.toString())); + aBuf.append("\nMy provider: "); + if (m_myP == null) + aBuf.append("null"); + else + aBuf.append(m_myP.getInfo()); + aBuf.append("\nSupported Names:\t"); + + for(int i = 0; i < m_names.length; i++) + aBuf.append(m_names[i].toString()).append(" "); + + aBuf.append("\nName Class:\t").append(m_nameClassName); + aBuf.append("\nCred Class:\t").append(m_credClassName); + aBuf.append("\nCtxt Class:\t").append(m_ctxtClassName); + + return (aBuf.toString()); + } + + //instance variables + private Oid m_oid; //oid for this mech + private Oid []m_names; //oids for names supported by the mech + private String m_nameClassName; //name of the name class + private String m_ctxtClassName; //name of the ctxt class + private String m_credClassName; //name of the credential class + private Provider m_myP; //provider for this mech + private Class m_nameClass; //class implementing name + private Class m_credClass; //class implementing cred + private Class m_ctxtClass; //class implementing ctxt + + //class variables + private static Properties M_oidAlias; //oid <-> alias mapping + + static { + M_oidAlias = new Properties(); + } +} + +/* + * Package private class that stores Oid -> MechInfo mapping for jgss + * Only loaded mechanisms are in this table. + */ +class MechTable { + + /** + * Hide constructor + */ + private MechTable() { } + + + /** + * Returns mechanism info for the specified oid. null if + * it does not exit. + */ + static MechInfo getMechInfo(Oid oid) { + + return ((MechInfo)M_table.get(oid)); + } + + + /** + * Puts the mapping for a mechanism into the table. + * If the mechanism is already in the table, it is not + * updated. Returns boolean indicating if the mechanism + * information was stored. + */ + static boolean putMechInfo(MechInfo aMech) { + + if (M_table.containsKey(aMech.getOid())) + return (false); + + M_table.put(aMech.getOid(), aMech); + return (true); + } + + + //private table storing the mapping + private static Hashtable M_table; + + static { + M_table = new Hashtable(13); + } +} //end of Class MechTable diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSName.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSName.java new file mode 100644 index 0000000000..2fccd8e15e --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSName.java @@ -0,0 +1,598 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.util.Vector; +import java.util.Enumeration; + +/** + * An object of this class encapsulates a single GSS-API principal entity. + * Different name formats and their definitions are identified with + * universal Object Identifiers (Oids). The format of the names can be + * derived based on the unique oid of each name type. + *

+ * JGSS distinguishes between the following name representations: + *

    + *
  • Internal Form + * - A name representation which may contain name elements + * from different mechanisms. + *
  • Mechanism Name (MN) + * - A name representation containing one and only one + * mechanism name element. + *
  • Flat Name + * - A contiguous octet stream representation of a MN. + *
+ *
RFC 2078 + *
This class implements the following RFC 2078 functions: + *
  • gss_compare_name + *
  • gss_display_name + *
  • gss_import_name + *
  • gss_release_name
+ *
+ * @see Oid + */ + +public class GSSName { + + /** + * Name type used to indicate a host-based service name form. It + * is used to represent services associated with host computers. + * This name form is constructed using two elements, "service" and + * "hostname", as follows: service@hostname + *
+ * Values for the "service" element are registered with the IANA. + * It represents the following value: + *

{ 1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 2(gss-host-based-services) } + */ + public static final Oid NT_HOSTBASED_SERVICE; + + + /** + * Name type used to indicate a named user on a local system. It + * represents the following value: + *

+ * { iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) user_name(1) } + */ + public static final Oid NT_USER_NAME; + + + /** + * Name type used to indicate a numeric user identifier corresponding + * to a user on a local system. (e.g. Uid). It represents the + * following value: + *

+ * { iso(1) member-body(2) United States(840) mit(113554) infosys(1) + * gssapi(2) generic(1) machine_uid_name(2) } + */ + public static final Oid NT_MACHINE_UID_NAME; + + + /** + * Name type used to indicate a string of digits representing the + * numeric user identifier of a user on a local system. It + * represents the following value: + *

+ * { iso(1) member-body(2) United States(840) mit(113554) infosys(1) + * gssapi(2) generic(1) string_uid_name(3) } + */ + public static final Oid NT_STRING_UID_NAME; + + + /** + * Name type used to represent an Anonymous identity. It represents + * the following value: + *

+ * { 1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes), + * 3(gss-anonymous-name) } + */ + public static final Oid NT_ANONYMOUS; + + + /** + * Name type used to indicate an exported name produced by the + * export method. It represents the following value: + *

+ * { 1(iso), 3(org), 6(dod), 1(internet), 5(security), 6(nametypes), + * 4(gss-api-exported-name) } + */ + public static final Oid NT_EXPORT_NAME; + + //initialize the oid objects + static { + try { + NT_HOSTBASED_SERVICE = new Oid("1.3.6.1.5.6.2"); + NT_USER_NAME = new Oid("1.2.840.113554.1.2.1.1"); + NT_MACHINE_UID_NAME = new Oid("1.2.840.113554.1.2.1.2"); + NT_STRING_UID_NAME = new Oid("1.2.840.113554.1.2.1.3"); + NT_ANONYMOUS = new Oid("1.3.6.1.5.6.3"); + NT_EXPORT_NAME = new Oid("1.3.6.1.5.6.4"); + + } catch (GSSException e) { + + //because we are initializeing statics, we can + //only throw a standard runtime exception + throw new NumberFormatException(); + } + } + + + /** + * Converts a contiguous string name to a GSSName object + * of the specified type. The nameStr parameter is + * interpreted based on the type specified. + * In general, the GSSName object created will not be an MN; + * the exception to this is if the type parameter indicates + * NT_EXPORT_NAME. + *

+ *

RFC 2078
equivalent to gss_import_name
+ * @param nameStr the name to create + * @param type an oid specifying the name type + */ + public GSSName(String nameStr, Oid type) { + + m_nameStr = nameStr; + m_nameType = type; + } + + + /** + * Creates a new GSSName object from the specified type. It + * is envisioned that this constructor will be called with + * buffers returned from GSSName.export() or for name types + * that aren't represented by printable strings. + *
RFC 2078 + *
equivalent to gss_import_name
+ * @param name buffer containing name + * @param type an Oid specifying the name type + * @exception GSSException with possible major codes of + * BAD_NAMETYPE, BAD_NAME, or FAILURE. + * @see GSSName#GSSName(String,Oid) + * @see GSSName#GSSName(byte[],Oid,Oid) + * @see #export + */ + public GSSName(byte[] name, Oid type) throws GSSException { + + m_nameType = type; + m_nameBytes = new byte[name.length]; + System.arraycopy(name, 0, m_nameBytes, 0, name.length); + + //check if export name, which means we can load it right now + if (type.equals(NT_EXPORT_NAME)) { + if (name[0] != 0x04 && name[1] != 0x01) + throw new GSSException(GSSException.BAD_NAME); + + Oid mechOid = new Oid(name, 2); + GSSNameSpi mn = GSSManager.getNameInstance(mechOid); + mn.init(name, type); + addMechName(mn); + } + } + + + /** + * Creates a new GSSName object of the specified type. + * This constructor takes an additional mechanism oid parameter + * which allows the creation of a mechanism name in one step. + *

+ *

RFC 2078
equivalent to gss_import_name + * followed by gss_canonicalize_name
+ * @param nameStr the name to create + * @param nameType an oid specifying the name type + * @param mechType the oid of the mechanism to create this name for + * @exception GSSException with possible major codes of + * BAD_NAMETYPE, BAD_NAME, or FAILURE. + * @see GSSName#GSSName(String,Oid) + */ + public GSSName(String nameStr, Oid nameType, Oid mechType) + throws GSSException { + + m_nameStr = nameStr; + m_nameType = nameType; + GSSNameSpi mn = GSSManager.getNameInstance(mechType); + mn.init(nameStr, nameType); + addMechName(mn); + } + + + /** + * Creates a new GSSName object from the specified type. It + * is envisioned that this constructor will be called with + * buffers returned from GSSName.export() or for name types + * that aren't represented by printable strings. This constructor + * takes an additional parameter for the mechanism oid. + *
RFC 2078
+ * equivalent to gss_import_name followed by gss_canonicalize_name + *
+ * @param name buffer containing name + * @param nameType an Oid specifying the name type + * @param mechType an Oid for the mechanism to create this name for + * @exception GSSException with possible major codes of + * BAD_NAMETYPE, BAD_NAME, or FAILURE. + * @see GSSName#GSSName(String,Oid) + * @see GSSName#GSSName(name,Oid) + * @see #export + */ + public GSSName(byte[] name, Oid nameType, Oid mechType) + throws GSSException { + + m_nameType = nameType; + m_nameBytes = new byte[name.length]; + System.arraycopy(name, 0, m_nameBytes, 0, name.length); + + GSSNameSpi mn = GSSManager.getNameInstance(mechType); + mn.init(name, nameType); + addMechName(mn); + } + + + /** + * Package private constructor used by the clone method and + * the credential object. - WE must make sure we set the name type + * oid. + */ + GSSName() { } + + + /** + * Package private constructor used by canonicalize name + * and the context object. Sets the specified mechanism name. + */ + GSSName(GSSNameSpi mechName) { + + addMechName(mechName); + m_nameType = mechName.getNameType(); + } + + + /** + * Compares this name with the specified GSSName for equality. + * If either of the names has type NT_ANONYMOUS, this call will + * return false. + *
RFC 2078 + *
equivalent to gss_compare_name
+ * @param another the GSSName object to be compared + * @return true if they both names refer to the same entity, false + * otherwise + * @overrides equals in class Object + */ + public boolean equals(Object another) { + + if ( !(another instanceof GSSName)) + return (false); + + try { + return (equals((GSSName)another)); + + } catch (GSSException e) { return false; } + } + + + /** + * A variation of equals method which may throw a GSSException + * when the names cannot be compared. If either of the names + * represents an anonymous entity, the method will return false. + *
RFC 2078 + *
equivalent to gss_compare_name
+ * @param another GSSName object to be compared + * @return true if they both names refer to the same entity, false + * otherwise + * @exception GSSException with possible major codes of + * BAD_NAMETYPE, BAD_NAME, FAILURE + */ + public boolean equals(GSSName another) throws GSSException { + + //check if anonymous name + if (isAnonymousName() || another.isAnonymousName()) + return (false); + + if (m_mechNames.size() != another.m_mechNames.size()) + return false; + + if (m_mechNames.size() < 1) { + + //check if the external names match + if (! m_nameType.equals(another.m_nameType)) + return false; + + if (m_nameStr != null && another.m_nameStr != null) + return (m_nameStr.equals(another.m_nameStr)); + + if (m_nameBytes != null && another.m_nameBytes != null) + return (m_nameBytes.equals(another.m_nameBytes)); + + return false; + } + + //we have some mechanism names, each name must be over same + //mechs and the names must equal + GSSNameSpi mechName1, mechName2; + for (Enumeration e = m_mechNames.elements(); e.hasMoreElements();) { + + mechName1 = (GSSNameSpi)e.nextElement(); + if ((mechName2 = another.getMechName(mechName1.getMech())) + == null) + return false; + + if (! mechName1.equals(mechName2)) + return false; + } + + //went through all the names and they equal, so must be same name + return (true); + } + + + /** + * Creates a new name which is guaranteed to be mechanism specific (MN). + *
RFC 2078 + *
equivalent to gss_canonicalize_name
+ * @param mechOid oid of the mechanism for which the name should be + * canonicalized + * @return a mechanism specific internal name (MN) + * @exception GSSException with possible major codes of + * BAD_MECH, BAD_NAMETYPE. + */ + public GSSName canonicalize(Oid mechOid) throws GSSException { + + //check if we already contain the mechanism name + GSSNameSpi mechName = getMechName(mechOid); + if (mechName != null) { + if (isMechName()) + return (this); + + //need to create new name only for this mechanism + return (new GSSName((GSSNameSpi)mechName.clone())); + } + + + //we don't already have it, so create it + if (m_nameStr != null) + return (new GSSName(m_nameStr, m_nameType, mechOid)); + else + return (new GSSName(m_nameBytes, m_nameType, mechOid)); + } + + + /** + * Returns a flat name representation for this GSSName object. The + * name must be in MN format before making this call. The name is + * prefixed with a mechanism independent header as specified in + * RFC 2078. The returned buffer can be passed into a GSSName + * constructor with GSSName.EXPORT_NAME as the name type. + *
RFC 2078 + *
equivalent to gss_export_name
+ * @return a byte array representing the name + * @exception GSSException with possible major codes of NAME_NOT_MN, + * BAD_NAME, BAD_NAMETYPE, FAILURE. + * @see #canonicalize + */ + public byte[] export() throws GSSException { + + //check if we have a mechanism specific name + if (!isMechName()) + throw new GSSException(GSSException.NAME_NOT_MN); + + return (getMechName(null).export()); + } + + + /** + * Returns a string representation of the GSSName object. + * To retrieve the printed name format call getStringNameType. + * @return a String representation for this GSSName + * @overrides java.lang.Object#toString + * @see #getStringNameType + **/ + public String toString() { + + if (isMechName()) + return (getMechName(null).toString()); + + if (m_nameStr != null) + return (m_nameStr); + + if (m_mechNames.size() > 0) + return (getMechName(null).toString()); + + //name must in byte format + return ("Unknown name"); + } + + + /** + * Returns the name type for the printed name. + *
RFC 2078 + *
equivalent to name_type parameter in gss_display_name
+ * @return Oid for the name type as printed with toString() + * @exception GSSException when the name can't be printed + * @see #toString + */ + public Oid getStringNameType() throws GSSException { + + if (isMechName()) + return (getMechName(null).getStringNameType()); + + if (m_nameStr != null) + return (m_nameType); + + if (m_mechNames.size() > 0) + return (getMechName(null).getStringNameType()); + + throw new GSSException(GSSException.BAD_NAME); + } + + + /** + * Creates a duplicate of this object. + *
RFC 2078 + *
equivalent to gss_duplicate_name
+ * @return a copy of this object + * @exception CloneNotSupportedException may be thrown + */ + public Object clone() throws CloneNotSupportedException { + + GSSName newName; + + try { + if (m_nameStr != null) + newName = new GSSName(m_nameStr, m_nameType); + else if (m_nameBytes != null) + newName = new GSSName(m_nameBytes, m_nameType); + else + newName = new GSSName(); + + for (Enumeration e = m_mechNames.elements(); + e.hasMoreElements(); ) + newName.addMechName((GSSNameSpi) + ((GSSNameSpi)e.nextElement()).clone()); + + } catch (Exception e) { + throw new CloneNotSupportedException(); + } + + return (newName); + } + + + /** + * Tests if this is an Anonymous name object. + * @return boolean indicating if this in an anonymous name + */ + public boolean isAnonymousName() { + + if (m_nameType.equals(NT_ANONYMOUS)) + return (true); + + if (m_mechNames.size() > 0) + return (getMechName(null).isAnonymousName()); + + return false; + } + + + /** + * Package private method to add a mechanism name to + * the name. Used by the credential object. + * + */ + void addMechName(GSSNameSpi mechName) { + + m_mechNames.addElement(mechName); + } + + + /** + * Tests if this is a mechanism name. + * Mechanism name is defined as having only one mechanism + * name element. + * @return boolean indicating if this is a MN + */ + private boolean isMechName() { + + return (m_mechNames.size() == 1); + } + + + /** + * Retrieves a mechanism specific name for the specified oid. + * If the name is not found, null is returned. null oid can be + * used to retrieve the first mechanism name. + * + * @param Oid for the mechanism name to retrieve + * @return GSSNameSpi for the requested mechanism or null if not found + */ + GSSNameSpi getMechName(Oid mechOid) { + + if (mechOid == null) { + if (m_mechNames.size() < 1) + return (null); + + return ((GSSNameSpi)m_mechNames.firstElement()); + } + + for (Enumeration e = m_mechNames.elements(); e.hasMoreElements(); ) { + + GSSNameSpi mechName = (GSSNameSpi)e.nextElement(); + + if (mechName.getMech().equals(mechOid)) + return (mechName); + + } + return (null); + } + + + /** + * Returns the mechanism specific name. If this name does not + * already contain it, it is created. + * @param mechOid oid of the mechanism for which the name should be + * canonicalized + * @return a mechanism specific internal name + * @exception GSSException with possible major codes of + * BAD_MECH, BAD_NAMETYPE. + */ + GSSNameSpi canonicalizeInPlace(Oid mechOid) throws GSSException { + + //check if we already contain the mechanism name + GSSNameSpi mechName = getMechName(mechOid); + if (mechName != null) + return (mechName); + + //we don't already have it, so create it + mechName = GSSManager.getNameInstance(mechOid); + + if (m_nameStr != null) + mechName.init(m_nameStr, m_nameType); + else + mechName.init(m_nameBytes, m_nameType); + + addMechName(mechName); + return (mechName); + } + + + //instance variables + //we use a vector because GSSCredential.getName() must return + //all the credential names in mechanism format + Vector m_mechNames = new Vector(3,2); + Oid m_nameType; + String m_nameStr; + byte [] m_nameBytes; +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSNameSpi.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSNameSpi.java new file mode 100644 index 0000000000..2186feda60 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/GSSNameSpi.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + + +/** + * This class represents a mechanism specific name element. One or + * more instances of this class are contained in an instance of + * a GSSName object. Each GSSNameSpi object represents at most 1 + * mechanism specific name element. + */ + +public interface GSSNameSpi { + + /** + * Initializer for the GSSNameSpi object using a byte array. + * + * @param byte[] name bytes which is to be interpreted based + * on the nameType + * @param nameType - oid representing the type of name supplied + * @exception GSSException The major codes can be BAD_NAMETYPE, + * BAD_NAME, and FAILURE. + * @see #init(String,Oid) + */ + public void init(byte[] externalName, Oid nameType) throws GSSException; + + + /** + * Initializer for the GSSNameSpi object using a String. + * + * @param name string which is to be interpreted based + * on the nameType + * @param nameType - oid representing the type of name supplied + * @exception GSSException The major codes can be BAD_NAMETYPE, + * BAD_NAME, and FAILURE. + * @see #init(String,Oid) + */ + public void init(String name, Oid nameType) throws GSSException; + + + /** + * Equal method for the GSSNameSpi objects. + * If either name denotes an anonymous principal, the call should + * return false. + * + * @param name to be compared with + * @returns true if they both refer to the same entity, else false + * @exception GSSException with major codes of BAD_NAMETYPE, + * BAD_NAME, FAILURE + */ + public boolean equals(GSSNameSpi name) throws GSSException; + + + /** + * Returns a flat name representation for this object. The name + * format is defined in RFC 2078. + * + * @return the flat name representation for this object + * @exception GSSException with major codes NAME_NOT_MN, BAD_NAME, + * BAD_NAME, FAILURE. + */ + public byte[] export() throws GSSException; + + + /** + * Get the mechanism type that this NameElement corresponds to. + * + * @return the Oid of the mechanism type + */ + public Oid getMech(); + + + /** + * Returns the name type oid for this name. + * + * @return the name type oid for this name + */ + public Oid getNameType(); + + + /** + * Returns a string representation for this name. The printed + * name type can be obtained by calling getStringNameType(). + * + * @return string form of this name + * @see #getStringNameType() + * @overrides Object#toString + */ + public String toString(); + + + /** + * Returns the oid describing the format of the printable name. + * + * @return the Oid for the format of the printed name + */ + public Oid getStringNameType(); + + + /** + * Produces a copy of this object. + */ + public Object clone(); + + + /** + * Indicates if this name object represents an Anonymous name. + */ + public boolean isAnonymousName(); +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/MessageProp.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/MessageProp.java new file mode 100644 index 0000000000..354161c34b --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/MessageProp.java @@ -0,0 +1,239 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +/** + * This class conveys information about the per-message security + * services requested/provided through the GSSContext class in the + * wrap and getMIC methods. It allows the caller to specify + * the desired per-message Quality of Protection (QOP) and + * privacy state. Upon return from these calls, this object indicates + * the actual applied QOP and confidentiality state. + * + * Instances of this class are also used by the unwrap and verifyMIC + * methods to obtain the message protection applied by the peer. The + * QOP indicates the algorithm used to protect the message. The + * privacy flag indicates if message privacy has been applied. Methods + * are also provided to query for supplementary status information + * for the processed token. + * + * @see GSSContext#wrap + * @see GSSContext#unwrap + * @see GSSContext#getMIC + * @see GSSContext#verifyMIC + */ + +public class MessageProp { + + private boolean m_privacyState; + private int m_qop; + private boolean m_dupToken; + private boolean m_oldToken; + private boolean m_unseqToken; + private boolean m_gapToken; + + /** + * Default constructor for the class. QOP is set to 0 and + * confidentiality to false. + */ + public MessageProp () { + + m_qop = 0; + m_privacyState = false; + resetStatusValues(); + } + + + /** + * Constructor allowing the setting of the qop and + * the privacy state. + * + * @param qop the qop value for the message + * @param privState indicates privacy request/applied state + */ + public MessageProp(int qop, boolean privState) { + + m_qop = qop; + m_privacyState = privState; + resetStatusValues(); + } + + + /** + * Retrieves the QOP value. + * + * @return the QOP value + */ + public int getQOP() { + + return (m_qop); + } + + + /** + * Retrieves the privacy state. + * + * @return true indicates privacy has been applied + */ + public boolean getPrivacy() { + + return (m_privacyState); + } + + + /** + * Sets the QOP value. + * + * @param QOP value to store. + */ + public void setQOP(int qopVal) { + + m_qop = qopVal; + } + + + /** + * Sets the privacy state. + * + * @param privacy value to store. + */ + public void setPrivacy(boolean privState) { + + m_privacyState = privState; + } + + + /** + * Method to signal supplementary information. + * Returns true if this is a duplicate of an earlier token. + */ + public boolean isDuplicateToken() { + + return (m_dupToken); + } + + + /** + * Method to signal supplementary information. + * Returns true if the token's validity period has expired. + */ + public boolean isOldToken() { + + return (m_oldToken); + } + + + /** + * Method to signal supplementary information. + * Returns true if a later token has already been processed. + */ + public boolean isUnseqToken() { + + return (m_unseqToken); + } + + + /** + * Method to signal supplementary information. + * Returns true if an expected per-message token was not + * received. + */ + public boolean isGapToken() { + + return (m_gapToken); + } + + + /* + * The following methods are to set the supplementary + * status values. These should be JGSS private, but + * the mechanism packages will need access to them. + */ + + /** + * Used by mechanism packages to set supplementary status value. + * Indicates that an expected per-message token was + * not received. + */ + public void setGapTokenStatus() { + + m_gapToken = true; + } + + + /** + * Used by mechanism packages to set supplementary status value. + * Indicates this is a duplicate of an earlier token. + */ + public void setDuplicateTokenStatus() { + + m_dupToken = true; + } + + + /** + * Used by mechanism packages to set supplementary status value. + * Indicates that the token's validity period has expired. + */ + public void setOldTokenState() { + + m_oldToken = true; + } + + + /** + * Used by mechanism packages to set supplementary status value. + * Indicates that a later token has already been processed. + */ + public void setUnseqTokenStatus() { + + m_unseqToken = true; + } + + + /** + * Resets the supplementary status values to false. + */ + void resetStatusValues() { + + m_dupToken = false; + m_oldToken = false; + m_unseqToken = false; + m_gapToken = false; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/Oid.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/Oid.java new file mode 100644 index 0000000000..d9017f5e03 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/Oid.java @@ -0,0 +1,295 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; + + +/** + * This class represents Universal Object Identifiers (Oids) and + * their associated operations. + *

+ * Oids are hierarchically globally-interpretable identifiers + * used within the GSS-API framework to identify mechanisms and + * name formats. The structure and encoding of Oids is defined + * in ISOIEC-8824 and ISOIEC-8825. For example the Oid + * representation of Kerberos V5 mechanism is 1.2.840.113554.1.2.2 + *

RFC 2078 + *
This class replaces the following GSS-API functions: + *
  • gss_test_oid_set_member + *
  • gss_release_oid + *
  • gss_oid_to_str + *
  • gss_str_to_oid
+ *
+ */ + +public class Oid { + + /** + * Creates an oid object from its DER octets. + */ + static Oid getFromDEROctets(InputStream is, int len) + throws GSSException { + + return new Oid(DERParser.decodeOidOctets(is, len)); + } + + + /** + * Creates an oid object from a vector of its integer components. + * The vector is not copied. + */ + private Oid(Vector v) { + + m_v = v; + } + + + /** + * Constructs an Oid object from a string representation of its + * integer components. Will throw a GSSException if the string + * is improperly formatted. + * + * @param strOid the string in either of these two formats: + * "{1 2 3 3}" or "1.2.3.3". + * @exception GSSException may be thrown when the + * string is incorrectly formatted + */ + public Oid(String strOid) throws GSSException { + + m_v = new Vector(8, 3); + parseFromStr(strOid); + } + + + /** + * Constructs an Oid object from its DER encoding. The structure + * and encoding of Oids is defined in ISOIEC-8824 and ISOIEC-8825. + * + * @param derOid stream containing the DER encoded oid + * @exception GSSException may be thrown when the DER + * encoding does not follow the prescribed format. + */ + public Oid(InputStream derOid) throws GSSException { + + m_v = DERParser.decodeOid(derOid); + } + + + /** + * Constructs an Oid object from its DER encoding. The structure + * and encoding of Oids is defined in ISOIEC-8824 and ISOIEC-8825. + * + * @param data byte array containing the DER encoded oid + * @param offset where in the data byte array to start from + * @exception GSSException may be thrown when the DER + * encoding does not follow the prescribed format. + */ + public Oid(byte [] data, int offset) throws GSSException { + + m_v = DERParser.decodeOid(new ByteArrayInputStream(data, + offset, data.length - offset)); + } + + + /** + * Constructs an Oid object from its DER encoding. The structure + * and encoding of Oids is defined in ISOIEC-8824 and ISOIEC-8825. + * + * @param DEROid a byte array containing the DER encoding of the Oid + * @exception GSSException may be thrown when the DER + * encoding does not follow the prescribed format. + * @see Oid#Oid(java.io.InputStream) + */ + public Oid(byte[] DEROid) throws GSSException { + + m_v = DERParser.decodeOid(new ByteArrayInputStream(DEROid)); + } + + + /** + * Returns a string representation of the oid's integer components + * in dot separated notation. + * @return string representation in the following format: "1.2.3.4.5" + * @see #toRFC2078String + * @overrides java.lang.Object#toString + */ + public String toString() { + + StringBuffer sb = new StringBuffer(50); + + if (m_v.size() < 1) + return (new String("")); + + for (Enumeration e = m_v.elements(); e.hasMoreElements();) { + sb.append(e.nextElement().toString()); + if (e.hasMoreElements()) + sb.append("."); + } + + return (sb.toString()); + } + + + /** + * Returns a string representation of the Oid's integer components + * in the format specified within RFC 2078. For example { 1 2 3 4 } + *
RFC 2078 + *
equivalent to gss_oid_to_str
+ * @return string representation in the following format: { 1 2 3 4 5 } + * @see #toString + */ + public String toRFC2078String() { + + StringBuffer sb = new StringBuffer(50); + + if (m_v.size() < 1) + return (new String("")); + + sb.append("{ "); + for (Enumeration e = m_v.elements(); e.hasMoreElements(); ) { + sb.append(e.nextElement().toString()); + sb.append(" "); + } + sb.append("}"); + + return (sb.toString()); + } + + + /** + * Equality test for oid objects. + * @param Obj Oid object that has to be compared to this one + * @return true if they represent the same Oid, false otherwise + * @overrides java.lang.Object#equals + */ + public boolean equals(Object Obj) { + + if (! (Obj instanceof Oid)) + return (false); + + //check if both reference the same object + if (this == Obj) + return (true); + + Oid anOid = (Oid) Obj; + + if (m_v.size() != anOid.m_v.size()) + return (false); + + for (Enumeration e1 = m_v.elements(), e2 = anOid.m_v.elements(); + e1.hasMoreElements(); ) { + + if (! e1.nextElement().equals(e2.nextElement())) + return (false); + } + + return (true); + } + + + /** + * Returns the full ASN.1 DER encoding for this oid object. + * + * @return byte array containing the DER encoding of this oid object. + * @exception GSSException may be thrown when the oid can't be encoded + */ + public byte[] getDER() throws GSSException { + + if (m_der != null) + return (m_der); + + m_der = DERParser.encodeOid(m_v); + return (m_der); + } + + + /** + * A utility method which takes an array of Oids and checks if + * it contains this oid object. + *

RFC 2078 + *
In the JGSS package Oid sets are represented as arrays of + * Oids. This method is equivalent to gss_test_oid_set_member.
+ * @param An array of Oids to search + * @return true if the array contains this object, false otherwise + */ + public boolean containedIn(Oid[] oids) { + + for (int i = 0; i < oids.length; i++) { + if (oids[i].equals(this)) + return (true); + } + + return (false); + } + + + /** + * Parses in the string encoding of the object. + * + * @param src string to parse + * @exception GSSException when src string is incorrectly formatted + **/ + private void parseFromStr(String src) throws GSSException { + + int firstIndex = src.indexOf("{"); + + try { + //skip over the { and } first + if (firstIndex != -1) + src = src.substring(firstIndex, src.lastIndexOf("}")); + + StringTokenizer st = new StringTokenizer(src, " ."); + while (st.hasMoreTokens()) { + m_v.addElement(new Integer(st.nextToken())); + } + + } catch (Exception e) { + throw new GSSException(GSSException.FAILURE); + } + } + + + //Instance variables + private Vector m_v; + byte [] m_der; +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs.properties b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs.properties new file mode 100644 index 0000000000..d2e92e2128 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs.properties @@ -0,0 +1,59 @@ +# +# Copyright (c) 1999, 2007 Sun Microsystems, Inc. +# All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# -Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# -Redistribution in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# Neither the name of Sun Microsystems, Inc. or the names of contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# This software is provided "AS IS," without a warranty of any kind. ALL +# EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING +# ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS +# SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE +# AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE +# SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE +# LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, +# SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED +# AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR +# INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGES. +# +# You acknowledge that this software is not designed,licensed or intended +# for use in the design, construction, operation or maintenance of any +# nuclear facility. +# +# +# +# This is the "GSS security machanism plug-in properties file". +# +# This file provides a way to plug-in a security mechanism into +# the java gss-api framework simply by providing the class name of +# the plug-in Provider. +# +# Each entry is of the form: +# +# gss.provider.= +# +# +# This declares a GSS-API plug-in provider, , which is a subclass +# of the java.security.Provider, and specifies its preference order +# as the default GSS-API plug-in provider. The order is 1-based; 1 is the +# most preferred default gss plug-in, and so on. +# +# +# +# Example: +# +# gss.provider.1=com.sun.gssapi.dummy.Dummy diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/Dummy.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/Dummy.java new file mode 100644 index 0000000000..85e7e5dff5 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/Dummy.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi.mechs.dummy; + +import java.security.Provider; + +import com.sun.gssapi.Oid; +import com.sun.gssapi.GSSException; + + +/** + * Dummy Mechanism plug in for JGSS + * This is the properties object required by the JGSS framework. + * All mechanism specific information is defined here. + */ + +public final class Dummy extends Provider { + + private static String info = "JGSS Dummy Mechanism Provider"; + + public Dummy() { + + super("JGSS Dummy Provider 1", 1.0, info); + + + //list mechs supported + put("JGSS.Mechs", "1.3.6.1.4.1.42.2.26.1.2"); + + //configure 1.3.6.1.4.1.42.2.26.1.2 + put("JGSS.Mech.1.3.6.1.4.1.42.2.26.1.2.Alias", "dummy"); + put("JGSS.Mech.dummy.NAMES", "1.3.6.1.5.6.2:1.2.840.113554.1.2.1.1"); + put("JGSS.Mech.dummy.CRED", "com.sun.gssapi.dummy.DummyCred"); + put("JGSS.Mech.dummy.CONTEXT", "com.sun.gssapi.dummy.DummyCtxt"); + put("JGSS.Mech.dummy.NAME", "com.sun.gssapi.dummy.DummyName"); + + + } + + + /** + * Package private method to return the oid of this mech. + */ + static Oid getMyOid() { + + return (M_myOid); + } + + + /** + * Package private method to return the number of tokens + * to be used in the context creation exchange. + */ + static int getNumOfTokExchanges() { + + return (M_tokNum); + } + + + //private variables + private static Oid M_myOid; + private static final int M_tokNum = 2; + + + static { + try { + M_myOid = new Oid("1.3.6.1.4.1.42.2.26.1.2"); + } catch (GSSException e) { + throw new NumberFormatException(); + } + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/DummyCred.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/DummyCred.java new file mode 100644 index 0000000000..768b214cf8 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/DummyCred.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi.mechs.dummy; + +import com.sun.gssapi.*; + +/** + * Implements the dummy credential class. + */ +public class DummyCred implements GSSCredSpi { + + + /** + * Standard constructor. + */ + public DummyCred() { + m_freed = false; + } + + + /** + * Initialization entry point. + * + * @param name of the credential entity; can be null + * meaning a system default + * @param Desired lifetime for the credential's ability + * to initialize contexts; 0 means use default + * @param Desired lifetime for the credential's ability + * to accept contexts; 0 means default + * @param Credential usage flag. + * @exception GSSException may be thrown + */ + public void init(GSSNameSpi aName, int initLifetime, + int acceptLifetime, int usage) throws GSSException { + + //set the name + if (aName == null) + m_myName = DummyName.getDefault(); + else { + //must be a dummy name + if (!(aName instanceof DummyName)) + throw new GSSException(GSSException.BAD_NAME); + + m_myName = (DummyName)aName; + } + + //get my lifetime + if (initLifetime == 0) + m_initLifetime = GSSCredential.INDEFINITE; + else + m_initLifetime = initLifetime; + + if (acceptLifetime == 0) + m_acceptLifetime = GSSCredential.INDEFINITE; + else + m_acceptLifetime = acceptLifetime; + + + m_usage = usage; + m_freed = false; + } + + + /** + * Release this mechanism specific credential element. + * + * @exception GSSException with major codes NO_CRED and FAILURE. + */ + public void dispose() throws GSSException { + + m_freed = true; + m_myName = null; + } + + + /** + * Returns the name for the credential. + * + * @exception GSSException may be thrown + */ + public GSSNameSpi getName() throws GSSException { + + //some debugging code + if (m_freed) + throw new GSSException(GSSException.NO_CRED); + + return (m_myName); + } + + + /** + * Returns the remaining context initialization lifetime in + * seconds. + * + * @exception GSSException may be thrown + */ + public int getInitLifetime() throws GSSException { + + //check if this is valid + if (m_freed) + throw new GSSException(GSSException.NO_CRED); + + //return time based on usage + if (getUsage() == GSSCredential.ACCEPT_ONLY) + return (0); + + return (m_initLifetime); + } + + /** + * Returns the remaining context acceptance lifetime in + * seconds. + * + * @exception GSSException may be thrown + */ + + public int getAcceptLifetime() throws GSSException { + + //sanity check + if (m_freed) + throw new GSSException(GSSException.NO_CRED); + + //take usage into account + if (getUsage() == GSSCredential.INITIATE_ONLY) + return (0); + + return (m_acceptLifetime); + } + + + /** + * Returns the remaining context lifetime in + * seconds. This takes into account the usage property and + * returns the minimum remaining. + * + * @exception GSSException may be thrown + */ + + public int getLifetime() throws GSSException { + + //sanity check + if (m_freed) + throw new GSSException(GSSException.NO_CRED); + + //take usage into account, return minimum remaining time + if (getUsage() == GSSCredential.ACCEPT_ONLY) + return (m_acceptLifetime); + else if (getUsage() == GSSCredential.INITIATE_ONLY) + return (m_initLifetime); + + if (m_initLifetime < m_acceptLifetime) + return (m_initLifetime); + + return (m_acceptLifetime); + } + + + /** + * Returns the credential usage flag. + * + * @exception GSSException may be thrown + */ + + public int getUsage() throws GSSException { + + //sanity check + if (m_freed) + throw new GSSException(GSSException.NO_CRED); + + return (m_usage); + } + + /** + * Returns the credential mechanism. Since this is a single + * credential element only a single oid can be returned. + */ + public Oid getMechanism() { + + return (Dummy.getMyOid()); + } + + + //instance variables + private DummyName m_myName; + private int m_usage; + private int m_initLifetime; + private int m_acceptLifetime; + private boolean m_freed; + +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/DummyCtxt.m4 b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/DummyCtxt.m4 new file mode 100644 index 0000000000..660fe7e8d7 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/DummyCtxt.m4 @@ -0,0 +1,754 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.gssapi.dummy; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.DataOutputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; + +import com.sun.gssapi.*; + + +/** + * Implements the dummy Context class GSSCtxtSpi interface + * for the dummy mechanism. + */ +public class DummyCtxt implements GSSCtxtSpi { + + + /** + * Standard constructor. + */ + public DummyCtxt() { + + m_state = NEW; + m_tokCount = Dummy.getNumOfTokExchanges(); + m_lifetime = 0; + } + + + /** + * Sets the context parameters for the initiator side of + * the context. + */ + public void _setInitOptions (GSSCredSpi myCred, GSSNameSpi targName, + int desLifetime, int ctxtOptions) throws GSSException { + + //make sure we are in right state + if (m_state != NEW) { + throw new GSSException(GSSException.NO_CONTEXT); + } + + //set the target name + if (targName == null || ! (targName instanceof DummyName)) + throw new GSSException(GSSException.BAD_NAME); + + m_targName = (DummyName)targName; + + + //get the src name from credential - that's all we have in there + if (myCred == null) { + m_srcName = DummyName.getDefault(); + } else { + if (! (myCred instanceof DummyCred)) + throw new GSSException(GSSException.DEFECTIVE_CREDENTIAL); + + //we can do the cast below because we know it is our credential + m_srcName = (DummyName)myCred.getName(); + } + + + //check for default lifetime request + if (desLifetime == 0) + m_lifetime = GSSContext.INDEFINITE; + else + m_lifetime = desLifetime; + + + m_flags = ctxtOptions; + m_initiator = true; + } + + + /** + * Sets the context parameters for the acceptor side + * of the context. + */ + public void _setAcceptOptions (GSSCredSpi myCred) throws GSSException { + + if (myCred == null) { + m_targName = DummyName.getDefault(); + m_lifetime = GSSContext.INDEFINITE; + } else { + + if (!(myCred instanceof DummyCred)) + throw new GSSException(GSSException.NO_CRED); + + m_targName = (DummyName)myCred.getName(); + m_lifetime = myCred.getAcceptLifetime(); + } + + m_flags = 0; + m_initiator = false; + } + + + /** + * Sets the channel bindings to be used during context + * establishment. + */ + public void _setChannelBinding (ChannelBinding chb) throws GSSException { + + throw new GSSException(GSSException.UNAVAILABLE); + } + + + /** + * Retrieves the mechanism options. + * + * @return int GSSContext options ORed together + */ + public int _getOptions () { + + return (m_flags); + } + + + /** + * Inquire the remaining lifetime. + * + * @return the lifetime in seconds. May return reserved + * value GSSContext.INDEFINITE for an indefinite lifetime. + */ + public int _getLifetime () { + + return (m_lifetime); + } + + + /** + * Returns the mechanism oid. + * + * @return the Oid of this context + */ + public Oid _getMech () { + + return (Dummy.getMyOid()); + } + + + /** + * Returns the context initiator name. + * + * @return initiator name + * @exception GSSException + */ + public GSSNameSpi _getSrcName () throws GSSException { + + if (m_state != DONE) { + throw new GSSException(GSSException.NO_CONTEXT); + + } + + return (m_srcName); + } + + + /** + * Returns the context acceptor. + * + * @return context acceptor(target) name + * @exception GSSException + */ + public GSSNameSpi _getTargName () throws GSSException { + + if (m_state != DONE) { + throw new GSSException(GSSException.NO_CONTEXT); + } + + + return (m_targName); + } + + + /** + * Returns the delegated credential for the context. This + * is an optional feature of contexts which not all + * mechanisms will support. A context can be requested to + * support credential delegation by using the CRED_DELEG. + * This is only valid on the acceptor side of the context. + * @return GSSCredSpi object for the delegated credential + * @exception GSSException + * @see GSSContext#getDelegCredState + */ + public GSSCredSpi _getDelegCred () throws GSSException { + + throw new GSSException(GSSException.UNAVAILABLE); + } + + + /** + * Tests if this is the initiator side of the context. + * + * @return boolean indicating if this is initiator (true) + * or target (false) + */ + public boolean _isInitiator () { + + return (m_initiator); + } + + + /** + * Tests if the context can be used for per-message service. + * Context may allow the calls to the per-message service + * functions before being fully established. + * + * @return boolean indicating if per-message methods can + * be called. + */ + public boolean _isProtReady () { + + return (m_state == DONE); + } + + + /** + * Initiator context establishment call. This method may be + * required to be called several times. A CONTINUE_NEEDED return + * call indicates that more calls are needed after the next token + * is received from the peer. + * + * @param is contains the token received from the peer. On the + * first call it will be ignored. + * @param os to which any tokens required to be sent to the peer + * will be written. It is responsibility of the caller + * to send the token to its peer for processing. + * @return integer indicating if more calls are needed. Possible + * values are COMPLETE and CONTINUE_NEEDED. + * @exception GSSException + */ + public int _initSecCtxt (InputStream is, OutputStream os) throws GSSException { + + + boolean needTokenBack = true; + boolean sendToken = true; + + m_tokCount--; + + if (m_state == NEW) { + m_initiator = true; + m_state = IN_PROCESS; + } + else if (m_state == IN_PROCESS) { + if (!_isInitiator ()) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + + //read the token + sendToken = processEstabToken(is); + } + + //determine if we need token back + if (!sendToken || m_tokCount < 1) + needTokenBack = false; + + if (sendToken) { + + //create a token for our peer + createEstabOutToken(os, needTokenBack); + } + + if (needTokenBack) { + return (GSSContext.CONTINUE_NEEDED); + } + + m_state = DONE; + return (GSSContext.COMPLETE); + } + + + /** + * Acceptor's context establishment call. This method may be + * required to be called several times. A CONTINUE_NEEDED return + * call indicates that more calls are needed after the next token + * is received from the peer. + * + * @param is contains the token received from the peer. + * @param os to which any tokens required to be sent to the peer + * will be written. It is responsibility of the caller + * to send the token to its peer for processing. + * @return integer indicating if more calls are needed. Possible + * values are COMPLETE and CONTINUE_NEEDED. + * @exception GSSException + */ + public int _acceptSecCtxt (InputStream is, OutputStream os) throws GSSException { + + boolean needTokenBack = true; + boolean sendToken = true; + + //we have this but it's not used since the status + // code in tokens dictate if we need more + m_tokCount--; + + if (m_state == NEW) { + m_initiator = false; + m_state = IN_PROCESS; + } + else if (m_state == IN_PROCESS) { + if (_isInitiator ()) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + + //read the token + sendToken = processEstabToken(is); + } + + //determine if we need token back + if (!sendToken || m_tokCount < 1) + needTokenBack = false; + + if (sendToken) { + + //create a token for our peer + createEstabOutToken(os, needTokenBack); + } + + if (needTokenBack) { + return (GSSContext.CONTINUE_NEEDED); + } + + m_state = DONE; + m_srcName = new DummyName("dummy src name"); + return (GSSContext.COMPLETE); + } + + + /** + * Queries the context for largest data size to accomodate + * the specified protection and be <= maxTokSize. + * + * @param qop the quality of protection that the context will be + * asked to provide. + * @param confReq a flag indicating whether confidentiality will be + * requested or not + * @param outputSize the maximum size of the output token + * @return the maximum size for the input message that can be + * provided to the wrap() method in order to guarantee that these + * requirements are met. + * @throws GSSException + */ + public int _getWrapSizeLimit (int qop, boolean confReq, int maxTokSize) throws GSSException { + + return (maxTokSize); + } + + + /** + * Provides per-message token encapsulation. + * + * @param is the user-provided message to be protected + * @param os the token to be sent to the peer. It includes + * the message from is with the requested protection. + * @param msgPro on input it contains the requested qop and + * confidentiality state, on output, the applied values + * @exception GSSException + * @see MessageInfo + * @see unwrap + */ + public void _wrap (InputStream is, OutputStream os, MessageProp msgProp) throws GSSException { + + + if (m_state != DONE) + throw new GSSException(GSSException.NO_CONTEXT); + + try { + + int length = is.available(); + createTokenHeader(os, length + 1); + + while (length-- > 0) { + os.write(is.read()); + } + + os.write(0); + + } catch (IOException e) { + throw new GSSException(GSSException.FAILURE, -1, "io exception in wrap"); + } + + } + + + /** + * Retrieves the message token previously encapsulated in the wrap + * call. + * + * @param is the token from the peer + * @param os unprotected message data + * @param msgProp will contain the applied qop and confidentiality + * of the input token + * @return int representing the informatory status; this can be + * COMPLETE, DUPLICATE_TOKEN, OLD_TOKEN, UNSEQ_TOKEN and GAP_TOKEN. + * @exception GSSException + * @see MessageInfo + * @see wrap + */ + public void _unwrap (InputStream is, OutputStream os, MessageProp msgProp) throws GSSException { + + if (m_state != DONE) + throw new GSSException(GSSException.NO_CONTEXT); + + try { + int length = processTokenHeader(is); + + while (length-- > 0) { + os.write(is.read()); + } + + msgProp.setPrivacy(true); + msgProp.setQOP(0); + } catch (IOException e) { + throw new GSSException(GSSException.FAILURE, -1, "io exception in unwrap"); + } + } + + + /** + * Applies per-message integrity services. + * + * @param is the user-provided message + * @param os the token to be sent to the peer along with the + * message token. The message token is not encapsulated. + * @param msgProp on input the desired QOP and output the applied QOP + * @exception GSSException + */ + public void _getMIC (InputStream is, OutputStream os, MessageProp msgProp) + throws GSSException { + + if (m_state != DONE) + throw new GSSException(GSSException.NO_CONTEXT); + + try { + String tokenStr = new String("dummy_gss_sign"); + createTokenHeader(os, tokenStr.length() + 1); + + os.write(tokenStr.getBytes()); + os.write(0); + + msgProp.setPrivacy(false); + msgProp.setQOP(0); + + } catch (IOException e) { + throw new GSSException(GSSException.FAILURE, -1, "io exception in unwrap"); + } + } + + + /** + * Checks the integrity of the supplied tokens. + * This token was previously generated by getMIC. + * + * @param is token generated by getMIC + * @param msgStr the message to check integrity for + * @param msgProp will contain the applied QOP and confidentiality + * states of the token + * @return int informatory status which can be one of COMPLETE, + * DUPLICATE_TOKEN, OLD_TOKEN, UNSEQ_TOKEN and GAP_TOKEN. + * @exception GSSException + */ + public void _verifyMIC (InputStream is, InputStream msgStr, MessageProp mProp) throws GSSException { + + try { + int msgLen = processTokenHeader(is); + is.skip(msgLen); + + } catch (IOException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + } + + + /** + * Produces a token representing this context. After this call + * the context will no longer be usable until an import is + * performed on the returned token. + * + * @param os the output token will be written to this stream + * @exception GSSException + */ + public byte [] _export () throws GSSException { + + + throw new GSSException(GSSException.UNAVAILABLE); + } + + + /** + * Imports a previously exported context. + * + * @param Previously exported token + * @exception GSSException + * @see export + */ + public void _importSecCtxt (byte []aCtxtToken) throws GSSException { + + + throw new GSSException(GSSException.UNAVAILABLE); + } + + + /** + * Releases context resources and terminates the + * context between 2 peer. + * + * @exception GSSException with major codes NO_CONTEXT, FAILURE. + */ + public void _dispose () throws GSSException { + + m_state = DELETED; + } + + + /** + * Create token used during context establishment. + */ + private void createEstabOutToken(OutputStream os, boolean moreTokens) + throws GSSException { + + try { + String msgBody; + if (moreTokens) + msgBody = Integer.toString(1); + else + msgBody = Integer.toString(0); + + /* + * the token is composed of: + * tag + * DER tok length + * DER oid + * 2 bytes for token type + * msg body + */ + + createTokenHeader(os, msgBody.length() + 1); + + DataOutputStream dos = new DataOutputStream(os); + + //need to be written as bytes because that is what C version uses + dos.writeBytes(msgBody); + dos.write(0); //add null char - this is what C dummy wants + dos.flush(); + } catch (IOException e) { + throw new GSSException(GSSException.FAILURE, -1, "createInitOutToken"); + } + } + + + /** + * Processes the peer's context establishment token. + */ + private boolean processEstabToken(InputStream is) throws GSSException { + + try { + + processTokenHeader(is); + + //get continue/complete code + byte []b = new byte[1]; + b[0] = (byte)is.read(); + int status = Integer.parseInt(new String(b)); + is.read(); //null Byte + + if (status == 1) + return (true); + + return(false); + + } catch (IOException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, "processing init token from peer"); + } + + } + + + /** + * Checks the token header. + * + * @return the length of the message remaining + */ + private int processTokenHeader(InputStream is) + throws GSSException, IOException { + + + if (is.read() != 0x60) + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + + //read token length + int length = DERParser.readLength(is); + Oid tokOid = new Oid(is); + if (!tokOid.equals(Dummy.getMyOid())) + throw new GSSException(GSSException.BAD_MECH); + + //read token tag - not used + is.read(); + is.read(); + + //return the length of message remaining + return (length - 1 - 1 - 10 - 2); + } + + + /** + * Constructs the token header + */ + private void createTokenHeader(OutputStream os, int msgBodyLen) + throws GSSException { + + try { + /* + * the token header is composed of: + * tag + * DER tok length + * DER oid + * 0x0 0x0 (token tag) + */ + + byte [] derOid = Dummy.getMyOid().getDER(); + + int length = derOid.length + msgBodyLen + 2; + + DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(os)); + + dos.write(0x60); + DERParser.writeLength(dos, length); + dos.write(derOid); + + //now write the token tag - 0x0 - doesn't seem to be used + dos.write(0); + dos.write(0); + + dos.flush(); + } catch (IOException e) { + throw new GSSException(GSSException.FAILURE, -1, "createTokenHeader"); + } + } + + + //instance variables + private DummyName m_srcName; + private DummyName m_targName; + private int m_tokCount; + private int m_state; + private int m_flags; + private int m_lifetime; + private boolean m_initiator; + + private static final int NEW = 1; + private static final int IN_PROCESS = 2; + private static final int DONE = 3; + private static final int DELETED = 4; +} + + + +/** + * This is a package private class used to decode/encode ASN.1 DER + * length. + */ +class DERParser { + + /** + * Returns the DER encoded length from the InputStream. + */ + static int readLength(InputStream is) throws GSSException { + + int length, tmp; + //get the length of Oid - check if short form + try { + if (((tmp = is.read()) & 0x080) == 0) + length = tmp; + else { + //must be long form + tmp &= 0x7f; + for (length = 0; tmp > 0; tmp--) { + length <<= 8; + length += (0xff & is.read()); + } + } + } catch (IOException e) { + throw new GSSException(GSSException.DEFECTIVE_TOKEN); + } + + return (length); + } + + + /** + * Encodes DER length. + */ + static void writeLength(OutputStream os, int length) throws IOException { + + //encode the length - for all practical purposes, the length + //should always be less then 0x80 (128) + if (length < 0x80) + os.write(length); + else if (length < 0x100) { + os.write(0x081); + os.write(length); + } else if (length < 0x80000) { + os.write(0x082); + os.write(length >> 8); + os.write(length & 0xff); + } else if (length < 0x1000000) { + os.write(0x083); + os.write(length >> 16); + os.write((length >> 8) & 0xff); + os.write(length & 0xff); + } else { + os.write(0x084); + os.write(length >>> 24); + os.write((length >> 16) & 0xff); + os.write((length >> 8) & 0xff); + os.write(length & 0xff); + } + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/DummyName.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/DummyName.java new file mode 100644 index 0000000000..2ddce2b1cb --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/mechs/dummy/DummyName.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ +package com.sun.gssapi.mechs.dummy; + +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; + +import com.sun.gssapi.*; + +/** + * Implements the GSSNameSpi for the dummy mechanism. + */ +public class DummyName implements GSSNameSpi { + + + /** + * Returns the default name for the dummy mechanism. + * It is the username@localDomain. + */ + static DummyName getDefault() { + + StringBuffer res = new StringBuffer(System.getProperty("user.name", "unknown")); + res.append("@"); + try { + res.append(InetAddress.getLocalHost().getHostName()); + } catch (UnknownHostException e) { + res.append("unknown"); + } + + return (new DummyName(res.toString())); + } + + + /** + * Standard constructor - nop. + */ + public DummyName() { } + + + /** + * Creates a dummy name from the specified user name. + */ + DummyName(String userName) { + + m_type = GSSName.NT_USER_NAME; + m_name = userName; + + } + + + /** + * Initializer for the GSSNameSpi object using a byte array. + * + * @param byte[] name bytes which is to be interpreted based + * on the nameType + * @exception GSSException The major codes can be BAD_NAMETYPE, + * BAD_NAME, and FAILURE. + * @see #init(String,Oid) + */ + public void init(byte[] externalName, Oid nameType) throws GSSException { + + throw new GSSException(GSSException.UNAVAILABLE); + } + + + /** + * Initializer for the GSSNameSpi object using a String. + * + * @param name string which is to be interpreted based + * on the nameType + * @exception GSSException The major codes can be BAD_NAMETYPE, + * BAD_NAME, and FAILURE. + * @see #init(String,Oid) + */ + public void init(String name, Oid nameType) throws GSSException { + + m_name = name; + m_type = nameType; + } + + + /** + * Equal method for the GSSNameSpi objects. + * If either name denotes an anonymous principal, the call should + * return false. + * + * @param name to be compared with + * @returns true if they both refer to the same entity, else false + * @exception GSSException with major codes of BAD_NAMETYPE, + * BAD_NAME, FAILURE + */ + public boolean equals(GSSNameSpi name) throws GSSException { + + if (!(name instanceof DummyName)) { + return (false); + } + + return (m_name.equals(((DummyName)name).m_name)); + } + + + /** + * Returns a flat name representation for this object. The name + * format is defined in RFC 2078. + * + * @return the flat name representation for this object + * @exception GSSException with major codes NAME_NOT_MN, BAD_NAME, + * BAD_NAME, FAILURE. + */ + public byte[] export() throws GSSException { + + + throw new GSSException(GSSException.UNAVAILABLE); + } + + + /** + * Get the mechanism type that this NameElement corresponds to. + * + * @return the Oid of the mechanism type + */ + public Oid getMech() { + + return (Dummy.getMyOid()); + } + + + /** + * Returns a string representation for this name. The printed + * name type can be obtained by calling getStringNameType(). + * + * @return string form of this name + * @see #getStringNameType() + * @overrides Object#toString + */ + public String toString() { + + return (m_name); + } + + + /** + * Returns the name type oid. + */ + public Oid getNameType() { + + return (m_type); + } + + + /** + * Returns the oid describing the format of the printable name. + * + * @return the Oid for the format of the printed name + */ + public Oid getStringNameType() { + + return (m_type); + } + + + /** + * Produces a copy of this object. + */ + public Object clone() { + + return null; + } + + + /** + * Indicates if this name object represents an Anonymous name. + */ + public boolean isAnonymousName() { + + if (m_type.equals(GSSName.NT_ANONYMOUS)) + return (true); + + return (false); + } + + + //instance variables + private String m_name; + private Oid m_type; +} + diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/samples/GSSClient.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/samples/GSSClient.java new file mode 100644 index 0000000000..94d8448c8f --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/samples/GSSClient.java @@ -0,0 +1,317 @@ +package com.sun.gssapi.samples; +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ +/* + * Sample gss-client application. + * This will inter-operate with the MIT samples. + * + * + * GSSClient [-port port] [-mech 1.2.3.] host service msg + */ + +import java.io.*; +import java.net.*; + +import com.sun.gssapi.*; + +class GSSClient { + + /** + * Main method for the GSSClient sample application. + * This application in compatible with the MIT sample + * applications (gss-server, gss-client). + */ + public static void main(String args[]) { + + String serverHost, serverName, message; + int port = 4444; + + if (args.length < 3) { + usage(); + exit(1); + } + + + //set the required command line args + serverHost = args[args.length - 3]; + serverName = args[args.length - 2]; + message = args[args.length - 1]; + + try { + + Oid mechOid = GSSManager.getDefaultMech(); + + //parse the command line options + for (int i = 0; i < (args.length - 3); i++) { + + if (args[i].equals("-port")) { + if (i >= (args.length - 4)) { + usage(); + exit(-1); + } + port = Integer.parseInt(args[++i]); + } else if (args[i].equals("-mech")) { + if (i >= (args.length-4)) { + usage(); + exit(-1); + } + mechOid = new Oid(args[++i]); + } + } + + //connect to the server + s = new Socket(serverHost, port); + + + //establish a GSSContext with server + GSSContext aCtxt = createCtxt(serverName, mechOid); + + print("\nContext established\n"); + + //display context options + displayContext(aCtxt); + + + //wrap the message and send it to server + sendMsgToPeer(aCtxt, message); + + //receiving message from server + verifyMsgFromPeer(aCtxt, message); + + //context no longer needed + aCtxt.dispose(); + exit(0); + + } catch (IOException e) { + print("\n**Communication ERROR**:\t" + e.getMessage()); + e.printStackTrace(); + exit(-1); + } catch (GSSException e) { + print("\n**GSSAPI ERROR**:\t" + e.getMessage()); + e.printStackTrace(); + exit(-1); + } + } + + + /** + * Creates a GSS-API context with the server over the specified + * security mechanism. + */ + private static GSSContext createCtxt(String serverName, Oid mechOid) + throws GSSException, IOException { + + GSSContext aCtxt = new GSSContext( + new GSSName(serverName, GSSName.NT_HOSTBASED_SERVICE), + mechOid, null, 0); + + //set context options + aCtxt.requestConf(true); + aCtxt.requestInteg(true); + aCtxt.requestMutualAuth(true); + aCtxt.requestReplayDet(true); + aCtxt.requestSequenceDet(true); + + //start the context creation process + DataInputStream dis = new DataInputStream(s.getInputStream()); + DataOutputStream dos = new DataOutputStream(s.getOutputStream()); + + byte []inTok = new byte[0]; + + print("\nCalling init....."); + do { + byte[] outTok = aCtxt.init(inTok, 0, inTok.length); + + //send the token if present + if (outTok != null) { + + print("\tSending token to peer (" + outTok.length + " bytes)..."); + + //MIT apps write length first, then token + dos.writeInt(outTok.length); + dos.write(outTok, 0, outTok.length); + } + + //check if we should expect more tokens + if (aCtxt.isEstablished()) + break; + + //get input token from peer + inTok = new byte[dis.readInt()]; + print("\tReceiving token from peer (" + inTok.length + " bytes)..."); + dis.readFully(inTok, 0, inTok.length); + } while (true); + + return (aCtxt); + } + + + /** + * Display context information/flags. + */ + private static void displayContext(GSSContext aCtxt) throws GSSException { + + + //display context information + print("Context Information...."); + if (aCtxt.getLifetime() == GSSContext.INDEFINITE) + print("\tOver mech:\t" + aCtxt.getMech().toString() + " for " + " INDEFINITE seconds"); + else + print("\tOver mech:\t" + aCtxt.getMech().toString() + " for " + aCtxt.getLifetime() + " seconds"); + + print("\tInitiator:\t" + aCtxt.getSrcName().toString()); + print("\tAcceptor:\t" + aCtxt.getTargName().toString()); + if (aCtxt.getDelegCredState()) + print("\tDelegated credentials available."); + else + print("\tNO delegated credentials"); + + if (aCtxt.getMutualAuthState()) + print("\tMutaul Authentication ON"); + else + print("\tNO mutual authentication performed."); + + if (aCtxt.getReplayDetState()) + print("\tReplay detection ON"); + else + print("NO replay detection"); + + if (aCtxt.getSequenceDetState()) + print("\tSequence detection ON"); + else + print("\tNO sequence detection"); + + if (aCtxt.getAnonymityState()) + print("\tAnonymous context"); + + if (aCtxt.isTransferable()) + print("\tContext is transferable"); + else + print("\tNO context transfer"); + + if (aCtxt.isProtReady()) + print("\tContext protection is ready"); + else + print("**ERROR wrong state - context established, but isProtReady = false"); + + if (aCtxt.getConfState()) + print("\tConfidentiality available"); + else + print("\tNO confidentiality services"); + + if (aCtxt.getIntegState()) + print("\tIntegrity available"); + else + print("\tNO integrity services"); + + } + + + /** + * Sends a wraped message to the server. + */ + private static void sendMsgToPeer(GSSContext aCtxt, String msg) + throws GSSException, IOException { + + print("\nWrapping message for server..."); + + MessageProp mInfo = new MessageProp(0, true); + byte []tok = aCtxt.wrap(msg.getBytes(), 0, msg.length(), mInfo); + DataOutputStream dos = new DataOutputStream(s.getOutputStream()); + dos.writeInt(tok.length); + dos.write(tok); + dos.flush(); + } + + + /** + * Checks the MIC on a message received from the server. + */ + private static void verifyMsgFromPeer(GSSContext aCtxt, String msg) + throws GSSException, IOException { + + + print("receiving MIC message from server..."); + + DataInputStream dis = new DataInputStream(s.getInputStream()); + + int len = dis.readInt(); + print("Receiving message from peer (" + len + " bytes)"); + + MessageProp mInfo = new MessageProp(); + aCtxt.verifyMIC(dis, new StringBufferInputStream(msg), mInfo); + + print("Verified server message protected with QOP = " + mInfo.getQOP()); + } + + + /** + * Utility method to display application usage string. + */ + private static void usage() { + + print("GSSClient [-port port] [-mech 1.2.3.3] serverhost servername message"); + } + + + /** + * Utility method to display information to the screen. + */ + private static void print(String msg) { + + System.out.println(msg); + } + + + /** + * Utility method to gracefully shut down the connection and + * terminate the application. + */ + private static void exit(int status) { + + if (s != null) { + try { + s.close(); + } catch (IOException e) {}; + } + + System.exit(status); + } + + //private class variables + private static Socket s; +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/samples/GSSServer.java b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/samples/GSSServer.java new file mode 100644 index 0000000000..d88fd89aff --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/gssapi/samples/GSSServer.java @@ -0,0 +1,331 @@ +package com.sun.gssapi.samples; +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +/* + * Sample gss-server application. + * This will inter-operate with the MIT samples. + * + * GSSServer [-port port] [-mech 1.2.3.4.] serviceName + */ + +import java.io.*; +import java.net.*; + +import com.sun.gssapi.*; + +class GSSServer { + + /** + * Main method to start our sample application. + * This is the server end of the MIT like sample + * GSS-API applications. + */ + public static void main(String args[]) { + + //default MIT port + int port = 4444; + + if (args.length < 1) { + usage(); + exit(-1); + } + + try { + + String serviceName = args[args.length-1]; + Oid mechOid = GSSManager.getDefaultMech(); + + //parse the command line options + for (int i = 0; i < args.length; i++) { + + if (args[i].equals("-port")) { + if (i >= (args.length - 2)) { + usage(); + exit(-1); + } + port = Integer.parseInt(args[++i]); + } else if (args[i].equals("-mech")) { + if (i >= (args.length-2)) { + usage(); + exit(-1); + } + mechOid = new Oid(args[++i]); + } + } + + + + //acquire server credentials + print("\nAcquiring credentials as " + serviceName + "..."); + GSSCredential server = new GSSCredential(new GSSName(serviceName, + GSSName.NT_HOSTBASED_SERVICE), GSSCredential.INDEFINITE, + mechOid, GSSCredential.ACCEPT_ONLY); + + print("\nDumping credential info...\n" + server.toString() + "\n"); + + s = new ServerSocket(port); + + while (true) { + + //wait for connections + print("\n\nWaiting for connections on port " + port + "..."); + Socket c = s.accept(); + + print("Accepted connection from " + c.getInetAddress().getHostName()); + processClient(server, c); + } + + + //catch all errors + } catch (IOException e) { + print("\n**Communication ERROR**:\t" + e.getMessage()); + e.printStackTrace(); + exit(-1); + } catch (GSSException e) { + print("\n**GSSAPI ERROR**:\t" + e.getMessage()); + e.printStackTrace(); + exit(-1); + } + } + + + /** + * Processes a client connection. + * -creates a context + * -displays context information + * -unwraps a client token + * -produces a MIC on client token + * -destroy the context + */ + private static void processClient(GSSCredential server, Socket client) + throws GSSException, IOException { + + //we have a client connected on the socket + DataInputStream dis = new DataInputStream(new BufferedInputStream(client.getInputStream())); + DataOutputStream dos = new DataOutputStream(client.getOutputStream()); + + print("\n\nCreating context..."); + + //MIT apps, first send token length + int tokLen = dis.readInt(); + print("\tReceiving token from peer (" + tokLen + " bytes)..."); + + + //create acceptor GSS-API context + GSSContext aCtxt = new GSSContext(server); + + //get first token from peer + byte []inTok = new byte[tokLen]; + dis.readFully(inTok, 0, inTok.length); + + do { + byte []outTok = aCtxt.accept(inTok, 0, inTok.length); + + //check if we need to send token to peer + if (outTok != null) { + + print("\tSending token to peer..."); + + //MIT samples write length first, then token + dos.writeInt(outTok.length); + dos.write(outTok); + } + + //are we done ?? + if (aCtxt.isEstablished()) + break; + + //the mechanism expects more tokens + inTok = new byte[dis.readInt()]; + print("\tReceiving token from peer (" + inTok.length + " bytes)..."); + dis.readFully(inTok, 0, inTok.length); + + } while (true); + + //context is ready + print("\tContext is fully established"); + + //display context information + displayContext(aCtxt); + + //exchange messages with peer + exchangeWithPeer(aCtxt, dis, dos); + + + //no more need for this context + aCtxt.dispose(); + client.close(); + } + + + /** + * Displays context informations/characteristics. + */ + private static void displayContext(GSSContext aCtxt) throws GSSException { + + + //display context information + print("\n\nContext Information...."); + if (aCtxt.getLifetime() == GSSContext.INDEFINITE) + print("\tOver mech:\t" + aCtxt.getMech().toString() + " for " + " INDEFINITE seconds"); + else + print("\tOver mech:\t" + aCtxt.getMech().toString() + " for " + aCtxt.getLifetime() + " seconds"); + + print("\tInitiator:\t" + aCtxt.getSrcName().toString()); + print("\tAcceptor:\t" + aCtxt.getTargName().toString()); + if (aCtxt.getDelegCredState()) + print("\tDelegated credentials available."); + else + print("\tNO delegated credentials"); + + if (aCtxt.getMutualAuthState()) + print("\tMutaul Authentication ON"); + else + print("\tNO mutual authentication performed."); + + if (aCtxt.getReplayDetState()) + print("\tReplay detraction ON"); + else + print("\tNO replay detection"); + + if (aCtxt.getSequenceDetState()) + print("\tSequence detection ON"); + else + print("\tNO sequence detection"); + + if (aCtxt.getAnonymityState()) + print("\tAnonymous context"); + + if (aCtxt.isTransferable()) + print("\tContext is transferable"); + else + print("\tNO context transfer"); + + if (aCtxt.isProtReady()) + print("\tContext protection is ready"); + else + print("**ERROR wrong state - context established, but isProtReady = false"); + + if (aCtxt.getConfState()) + print("\tConfidentiality available"); + else + print("\tNO confidentiality services"); + + if (aCtxt.getIntegState()) + print("\tIntegrity available"); + else + print("\tNO integrity services"); + + } + + + /** + * Performs exchange with client on a fully established context. + */ + private static void exchangeWithPeer(GSSContext aCtxt, DataInputStream dis, + DataOutputStream dos) throws GSSException, IOException { + + /* + * We have a simple exchange with the client + * First it sends us a wrapped message which we + * unwrap, and produce a MIC on. This is then sent + * back to the client. + */ + print("\n\nPeer message exchange..."); + + int len = dis.readInt(); + print("\tReceiving message from peer (" + len + " bytes)...."); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + MessageProp mInfo = new MessageProp(); + + aCtxt.unwrap(dis, bos, mInfo); + print("\tMessage from peer:\t" + new String(bos.toByteArray())); + + mInfo.setQOP(0); + mInfo.setPrivacy(false); + + print("\n\tSending MIC to peer."); + + //now perform a signature on the received data + byte []peerTok = bos.toByteArray(); + byte []toPeer = aCtxt.getMIC(peerTok, 0, peerTok.length, mInfo); + + //send token to peer + dos.writeInt(toPeer.length); + dos.write(toPeer); + dos.close(); + + } + + + /** + * Display usage message. + */ + private static void usage() { + + print("\nUsage:\tGSSServert [-mech 1.2.34] [-port port] serviceName"); + } + + + /** + * Utility method to display a string on the console. + */ + private static void print(String msg) { + + System.out.println(msg); + } + + + /** + * Terminates the application, performing socket cleanup. + */ + private static void exit(int status) { + + if (s != null) { + try { + s.close(); + } catch (IOException e) {}; + } + + System.exit(status); + } + + + //private class variables + private static ServerSocket s; +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/http/XFileAccessor.java b/mucommander-protocol-nfs/src/main/java/com/sun/http/XFileAccessor.java new file mode 100644 index 0000000000..eb5e928592 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/http/XFileAccessor.java @@ -0,0 +1,378 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.http; + +import com.sun.xfile.*; +import java.net.URL; +import java.net.URLConnection; +import java.io.*; + +/** + * The XFileAccessor interface is implemented by filesystems that + * need to be accessed via the XFile API. + * + * @author Brent Callaghan + * @version 1.0, 04/08/98 + * @see com.sun.xfile.XFile + */ +public class XFileAccessor implements com.sun.xfile.XFileAccessor { + + XFile xf; + URL url; + URLConnection urlConn; + InputStream iStream; + OutputStream oStream; + long fp; // file pointer + + /** + * Open this file object + * + * @param xf the XFile for this file + * @param serial true if serial access + * @param readOnly true if read only + */ + public boolean open(XFile xf, boolean serial, boolean readOnly) { + + if (! serial) + return false; + + this.xf = xf; + + try { + url = new URL(xf.toString()); + urlConn = url.openConnection(); + + urlConn.setDoInput(readOnly); + urlConn.setDoOutput(! readOnly); + + urlConn.connect(); + + return true; + + } catch (IOException e) { + return false; + } + } + + + /** + * Get the XFile for this Accessor + * + * @return XFile for this object + */ + public XFile getXFile() { + return xf; + } + + /** + * Tests if this XFileAccessor object exists. + * + * @return true if the file specified by this object + * exists; false otherwise. + */ + public boolean exists() { + try { + if (iStream == null) + iStream = urlConn.getInputStream(); + + return true; + + } catch (IOException e) { + return false; + } + } + + + /** + * Tests if the application can write to this file. + * + * @return true if the application is allowed to + * write to a file whose name is specified by this + * object; false otherwise. + */ + public boolean canWrite() { + try { + if (oStream == null) + oStream = urlConn.getOutputStream(); + + return true; + + } catch (IOException e) { + return false; + } + } + + + /** + * Tests if the application can read from the specified file. + * + * @return true if the file specified by this + * object exists and the application can read the file; + * false otherwise. + */ + public boolean canRead() { + return exists(); + } + + /** + * Tests if the file represented by this + * object is a "normal" file. + *

+ * A file is "normal" if it is not a directory and, in + * addition, satisfies other system-dependent criteria. Any + * non-directory file created by a Java application is + * guaranteed to be a normal file. + * + * @return true if the file specified by this + * XFile object exists and is a "normal" + * file; false otherwise. + */ + public boolean isFile() { + return true; + } + + + /** + * Tests if the file represented by this XFileAccessor + * object is a directory. + * + * @return true if this XFileAccessor object + * exists and is a directory; false + * otherwise. + */ + public boolean isDirectory() { + return false; + } + + + /** + * Returns the time that the file represented by this + * XFile object was last modified. + *

+ * The return value is system dependent and should only be + * used to compare with other values returned by last modified. + * It should not be interpreted as an absolute time. + * + * @return the time the file specified by this object was last + * modified, or 0L if the specified file + * does not exist. + */ + public long lastModified() { + return urlConn.getLastModified(); + } + + + /** + * Returns the length of the file represented by this + * XFileAccessor object. + * + * @return the length, in bytes, of the file specified by + * this object, or 0L if the specified + * file does not exist. + */ + public long length() { + long len = urlConn.getContentLength(); + + return len < 0 ? 0 : len; + } + + + /** + * Creates a file whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the file could be created; + * false otherwise. + */ + public boolean mkfile() { + try { + if (oStream == null) + oStream = urlConn.getOutputStream(); + + return true; + + } catch (IOException e) { + return false; + } + } + + + /** + * Creates a directory whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the directory could be created; + * false otherwise. + */ + public boolean mkdir() { + return false; + } + + + /** + * Renames the file specified by this XFileAccessor object to + * have the pathname given by the XFileAccessor object argument. + * + * @param dest the new filename. + * @return true if the renaming succeeds; + * false otherwise. + */ + public boolean renameTo(XFile dest) { + return false; + } + + + /** + * Returns a list of the files in the directory specified by + * this XFileAccessor object. + * + * @return an array of file names in the specified directory. + * This list does not include the current directory or + * the parent directory ("." and + * ".." on Unix systems). + */ + public String[] list() { + return new String[0]; + } + + + /** + * Deletes the file specified by this object. If the target + * file to be deleted is a directory, it must be empty for + * deletion to succeed. + * + * @return true if the file is successfully deleted; + * false otherwise. + */ + public boolean delete() { + return false; + } + + + /** + * Reads a subarray as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param foff the offset into the file + * @return number of bytes read; -1 if EOF + * @exception IOException If an I/O error has occurred. + */ + public int read(byte b[], int off, int len, long foff) + throws IOException { + + int c; + + if (iStream == null) + iStream = urlConn.getInputStream(); + + if (foff > fp) { + iStream.skip(foff - fp); + fp = foff; + } + + c = iStream.read(b, off, len); + + if (c > 0) + fp += c; + + return (c); + } + + + /** + * Writes a sub array as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param foff the offset into the file + * @exception IOException If an I/O error has occurred. + */ + public void write(byte b[], int off, int len, long foff) + throws IOException { + + if (oStream == null) + oStream = urlConn.getOutputStream(); + + oStream.write(b, off, len); + + fp += len; + } + + + /** + * Forces any buffered output bytes to be written out. + *

+ * + * @exception IOException if an I/O error occurs. + */ + public void flush() throws IOException { + if (oStream != null) + oStream.flush(); + } + + + /** + * Close the Streams + * + * @exception IOException If an I/O error has occurred. + */ + public void close() throws IOException { + + if (iStream != null) { + iStream.close(); + iStream = null; + } + if (oStream != null) { + oStream.close(); + oStream = null; + } + } + + + /** + * Returns a string representation of this object. + * + * @return a string giving the pathname of this object. + */ + public String toString() { + return url.toString(); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Buffer.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Buffer.java new file mode 100644 index 0000000000..6eaddfbac1 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Buffer.java @@ -0,0 +1,403 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.rpc.*; + +/** + * Here we do all the NFS read and write buffering. + * + * @see Nfs + * @see Nfs2 + * @see Nfs3 + * @author Brent Callaghan + */ + +public class Buffer extends Thread { + + Nfs nfs; + long foffset; + + byte[] buf; // The buffer itself + int bufoff; // Offset into the buffer + int buflen; // Bytes in buffer + int bufsize; // Size of buffer + + int minOffset; // First byte written + int maxOffset; // Last byte written + + int status; + private int action; + boolean eof; + IOException e; + Error err; + long writeVerifier; + int syncType; + + // Various kinds of action + + private final static int IDLE = 0; + private final static int LOAD = 1; + private final static int UNLOAD = 2; + private final static int EXIT = 3; + + /* + * The initial state of a buffer is EMPTY. + * When file data is read into a file it becomes LOADED. + * If the buffer contains data that has not yet been written + * to the file then it is DIRTY. + * The COMMIT state indicates that the data is written but + * not yet committed. Once committed, the state returns + * to LOADED. + */ + final static int EMPTY = 0; // Has no data + final static int LOADED = 1; // Has file data + final static int DIRTY = 2; // Has new data + final static int COMMIT = 3; // Not committed + + public Buffer(Nfs nfs, long foffset, int bufsize) { + this.nfs = nfs; + this.foffset = foffset; + this.bufsize = bufsize; + this.buflen = 0; + + minOffset = bufsize; + maxOffset = 0; + + setDaemon(true); // NFS threads die when app exits + try { + setName("Buffer-" + (foffset / bufsize)); + } catch (Exception e) {}; // non-essential, ignore + action = IDLE; + start(); + } + + /* + * Copy data from a buffer. + * We assume the buffer is loaded with data + */ + synchronized int copyFrom(byte[] buff, int boff, long foffset, int length) + throws IOException { + + /* + * May have gotten an async exception + * so throw it here. + */ + if (e != null) + throw e; + if (err != null) + throw err; + + if (status == EMPTY) + throw new IOException("no data"); + + /* + * We may have a partial buffer if the file + * has since been extended by a write into + * another buffer that is not yet unloaded. + * We must make sure that the buffer is complete. + */ + if (buflen < bufsize) { + byte[] nbuf = new byte[bufsize]; // bigger buffer + if (buflen > 0) + System.arraycopy(buf, bufoff, nbuf, 0, buflen); + buflen = bufsize; + bufoff = 0; + buf = nbuf; + } + + int off = (int) (foffset - this.foffset); + int copylen = Math.min(length, buflen - off); + copylen = (int) Math.min((long)copylen, nfs.length() - foffset); + + System.arraycopy(buf, bufoff + off, buff, boff, copylen); + + return copylen; + } + + /* + * Copy data to a buffer. + * If the buffer maps to a valid offset of a file then first + * make sure data is loaded from the file into the buffer. + * Record the range of data modified in the buffer so that + * when the buffer is written only the modified range is + * written back to the server. + */ + synchronized int copyTo(byte[] buff, int boff, long foffset, int length) + throws IOException { + + /* + * May have gotten an async exception + * so throw it here. + */ + if (e != null) + throw e; + if (err != null) + throw err; + + int off = (int) (foffset - this.foffset); + int copylen = Math.min(length, bufsize - off); + + /* + * If writing less than a full buffer and if + * overwriting existing file data, then make + * sure the buffer is loaded from the file. + */ + if (status == EMPTY) { + long bufEnd = Math.min(nfs.length(), this.foffset + nfs.wsize); + + if (this.foffset < nfs.length() && + (foffset > this.foffset || foffset + length < bufEnd)) { + startLoad(); + waitLoaded(); + } + } + + /* + * May need to extend the size of the buffer + */ + if (off + copylen > buflen) { + byte[] nbuf = new byte[bufsize]; + if (buf != null) + System.arraycopy(buf, bufoff, nbuf, 0, buflen); + buf = nbuf; + bufoff = 0; + buflen = bufsize; + } + + System.arraycopy(buff, boff, buf, bufoff + off, copylen); + + status = DIRTY; + + /* + * Record the range of the buffer that's been + * modified so that we can write less than + * the full buffer if possible. + */ + if (off < minOffset) + minOffset = off; + + if (off + copylen > maxOffset) + maxOffset = off + copylen; + + return copylen; + } + + /* + * Notify the buffer thread that it is to read data + */ + synchronized void startLoad() { + action = LOAD; + notifyAll(); + } + + /* + * Wait until the buffer thread has finished loading the buffer + */ + synchronized void waitLoaded() throws IOException { + + /* + * Check for an exception thrown by the async thread + * in case the thread died and we block forever + * waiting for the buffer state to change. + */ + if (e != null) + throw e; + if (err != null) + throw err; + + while (this.status == EMPTY) { + try { + wait(); + } catch (InterruptedException e) {} + + if (this.e != null) + throw this.e; + if (err != null) + throw err; + } + } + + /* + * Wait until the buffer thread is finished writing the buffer + */ + synchronized void waitUnloaded() throws IOException { + + /* + * Check in case async thread threw an + * exception and died. + */ + if (e != null) + throw e; + if (err != null) + throw err; + + while (action == UNLOAD) { + try { + wait(); + } catch (InterruptedException e) {} + + if (this.e != null) + throw this.e; + if (err != null) + throw err; + } + } + + + /* + * Notify the buffer thread that it is to write data + */ + synchronized void startUnload(int sync) { + nfs.beginWrite(); + + action = UNLOAD; + syncType = sync; + notifyAll(); + } + + /* + * Request the buffer thread to exit cleanly + */ + synchronized void exit() { + + action = EXIT; + notifyAll(); + } + + /* + * This is the run method for the buffer thread. + * It is started when the buffer is instantiated + * and sleeps on the monitor waiting to be woken + * up and perform one of two actions: LOAD data + * (write) or UNLOAD data (read). + */ + public void run() { + + synchronized (this) { + try { + while (true) { + + while (action == IDLE) { + try { + wait(); + } catch (InterruptedException e) {} + } + + /* + * Thread has been notified - perform the action + */ + switch (action) { + + case LOAD: + try { + nfs.read_otw(this); + + } catch (IOException e) { + if (this.e == null) + this.e = e; + } + + status = LOADED; + break; + + case UNLOAD: + try { + + /* + * Server may do a short write, so keep + * writing until all the bytes have been + * written. + */ + int saveMin = minOffset; + while (minOffset < maxOffset) + minOffset += nfs.write_otw(this); + + minOffset = bufsize; + maxOffset = 0; + + } catch (IOException e) { + if (this.e == null) + this.e = e; + } + nfs.endWrite(); + break; + + case EXIT: + notifyAll(); + + /* + * XXX Dereferencing the buf here should not be + * necessary since the entire buffer is dereferenced + * from the bufferList in Nfs, however for some reason + * the GC is ignoring dereferenced buffers. + * Setting buf to null makes sure that the GC collects + * the bulk of the memory tied up in a buffer, even + * if the Buffer object itself is not reclaimed. + */ + buf = null; + + return; + } + + action = IDLE; + notifyAll(); + } + } catch (Error e) { + /* + * Need to catch errors here, e.g. OutOfMemoryError + * and notify threads before this thread dies + * otherwise they'll wait forever. + */ + err = e; + notifyAll(); + throw e; + } + } + } + + public String toString() { + return (nfs.name + " @ " + foffset + " for " + buflen); + } + +// protected void finalize() throws Throwable { +// System.out.println("#### BUFFER FINALIZE " + toString()); +// super.finalize(); +// } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Fattr.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Fattr.java new file mode 100644 index 0000000000..90bbad6034 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Fattr.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import com.sun.rpc.*; + +/** + * + * NFS file attributes + * + * This is essentially a container class that holds + * the attributes, but it also has methods to encode + * and decode the attributes in an Xdr buffer. + * + * Note that the time at which the attributes were + * retrieved is automatically updated and the cache + * time varies according to the frequency of file + * modification. + * + * There are two subclasses: Fattr2 for NFS v2 + * attributes and Fattr3 for v3. + * + * @see Nfs + * @see Fattr2 + * @see Fattr3 + * @author Brent Callaghan + */ +public abstract class Fattr { + + long validtime; // time when attrs were new + long cachetime; // max cache duration in ms + static final int ACMIN = 3 * 1000; // 3 sec - min cache time + static final int ACMAX = 60 * 1000; // 1 min - max cache time + + static final int NOBODY = 60001; // Svr4 UID/GID "nobody" + static final int NFS_NOBODY = -2; // NFS UID/GID "nobody" + + + /** + * Check if the attributes are "fresh" enough. + * + * If not, then the caller will likely update + * the attributes with an NFS getattr request. + * + * @returns true if the attributes are valid + */ + boolean valid() { + long timenow = System.currentTimeMillis(); + + return (timenow <= validtime + cachetime); + } + + abstract void putFattr(Xdr x); + + abstract void getFattr(Xdr x); +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Fattr2.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Fattr2.java new file mode 100644 index 0000000000..e6ad22a353 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Fattr2.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.rpc.*; +import java.util.Date; + +/** + * + * NFS version 2 file attributes + * + */ +class Fattr2 extends Fattr { + int ftype; + long mode; + long nlink; + long uid; + long gid; + long size; + long blocksz; + long rdev; + long blocks; + long fsid; + long fileid; + long atime; + long mtime; + long ctime; + + Fattr2() { + } + + Fattr2 (Xdr x) { + this.getFattr(x); + } + + void putFattr(Xdr x) { + x.xdr_int(ftype); + x.xdr_u_int(mode); + x.xdr_u_int(nlink); + x.xdr_u_int(uid); + x.xdr_u_int(gid); + x.xdr_u_int(size); + x.xdr_u_int(blocksz); + x.xdr_u_int(rdev); + x.xdr_u_int(blocks); + x.xdr_u_int(fsid); + x.xdr_u_int(fileid); + x.xdr_u_int(atime / 1000); // sec + x.xdr_u_int(atime % 1000); // msec + x.xdr_u_int(mtime / 1000); // sec + x.xdr_u_int(mtime % 1000); // msec + x.xdr_u_int(ctime / 1000); // sec + x.xdr_u_int(ctime % 1000); // msec + } + + void getFattr(Xdr x) { + long oldmtime = mtime; + + ftype = x.xdr_int(); + mode = x.xdr_u_int(); + nlink = x.xdr_u_int(); + uid = x.xdr_u_int(); if (uid == NFS_NOBODY) uid = NOBODY; + gid = x.xdr_u_int(); if (gid == NFS_NOBODY) gid = NOBODY; + size = x.xdr_u_int(); + blocksz = x.xdr_u_int(); + rdev = x.xdr_u_int(); + blocks = x.xdr_u_int(); + fsid = x.xdr_u_int(); + fileid = x.xdr_u_int(); + atime = x.xdr_u_int() * 1000 + x.xdr_u_int(); + mtime = x.xdr_u_int() * 1000 + x.xdr_u_int(); + ctime = x.xdr_u_int() * 1000 + x.xdr_u_int(); + + /* + * We want the cache time to be short + * for files/dirs that change frequently + * and long for files/dirs that change + * infrequently. So set the cache time to + * the delta between file modifications + * limited by ACMIN and ACMAX + */ + long delta = mtime - oldmtime; + if (delta > 0) { + cachetime = delta; + if (cachetime < ACMIN) + cachetime = ACMIN; + else if (cachetime > ACMAX) + cachetime = ACMAX; + } + validtime = System.currentTimeMillis(); + } + + public String toString() { + return ( + " ftype = " + ftype + "\n" + + " mode = 0" + Long.toOctalString(mode) + "\n" + + " nlink = " + nlink + "\n" + + " uid = " + uid + "\n" + + " gid = " + gid + "\n" + + " size = " + size + "\n" + + "blocksz = " + blocksz + "\n" + + " rdev = 0x" + Long.toHexString(rdev) + "\n" + + " blocks = " + blocks + "\n" + + " fsid = " + fsid + "\n" + + " fileid = " + fileid + "\n" + + " atime = " + new Date(atime) + "\n" + + " mtime = " + new Date(mtime) + "\n" + + " ctime = " + new Date(ctime) + ); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Fattr3.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Fattr3.java new file mode 100644 index 0000000000..db3d13cf04 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Fattr3.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.rpc.*; +import java.util.Date; + +/** + * + * NFS version 3 file attributes + * + */ +class Fattr3 extends Fattr { + int ftype; + long mode; + long nlink; + long uid; + long gid; + long size; + long used; + long rdev; + long fsid; + long fileid; + long atime; + long mtime; + long ctime; + + Fattr3() { + } + + Fattr3(Xdr x) { + this.getFattr(x); + } + + void putFattr(Xdr x) { + x.xdr_int(ftype); + x.xdr_u_int(mode); + x.xdr_u_int(nlink); + x.xdr_u_int(uid); + x.xdr_u_int(gid); + x.xdr_hyper(size); + x.xdr_hyper(used); + x.xdr_hyper(rdev); + x.xdr_hyper(fsid); + x.xdr_hyper(fileid); + x.xdr_u_int(atime / 1000); // sec + x.xdr_u_int(atime % 1000 * 1000000); // nsec + x.xdr_u_int(mtime / 1000); // sec + x.xdr_u_int(mtime % 1000 * 1000000); // nsec + x.xdr_u_int(ctime / 1000); // sec + x.xdr_u_int(ctime % 1000 * 1000000); // nsec + } + + void getFattr(Xdr x) { + long oldmtime = mtime; + + ftype = x.xdr_int(); + mode = x.xdr_u_int(); + nlink = x.xdr_u_int(); + uid = x.xdr_u_int(); if (uid == NFS_NOBODY) uid = NOBODY; + gid = x.xdr_u_int(); if (gid == NFS_NOBODY) gid = NOBODY; + size = x.xdr_hyper(); + used = x.xdr_hyper(); + rdev = x.xdr_hyper(); + fsid = x.xdr_hyper(); + fileid = x.xdr_hyper(); + atime = x.xdr_u_int() * 1000 + x.xdr_u_int() / 1000000; + mtime = x.xdr_u_int() * 1000 + x.xdr_u_int() / 1000000; + ctime = x.xdr_u_int() * 1000 + x.xdr_u_int() / 1000000; + + /* + * We want the cache time to be short + * for files/dirs that change frequently + * and long for files/dirs that change + * infrequently. So set the cache time to + * the delta between file modifications + * limited by ACMIN and ACMAX + */ + long delta = mtime - oldmtime; + if (delta > 0) { + cachetime = delta; + if (cachetime < ACMIN) + cachetime = ACMIN; + else if (cachetime > ACMAX) + cachetime = ACMAX; + } + validtime = System.currentTimeMillis(); + } + + public String toString() { + return ( + " ftype = " + ftype + "\n" + + " mode = 0" + Long.toOctalString(mode) + "\n" + + " nlink = " + nlink + "\n" + + " uid = " + uid + "\n" + + " gid = " + gid + "\n" + + " size = " + size + "\n" + + " used = " + used + "\n" + + " rdev = 0x" + Long.toHexString(rdev) + "\n" + + " fsid = " + fsid + "\n" + + "fileid = " + fileid + "\n" + + " atime = " + new Date(atime) + "\n" + + " mtime = " + new Date(mtime) + "\n" + + " ctime = " + new Date(ctime) + ); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Mount.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Mount.java new file mode 100644 index 0000000000..a50e077f3c --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Mount.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.rpc.*; + +/** + * Handle the mount protocol for NFS versions 2 and 3 + * + * Note that we transmit an unmount request immediately + * after a successful mount request. This avoids having + * "mount" entries pile up in the server's /etc/rmtab log. + * + * @see Nfs + * @author Brent Callaghan + */ +class Mount { + private final static int MOUNTPROG = 100005; + + private final static int MOUNTPROC_MNT = 1; + private final static int MOUNTPROC_UMNT = 3; + private final static int MOUNTPROC_EXPORT = 5; + + private final static int FHSIZE = 32; + private final static int FHSIZE3 = 64; + + private final static int ENOENT = 2; + private final static int EACCES = 13; + + String sec_flavor; + + /** + * Get an NFS v2 or v3 file handle + * + * @param server The NFS server + * @param path The file path on the server + * @param vers The NFS version + * @returns The filehandle as a byte array + */ + byte[] getFH(String server, String path, int vers) + throws java.net.UnknownHostException, IOException { + Rpc mnt; + Xdr callmsg = new Xdr(1024); + int status; + byte[] fh; + + // Use Mount v1 for NFS v2, Mount v3 for NFS v3 + + mnt = new Rpc(server, 0, MOUNTPROG, vers == 2 ? 1 : 3, "udp", 512); + mnt.setCred(new CredUnix(0, 0)); + mnt.rpc_header(callmsg, MOUNTPROC_MNT); + callmsg.xdr_string(path); + + Xdr replymsg = mnt.rpc_call(callmsg, 3 * 1000, 3); + + status = replymsg.xdr_int(); + if (status != 0) { + /* + * If ENOENT is returned and the path didn't + * start with a slash then assume it's because + * the URL didn't include it (a common mistake). + * Add the slash and try again. + */ + if ((status == ENOENT || status == EACCES) && ! path.startsWith("/")) + return getFH(server, "/" + path, vers); + + throw new IOException("Mount status: " + status); + } + + // Filehandle is different depending on version + + fh = vers == 2 ? replymsg.xdr_raw(FHSIZE) : replymsg.xdr_bytes(); + + // Get security flavors if this is MOUNT V3. + sec_flavor = null; + if (vers == 3) { + int numsec = replymsg.xdr_int(); + String prefer = NfsSecurity.getPrefer(); + while (numsec-- > 0) { + String secmode = Integer.toString(replymsg.xdr_int()); + + if ((prefer != null) && prefer.equals(secmode)) { + sec_flavor = prefer; + } + + if ((sec_flavor == null) && + NfsSecurity.hasValue(secmode)) { + sec_flavor = secmode; + } + } // while + } + if (sec_flavor == null) { + sec_flavor = NfsSecurity.getDefault(); + } + + /* + * Now send an unmount request + */ + mnt.rpc_header(callmsg, MOUNTPROC_UMNT); + callmsg.xdr_string(path); + try { + mnt.rpc_call(callmsg, 1000, 1); + } catch (InterruptedIOException e) { + // ignore + } + + return (fh); + } + + /* + * get the sec_flavor after a successful getMountInfo() + */ + String getSec() { + return (sec_flavor); + } + + /* + * Get the server's export list + * + */ + static String[] getExports(String server) + throws java.net.UnknownHostException, IOException { + Rpc mnt; + Xdr callmsg = new Xdr(255); + Xdr replymsg; + String[] elist = new String[32]; + int i = 0; + + try { + mnt = new Rpc(server, 0, MOUNTPROG, 1, "tcp", 8192); + mnt.setCred(new CredUnix(0, 0)); + mnt.rpc_header(callmsg, MOUNTPROC_EXPORT); + + // This RPC proc takes no arguments + + replymsg = mnt.rpc_call(callmsg, 3 * 1000, 3); + + } catch (java.net.UnknownHostException e) { + throw e; + + } catch (IOException e) { + return new String[0]; // an empty export list + } + + /* + * The exports come back as a linked list. + * Walk along the list extracting the export names + * into an array and ignore the associated groups list. + */ + while (replymsg.xdr_bool()) { + elist[i++] = replymsg.xdr_string(); + if (i >= elist.length) { // last elem in array ? + String[] tmp = elist; + + elist = new String[i*2]; // double its size + System.arraycopy(tmp, 0, elist, 0, i); + } + + /* + * Skip the groups list + */ + while (replymsg.xdr_bool()) { + replymsg.xdr_string(); + } + } + + /* + * Trim export list to exact size + */ + if (i < elist.length) { + String[] tmp = elist; + + elist = new String[i]; + System.arraycopy(tmp, 0, elist, 0, i); + } + + return elist; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Nfs.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Nfs.java new file mode 100644 index 0000000000..a05c593141 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Nfs.java @@ -0,0 +1,731 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.rpc.*; +import java.util.Hashtable; +import java.util.Vector; + +/** + * + * Container class for an NFS object: either a file + * or a directory. Herein are common + * methods that are not version specific. + * + * This class holds the file's filehandle, name, + * and attributes. If a regular file then data may + * be cached in an XDR buffer. If a directory then + * the string array for the entries will be cached. + * There's also a static hash table that's used to cache + * these Nfs objects. + * + * @see Nfs2 + * @see Nfs3 + * @see Buffer + * @author Brent Callaghan + * @author Ricardo Labiaga + */ +public abstract class Nfs { + byte[] fh; + Rpc rpc; + String name; + String[] dircache; + String symlink; + Buffer[] bufferList; + long cacheTime; // Time when object was cached + int rsize, wsize; + private Object wbLock = new Object(); // write-behind semaphore lock + static Hashtable cacheNfs = new Hashtable(); + + // Some of the filetypes we're dealing with. + + static final int NFREG = 1; + static final int NFDIR = 2; + static final int NFLNK = 5; + + // Flags for asynchronous or synchronous writes + + private final static int ASYNC = 0; + private final static int SYNC = 2; + + int NRA; // max reads-ahead (set in subclass constructor) + int NWB; // max writes-behind (") + int NWC; // max writes committed (") + int nwb; // current writes-behind + int prevReadIndex = -1; // Buffer index of previous read + int prevWriteIndex = -1; // Buffer index of previous write + int maxIndexRead = 0; // Max file offset read + long maxLength = 0; // Size of file + + // Some important permission bits + + static final int RBIT = 004; + static final int WBIT = 002; + + /* + * The following abstract classes are version-specific + * and are implemented in the version subclasses. + */ + + abstract void checkAttr() throws IOException; + + abstract boolean cacheOK(long t) throws IOException; + + abstract void getattr() throws IOException; + + abstract long mtime() throws IOException; + + abstract long length() throws IOException; + + abstract boolean exists() throws IOException; + + abstract boolean canWrite() throws IOException; + + abstract boolean canRead() throws IOException; + + abstract boolean isFile() throws IOException; + + abstract boolean isDirectory() throws IOException; + + abstract boolean isSymlink() throws IOException; + + abstract Fattr getAttr() throws IOException; + + abstract Nfs lookup(String path) throws IOException; + + abstract String lookupSec() throws IOException; + + abstract void read_otw(Buffer b) throws IOException; + + abstract int write_otw(Buffer buf) throws IOException; + + abstract String[] readdir() throws IOException; + + abstract String readlink() throws IOException; + + abstract Nfs create(String name, long mode) throws IOException; + + abstract Nfs mkdir(String name, long mode) throws IOException; + + abstract boolean remove(String name) throws IOException; + + abstract boolean rename(Nfs dstP, String sName, String dName) throws IOException; + + abstract boolean rmdir(String name) throws IOException; + + abstract void fsinfo() throws IOException; + + abstract long commit(int foffset, int length) throws IOException; + + abstract void invalidate(); + + + /* + * The following methods are all NFS version independent. + */ + + /* + * Get FileHandle for Nfs Object + */ + byte[] getFH() { + return (fh); + } + + /* + * Cache an Nfs object + * + * @param n the object to be cached + */ + static void cache_put(Nfs n) { + cacheNfs.put(n.rpc.conn.server + ":" + n.name, n); + } + + /* + * Retrieve a cached Nfs object + * + * @param server The server that hosts the object + * @param name The pathname of the object + * @returns The object - or null if not cached + */ + static Nfs cache_get(String server, String name) { + return ((Nfs)cacheNfs.get(server + ":" + name)); + } + + /* + * Remove an Nfs object from the cache + * + * @param n the object to be removed from cache + */ + static void cache_remove(Nfs n, String name) { + if (n.name.equals(".")) + cacheNfs.remove(n.rpc.conn.server + ":" + name); + else + cacheNfs.remove(n.rpc.conn.server + ":" + n.name + "/" + name); + } + + /** + * Read data from the specified file offset + * + * @param buf The destination buffer + * @param boff Offset into the dest buffer + * @param length Amount of data to read + * @param foffset File offset to begin reading + * @exception java.io.IOException + * @return actual bytes read + */ + synchronized int read(byte[] buf, int boff, int length, long foffset) + throws IOException { + + Buffer b = null; + int index; + int readAhead = 0; + int bytesRead = 0; + + /* + * If the file modification time has changed since + * the last read then invalidate all cached buffers. + */ + if (!cacheOK(cacheTime) && bufferList != null) { + for (int i = 0; i < bufferList.length; i++) + if (i != prevWriteIndex) // don't delete dirty buffers + bufferList[i] = null; + + prevReadIndex = -1; + } + + /* + * Check whether we're at EOF + */ + if (foffset >= length()) + return -1; + + /* + * Keep reading until the read request is satisfied. + */ + while (length > 0) { + + /* + * Check whether we're at EOF + */ + if (foffset >= length()) + break; + + /* + * Make sure an array of buffers exists that's big enough + * to for the entire file. + */ + if (bufferList == null) + bufferList = new Buffer[(int) (length() / rsize + 1)]; + + /* + * Find the block that holds the data + */ + index = (int) (foffset / rsize); + if (index > maxIndexRead) + maxIndexRead = index; + + /* + * Make sure that previously read buffers are + * released. If not, then reading a large file + * would quickly run the app out of memory, though + * must be careful not to release in-use write buffers. + * XXX We should find a way to make better use of + * available memory and keep file buffers cached. + */ + if (index != prevReadIndex) { + if (prevReadIndex >= 0 && prevReadIndex != prevWriteIndex) { + b = bufferList[prevReadIndex]; + if (b.status == b.LOADED) { + bufferList[prevReadIndex] = null; + b.exit(); + } + + /* + * Do read-ahead only for sequential I/O + */ + if (index == (prevReadIndex + 1) && index >= maxIndexRead) + readAhead = NRA; + } + prevReadIndex = index; + } + + /* + * Make sure that the buffer is + * are loaded or loading - as well as + * any buffers that will likely be needed + * i.e. read-ahead buffers. + */ + for (int n = index; n <= index + readAhead; n++) { + + if (n >= bufferList.length) + break; + + b = bufferList[n]; + if (b == null) { + b = new Buffer(this, (long) n * (long) rsize, rsize); + b.startLoad(); + bufferList[n] = b; + } + } + + /* + * Now select the buffer and wait until its not busy. + */ + b = bufferList[index]; + try { + b.waitLoaded(); + } catch (NfsException n) { + /* + * Check if it's a bogus "EBADRPC" + * error from a Digital Unix server. + * It implies that the read was too + * long. The server should just return + * a short read - but until they fix it + * we'll handle it here. + * Optimistically set the read + * size to 8k and try again. + */ + if (n.error == 72) { // DEC's EBADRPC + rsize = 8192; + bufferList = + new Buffer[(int)(length() / rsize + 1)]; + continue; + } + + throw n; + } + + /* + * If the buffer contains less data than requested + * and it's not EOF, then assume that we guessed + * too big for the server's transfer size. + */ + int bufflen = b.buflen; + if (bufflen < rsize && !b.eof) { + rsize = bufflen; + bufferList = null; + prevReadIndex = -1; + prevWriteIndex = -1; + + continue; // Try again with new rsize + } + + /* + * Copy data from the file buffer into the application buffer. + */ + int cc = b.copyFrom(buf, boff, foffset,length); + + boff += cc; + foffset += cc; + length -= cc; + bytesRead += cc; + } + + return (bytesRead); + } + + /* + * These two methods implement a semaphore to prevent the client from + * generating an huge number of write-behind threads that could + * overload the server. + * + * These methods synchronize on wbLock rather than the + * class monitor otherwise there's a risk of deadlock + * through Nfs.write() -> Buffer.startUnload() -> Nfs.beginWrite() + */ + void beginWrite() { + synchronized (wbLock) { + while (nwb >= NWB) { + try { + wbLock.wait(); + } catch (InterruptedException e) {} + } + nwb++; + } + } + + void endWrite() { + synchronized (wbLock) { + nwb--; + wbLock.notify(); + } + } + + /** + * Write data to a file at a specified offset. + * + * @param buf The data to write + * @param boff Offset into the data buffer + * @param length Amount of data to write + * @param foffset File offset to begin writing at + * @exception java.io.IOException + */ + synchronized void write(byte buf[], int boff, int length, long foffset) + throws IOException { + + /* + * If the write size is not set then call FSINFO + * to set it. We would prefer not to make this call + * since it adds an extra turnaround, but the alternative + * is to guess at the write size by trying a large write + * and see how many bytes the server writes. If we're doing + * async write-behind it'll take complex code to recover + * from a series of partial writes that would wreak havoc with + * any write gathering that the server might be doing. So + * it's likely safer just to have the server tell us its + * preferred write size as the protocol intended. + */ + if (wsize == 0) + fsinfo(); + + /* + * If we haven't read the file yet then there may + * be no buffer list. Allocate one that will hold + * all of the existing file blocks, or if it's a newly + * created file, assume an initial size of 50 blocks. + */ + if (bufferList == null) { + long fileSize = Math.max(length(), 50 * wsize); + bufferList = new Buffer[(int)(fileSize / wsize + 1)]; + } + + /* + * Keep writing data to the server in buffer-size chunks + * until the write request is satisfied. If the write + * is a short one into an existing buffer then no data + * will be written at all. This is good, it's much more + * efficient to write larger amounts of data to the server. + * + * We get further improvement in write throughput by writing + * buffers asynchronously in a buffer thread. This allows the + * application to continue filling a new buffer while previous + * buffers are written. + * + * This method takes advantage of the ability of NFS version 3 + * to perform safe, asynchronous writes which significantly + * increase write throughput. + */ + while (length > 0) { + + int index = (int)(foffset / wsize); + + /* + * If writing into a new buffer + * start writing out the previous one. + */ + if (index != prevWriteIndex) { + if (prevWriteIndex >= 0) { + bufferList[prevWriteIndex].startUnload(ASYNC); + + checkCommit(false); + } + prevWriteIndex = index; + } + + /* + * If trying to write to a buffer off the end of + * the current buffer list, then double the size + * of the buffer list. + */ + if (index >= bufferList.length) { + Buffer[] tlist = new Buffer[bufferList.length * 2]; + for (int i = 0; i < bufferList.length; i++) + tlist[i] = bufferList[i]; + bufferList = tlist; + } + + + /* + * Check if there's a buffer allocated + */ + Buffer b = bufferList[index]; + if (b == null) { + b = new Buffer(this, (long) index * wsize, wsize); + bufferList[index] = b; + } + + /* + * Copy data from the application buffer to the file buffer. + */ + int cc = b.copyTo(buf, boff, foffset, length); + + boff += cc; + foffset += cc; + length -= cc; + + /* + * Need to record max file offset here in case + * the app calls length() before the data has + * been written out and recorded in the file attrs. + */ + if (foffset > maxLength) + maxLength = foffset; + + } // end while + } + + /* + * Check the buffer list for buffers that should be released. + * Buffers must be released otherwise the entire file will + * become cached and we risk running out of memory. + * + * The same scan also checks for buffers that are pending + * commit. If it's a v2 server then there will be none, + * but if v3 and there are more than NWC of these then + * send a COMMIT request. Until these buffers are committed + * they cannot be released. The scan records the range of + * buffers pending commit for the benefit of the COMMIT + * request which requires an offset and range. + * + * This method is called with flushing set to true when + * the file is being closed. In this case the code must + * write the current buffer and wait for all write operations + * to complete. + */ + void checkCommit(boolean flushing) throws IOException { + + int minIndex = Integer.MAX_VALUE; + int maxIndex = 0; + int nwc = 0; + + /* + * Determine the first and last buffers in + * the buffer list that are waiting commit. + * Then we know the byte range to be committed. + * + * Also, release any LOADED buffers. + */ + for (int i = 0; i < bufferList.length; i++) { + Buffer b = bufferList[i]; + if (b != null) { + if (flushing) + b.waitUnloaded(); + + if (b.status == b.LOADED) { + + /* + * Don't throw away the "current" buffer + */ + if (i == prevReadIndex || i == prevWriteIndex) + continue; + + bufferList[i] = null; + b.exit(); + } else if (b.status == b.COMMIT) { + nwc++; + if (i < minIndex) + minIndex = i; + if (i > maxIndex) + maxIndex = i; + } + } + } + + /* + * If flushing write the "current" buffer if it is dirty. + * Here we catch writes to files no bigger than one + * buffer. It's better to do a single sync write than + * do an async write followed by a commit for a single + * buffer. + */ + if (flushing) { + Buffer b = bufferList[prevWriteIndex]; + if (b != null) { + if (b.status == b.DIRTY) { + if (nwc == 0) { // just one - do it sync + b.startUnload(SYNC); + b.waitUnloaded(); + } else { // more than one - do it async + b.startUnload(ASYNC); + b.waitUnloaded(); + + // Record the commit range + + if (prevWriteIndex < minIndex) + minIndex = prevWriteIndex; + if (prevWriteIndex > maxIndex) + maxIndex = prevWriteIndex; + } + } + } + } + + /* + * If writing to a v3 server then there may + * be some buffers pending commit. + * If the commit is successful the buffers can + * be released. + */ + if (nwc > 0 && (flushing || nwc >= NWC)) { + int commitOffset = minIndex * rsize + + bufferList[minIndex].minOffset; + int commitLength = (maxIndex * rsize + + bufferList[maxIndex].maxOffset) - commitOffset; + + long verf = commit(commitOffset, commitLength); + + /* + * Check the write verifiers of the buffers + * in the commit range. If each verifier + * matches then the buffer data are safe + * and we can release the buffer. + * If the verifier does not match its possible + * that the server lost the data so rewrite + * the buffer. + */ + for (int i = minIndex; i <= maxIndex; i++) { + Buffer b = bufferList[i]; + if (b == null) + continue; + + if (flushing) + b.waitUnloaded(); + + if (b.status == b.COMMIT) { + + /* + * Can now release committed buffers with + * matching verifiers iff they're not "current" + */ + if (b.writeVerifier == verf) { + + if (i == prevReadIndex || i == prevWriteIndex) { + b.status = b.LOADED; + continue; + } + + bufferList[i] = null; // release buffer + b.exit(); + } else { + + /* + * Have to rewrite. + * + * If flushing then do sync-writes because + * we can't return until the data are safe. + * Otherwise, we just fire off another async + * write and have it committed later. + */ + if (flushing) { + b.startUnload(SYNC); + b.waitUnloaded(); + } else { + b.startUnload(ASYNC); + } + } + } + } // end for + } + } + + /** + * Flush any buffered writes to the file. This must be + * called after any series of writes to guarantee that the + * data reach the server. + * @exception java.io.IOException if writes failed for some reason, e.g. + * if server ran out of disk space. + */ + synchronized public void flush() throws IOException { + if (prevWriteIndex >= 0) // if no writes then don't bother + checkCommit(true); + } + + /** + * Close the file by flushing data and + * deallocating buffers. + * @exception java.io.IOException if failure during flushing. + */ + synchronized public void close() throws IOException { + int n = 0; + + if (bufferList == null) + return; + + flush(); // unwritten data + + for (int i = 0; i < bufferList.length; i++) { + if (bufferList[i] != null) { + Buffer b = bufferList[i]; + bufferList[i] = null; + b.exit(); + } + } + + prevReadIndex = -1; + prevWriteIndex = -1; + } + + /* + * Make sure that pending writes are flushed if the app + * neglected to call flush(). + */ + protected void finalize() throws Throwable { + close(); + super.finalize(); + } + + public String toString() { + + try { + if (isSymlink()) { + if (symlink != null) + return "\"" + name + "\": symlink -> \"" + symlink + "\""; + else + return "\"" + name + "\": symlink"; + + } + + if (isDirectory()) { + String s = "\":" + name + "\" directory"; + + if (dircache != null) + return s + "(" + dircache.length + " entries)"; + else + return s; + } + + // Must be a regular file + + return "\"" + name + "\": file (" + length() + " bytes)"; + + } catch (IOException e) { + return e.getMessage(); + } + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Nfs2.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Nfs2.java new file mode 100644 index 0000000000..372ee72e13 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Nfs2.java @@ -0,0 +1,832 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.rpc.*; + +/** + * This class contains the methods specific to + * NFS version 2. + * + * @see Nfs + * @see Nfs3 + * @see Fattr + * @author Brent Callaghan + * @author Ricardo Labiaga + */ +public class Nfs2 extends Nfs { + + Fattr2 attr; + + /* + * NFS version 2 procedure numbers + */ + private final static int NFSPROC2_NULL = 0; + private final static int NFSPROC2_GETATTR = 1; + private final static int NFSPROC2_SETATTR = 2; + private final static int NFSPROC2_LOOKUP = 4; + private final static int NFSPROC2_READLINK = 5; + private final static int NFSPROC2_READ = 6; + private final static int NFSPROC2_WRITE = 8; + private final static int NFSPROC2_CREATE = 9; + private final static int NFSPROC2_REMOVE = 10; + private final static int NFSPROC2_RENAME = 11; + private final static int NFSPROC2_LINK = 12; + private final static int NFSPROC2_SYMLINK = 13; + private final static int NFSPROC2_MKDIR = 14; + private final static int NFSPROC2_RMDIR = 15; + private final static int NFSPROC2_READDIR = 16; + private final static int NFSPROC2_STATFS = 17; + + private final static int NFS_OK = 0; + private final static int RWSIZE = 8192; // optimal read/write size + private final static int FHSIZE = 32; // file handle size + + int nwb; // current writes-behind + + /** + * Construct a new NFS version 2 object (file or directory) + * + * @param rpc Rpc object for the server + * @param fh File handle for the object + * @param name Name of the file/dir + * @param attr File attributes for the object + */ + public Nfs2(Rpc rpc, byte[] fh, String name, Fattr2 attr) { + this.rpc = rpc; + this.fh = fh; + if (name.startsWith("./")) // normalize for cache lookup + name = name.substring(2); + this.name = name; + this.attr = attr == null ? new Fattr2() : attr; + this.rsize = RWSIZE; + NRA = 2; // Max reads-ahead + NWB = 8; // Max writes-behind + } + + void getattr() throws IOException { + Xdr call = new Xdr(rsize + 512); + rpc.rpc_header(call, NFSPROC2_GETATTR); + call.xdr_raw(fh); + + Xdr reply; + + try { + reply = rpc.rpc_call(call, 2 * 1000, 2); + } catch (IOException e) { + // don't let a mere getattr hang + // the app if the server is down. + return; + } + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + attr.getFattr(reply); + } + + void checkAttr() throws IOException { + + if (! attr.valid()) + getattr(); + } + + boolean cacheOK(long t) throws IOException { + checkAttr(); + + return t == attr.mtime; + } + + void invalidate() { + attr.validtime = 0; + } + + /* + * Get the file modification time + * @return the time in milliseconds + */ + long mtime() throws IOException { + checkAttr(); + + return attr.mtime; + } + + /* + * Get the file size in bytes. + * + * Note that the size may be greater than that + * shown in the attributes if the file is being written. + * + * @return file size + */ + long length() throws IOException { + checkAttr(); + + return maxLength > attr.size ? maxLength : attr.size; + } + + /* + * Verify if file exists + * @return true if file exists + */ + boolean exists() throws IOException { + checkAttr(); + + return true; + } + + private boolean check_access(long mode) { + boolean found = false; + long uid = NfsConnect.getCred().getUid(); + long gid = NfsConnect.getCred().getGid(); + int gids[] = NfsConnect.getCred().getGids(); + + /* + * Access check is based on only + * one of owner, group, public. + * If not owner, then check group. + * If not a member of the group, + * then check public access. + */ + mode <<= 6; + if (uid != attr.uid) { + mode >>= 3; + if (gid != attr.gid) { + // check group list + int gidsLength = 0; + + if (gids != null) + gidsLength = gids.length; + + for (int i = 0; i < gidsLength; i++) + if (found = ((long)gids[i] == attr.gid)) + break; + if (!found) { + // not in group list, check "other" field + mode >>= 3; + } + } + } + + return (attr.mode & mode) == mode; + } + + /* + * Verify if file can be created/updated + * @return true if file can be created/updated + */ + boolean canWrite() throws IOException { + checkAttr(); + + return check_access(WBIT); + } + + /* + * Verify if file can be read + * @return true if file can be read + */ + boolean canRead() throws IOException { + checkAttr(); + + return check_access(RBIT); + } + + /* + * Verify if this is a file + * @return true if a file + */ + boolean isFile() throws IOException { + checkAttr(); + + return attr.ftype == NFREG; + } + + /* + * Verify if this is a directory + * @return true if a directory + */ + boolean isDirectory() throws IOException { + checkAttr(); + + return attr.ftype == NFDIR; + } + + /* + * Verify if this is a symbolic link + * @return true if a symbolic link + */ + boolean isSymlink() throws IOException { + checkAttr(); + + return attr.ftype == NFLNK; + } + + /* + * @return file attributes + */ + Fattr getAttr() throws IOException { + checkAttr(); + + return (Fattr)attr; + } + + /* + * Lookup a name in a directory + * + * If its a symbolic link - follow it + * + * @param name Name of entry in directory + * @returns Nfs object + * @exception java.io.IOException + */ + Nfs lookup(String name) throws IOException { + byte[] newfh; + Fattr2 newattrs; + Nfs nfs; + String pathname; + + /* For multi-component lookup, the name would already be + * filled in when object is created and + * thus name passed in will be null. + */ + if (name == null) { + pathname = this.name; + name = this.name; + } else { /* Single component case */ + if (this.name == null) + pathname = name; + else + pathname = this.name + "/" + name; + } + + /* + * First check the cache to see + * if we already have this file/dir + */ + nfs = cache_get(rpc.conn.server, pathname); + if (nfs != null && nfs.cacheOK(cacheTime)) { + + // If a symbolic link then follow it + + if (((Nfs2)nfs).attr.ftype == NFLNK) + nfs = NfsConnect.followLink(nfs); + + return nfs; + } + + Xdr call = new Xdr(rsize + 512); + Xdr reply = null; + + /* + * If needed, give one try to get the security information + * from the server. + */ + for (int sec_tries = 1; sec_tries >= 0; sec_tries--) { + rpc.rpc_header(call, NFSPROC2_LOOKUP); + call.xdr_raw(fh); + call.xdr_string(name); + + try { + reply = rpc.rpc_call(call, 5 * 1000, 0); + break; + } catch (MsgRejectedException e) { + /* + * Check if this lookup is using public fh. + * If so and if the call receives an AUTH_TOOWEAK error, + * lookupSec() is called to get the security flavor + * information from the server by using the WebNFS + * security negotiation protocol (supported in Solaris 8). + */ + boolean is_v2pubfh = true; + for (int i = 0; i < 32; i++) { + if (fh[i] != (byte) 0) { + is_v2pubfh = false; + break; + } + } + if (is_v2pubfh && e.why == + MsgRejectedException.AUTH_TOOWEAK) { + String secKey = lookupSec(); + if (secKey != null && + NfsSecurity.getMech(secKey) != null) { + rpc.setCred(new CredGss("nfs", + NfsSecurity.getMech(secKey), + NfsSecurity.getService(secKey), + NfsSecurity.getQop(secKey))); + continue; + } else if (secKey != null && secKey.equals("1")) { + rpc.setCred(new CredUnix()); + continue; + } + } + throw e; + } catch (IOException e) { + throw e; + } + } // for + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + newfh = reply.xdr_raw(FHSIZE); + newattrs = new Fattr2(reply); + + nfs = new Nfs2(rpc, newfh, pathname, newattrs); + cache_put(nfs); + + // If a symbolic link then follow it + + if (((Nfs2)nfs).attr.ftype == NFLNK) + nfs = NfsConnect.followLink(nfs); + + return nfs; + } + + /* + * lookupSec() uses the WebNFS security negotiation protocol to + * get nfs flavor numbers required by the nfs server. + * + * If the server fails to return the security numbers, the client + * will use a default security mode specified in the + * nfssec.properties file. + * + * If the server successfully returns a list of security modes, + * the client will use the preferred security mode that matches + * any security number found in the list, otherwise, it + * will use the first security number from the list that the + * client supports. + * + * Null string is returned if the client does not support any + * security numbers that the server requests. + * + * Here is an example of the WebNFS security negotiation protocol: + * + * Suppose the server shares /export/home as follows: + * + * share -o sec=sec_1:sec_2:sec_3 /export/secure + * + * Here is how to READ a file from server:/export/secure: + * + * Client Server + * ------ ------ + * + * LOOKUP 0x0, foo, "path" + * -----------> + * <----------- + * AUTH_TOOWEAK + * + * LOOKUP 0x0, foo, 0x81, , "path" + * -----------> + * <----------- + * FH = {...,sec_1, ..., sec_3} + * LOOKUP 0x0, foo, "path" + * use a selected sec flavor (sec_x) + * -----------> + * <----------- + * FH = 0x01 + * READ 0x01, sec_x, offset=0 for 32k + * -----------> + * <----------- + * + * Here is the contents of the FH returned from the server for the + * "0x81" V2 LOOKUP request: + * + * 1 2 3 4 32 + * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ + * | l | s | | | sec_1 |...| sec_n |...| | + * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ + * + * where l is the length : 4 * n (bytes) + * s is status indicating whether there are more sec flavors + * (1 is yes, 0 is no) that require the client to perform + * another 0x81 LOOKUP request. Client uses + * to indicate the offset of the flavor number (sec_index + n) + * + */ + public String lookupSec() throws IOException { + + int sec_index = 1; + boolean more = false; + String secmode, first_secmode = null; + Xdr call = new Xdr(rsize + 512); + + do { + rpc.rpc_header(call, NFSPROC2_LOOKUP); + call.xdr_raw(new byte[32]); // v2 public file handle + + // send "0x81pathname" over the wire + int len = name.getBytes().length + 2; + byte[] b = new byte[len]; + b[0] = (byte) 0x81; + b[1] = (byte) sec_index; + System.arraycopy(name.getBytes(), 0, b, 2, name.getBytes().length); + call.xdr_bytes(b); + + Xdr reply = rpc.rpc_call(call, 5 * 1000, 3); + int status = reply.xdr_int(); + + // If the server does not support the MClookup security + // negotiation, simply use the default security flavor. + if (status != NFS_OK) { + return NfsSecurity.getDefault(); + } + + byte[] s = reply.xdr_raw(4); + int numsec = ((int) s[0])/4; // 4 is sizeof (int) + if (s[1] == (byte) 0) { + more = false; + } else { + more = true; + sec_index = sec_index + numsec; + } + + String prefer = NfsSecurity.getPrefer(); + while (numsec-- > 0) { + secmode = Integer.toString(reply.xdr_int()); + + if ((prefer != null) && prefer.equals(secmode)) { + return prefer; + } + + if ((first_secmode == null) && + NfsSecurity.hasValue(secmode)) { + first_secmode = secmode; + } + } + } while (more); + + return first_secmode; + } + + + /* + * Read data from a file into a buffer + * + */ + void read_otw(Buffer buf) throws IOException { + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NFSPROC2_READ); + call.xdr_raw(fh); + call.xdr_u_int(buf.foffset); + call.xdr_u_int(rsize); + call.xdr_u_int(rsize); // totalcount (unused) + + Xdr reply = rpc.rpc_call(call, 1 * 1000, 0); + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + attr.getFattr(reply); + + int bytesread = reply.xdr_int(); + buf.eof = buf.foffset + rsize >= attr.size; + buf.buf = reply.xdr_buf(); + buf.bufoff = reply.xdr_offset(); + buf.buflen = bytesread; + cacheTime = attr.mtime; + } + + /* + * Write data from a file into a buffer + * + */ + int write_otw(Buffer buf) throws IOException { + + Xdr call = new Xdr(wsize + 512); + + int fileOffset = (int) buf.foffset + buf.minOffset; + int writeLength = buf.maxOffset - buf.minOffset; + + rpc.rpc_header(call, NFSPROC2_WRITE); + call.xdr_raw(fh); + call.xdr_u_int(fileOffset); // beginoffset - not used + call.xdr_u_int(fileOffset); + call.xdr_u_int(writeLength); // totalcount - not used + call.xdr_bytes(buf.buf, buf.bufoff + buf.minOffset, writeLength); + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + attr.getFattr(reply); + + buf.status = buf.LOADED; + buf.writeVerifier = 0; + cacheTime = attr.mtime; + + return writeLength; + } + + /* + * Read a directory + * + * Returns an array of names. + */ + String[] readdir() throws IOException { + + long cookie = 0; + boolean eof = false; + String[] s = new String[32]; + String ename; + int i = 0; + + /* + * If we already have the directory entries + * cached then return them. + */ + if (dircache != null && cacheOK(cacheTime)) + return dircache; + + Xdr call = new Xdr(rsize + 512); + + while (!eof) { + rpc.rpc_header(call, NFSPROC2_READDIR); + call.xdr_raw(fh); + call.xdr_u_int(cookie); + call.xdr_u_int(4096); // number of directory bytes + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + /* + * Get directory entries + */ + while (reply.xdr_bool()) { + reply.xdr_u_int(); // skip fileid + ename = reply.xdr_string(); // filename + + cookie = reply.xdr_u_int(); + + if (ename.equals(".") || ename.equals("..")) // ignore + continue; + + s[i++] = ename; + + if (i >= s.length) { // last elem in array ? + String[] tmp = s; + + s = new String[i*2]; // double its size + System.arraycopy(tmp, 0, s, 0, i); + } + } + eof = reply.xdr_bool(); // end of directory + } + + /* + * Trim array to exact size + */ + if (i < s.length) { + String[] tmp = s; + + s = new String[i]; + System.arraycopy(tmp, 0, s, 0, i); + } + + dircache = s; + cacheTime = attr.mtime; + + return s; + } + + /* + * Read a symbolic link + * + * Returns the text in the symbolic link + */ + String readlink() throws IOException { + /* + * If we've already read the symlink + * then return the cached text. + */ + if (symlink != null && cacheOK(cacheTime)) + return symlink; + + Xdr call = new Xdr(rsize + 512); + rpc.rpc_header(call, NFSPROC2_READLINK); + call.xdr_raw(fh); + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + symlink = reply.xdr_string(); + cacheTime = attr.mtime; + + return symlink; + } + + /* + * Create a file + * + * @param name Name of file + * @param mode UNIX style mode + * @returns true if successful + * @exception java.io.IOException + */ + Nfs create(String name, long mode) throws IOException { + return create_otw(NFSPROC2_CREATE, name, mode); + } + + /* + * Create a directory + * + * @param name name of directory + * @param mode UNIX style mode + * @returns true if successful + * @exception java.io.IOException + */ + Nfs mkdir(String name, long mode) throws IOException { + return create_otw(NFSPROC2_MKDIR, name, mode); + } + + /* + * Create Nfs Object over-the-wire + * + * @param nfsOp NFS operation + * @param mode UNIX style mode + * @returns true if successful + * @exception java.io.IOException + */ + private Nfs create_otw(int nfsOp, String name, long mode) + throws IOException { + + long currTime = System.currentTimeMillis(); + byte[] newfh; + Fattr2 newattrs; + Nfs nfs; + + Xdr call = new Xdr(rsize + 512); + rpc.rpc_header(call, nfsOp); + call.xdr_raw(fh); + call.xdr_string(name); + call.xdr_u_int(mode); + call.xdr_u_int(NfsConnect.getCred().getUid()); // owner + call.xdr_u_int(NfsConnect.getCred().getGid()); // group + call.xdr_u_int(0); // size + call.xdr_u_int(currTime / 1000); // atime seconds + call.xdr_u_int(currTime % 1000); // atime mseconds + call.xdr_u_int(currTime / 1000); // mtime seconds + call.xdr_u_int(currTime % 1000); // mtime mseconds + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + /* + * Cache the new NFS Object + */ + newfh = reply.xdr_raw(FHSIZE); + newattrs = new Fattr2(reply); + + String pathname = this.name + "/" + name; + + nfs = new Nfs2(rpc, newfh, pathname, newattrs); + cache_put(nfs); + dircache = null; + return nfs; + } + + /* + * Get Filesystem Information + * + */ + void fsinfo() throws IOException { + wsize = RWSIZE; + } + + /* + * Commit writes - not implemented in v2 + */ + long commit(int foffset, int length) throws IOException { + return 0; + } + + /** + * Remove file + * + * Returns true if the file was removed + */ + boolean remove(String name) throws IOException { + return remove_otw(NFSPROC2_REMOVE, name); + } + + /** + * Remove directory + * + * @returns true if the directory could be deleted + * @exception java.io.IOException + */ + boolean rmdir(String name) throws IOException { + return remove_otw(NFSPROC2_RMDIR, name); + } + + /* + * Remove Nfs Object + * + * @param nfsOp over-the-wire operation + * @param nfsP Nfs object of Parent directory + * @param name Name of file/dir to be deleted. + * @return true if the Nfs Object could be deleted + * @exception java.io.IOException + */ + private boolean remove_otw(int nfsOp, String name) throws IOException { + + Xdr call = new Xdr(rsize + 512); + rpc.rpc_header(call, nfsOp); + call.xdr_raw(fh); + call.xdr_string(name); + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + cache_remove(this, name); // Remove Nfs object from cache + dircache = null; + return true; + } + + /* + * Rename file + * + * @param srcP Nfs obj of parent of src + * @param dstP Nfs obj of parent of dst + * @param sName src Name. + * @param dName destination filename. May be 'path/filename' or simply + * 'filename' + * @returns true if the file/directory was renamed + * @exception java.io.IOException + */ + boolean rename(Nfs dstP, String sName, String dName) throws IOException{ + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NFSPROC2_RENAME); + call.xdr_raw(fh); // Source dir filehandle + call.xdr_string(sName); // Source filename + call.xdr_raw(dstP.getFH()); // Dest dir filehandle + call.xdr_string(dName); // Dest filename + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + cache_remove(this, sName); // Remove Nfs object from cache + dircache = null; + dstP.dircache = null; + return true; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Nfs3.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Nfs3.java new file mode 100644 index 0000000000..4c124131d4 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/Nfs3.java @@ -0,0 +1,1224 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.rpc.*; + +/** + * This class contains the methods specific to + * NFS version 3. + * + * @see Nfs + * @see Nfs2 + * @see Fattr + * @author Brent Callaghan + * @author Ricardo Labiaga + */ +class Nfs3 extends Nfs { + + Fattr3 attr; + + int accessBits = -1; // Cache access bits + long accessTime; // Time when accessBits was cached + + /* + * NFS version 3 procedure numbers + */ + private final static int NFSPROC3_NULL = 0; + private final static int NFSPROC3_GETATTR = 1; + private final static int NFSPROC3_SETATTR = 2; + private final static int NFSPROC3_LOOKUP = 3; + private final static int NFSPROC3_ACCESS = 4; + private final static int NFSPROC3_READLINK = 5; + private final static int NFSPROC3_READ = 6; + private final static int NFSPROC3_WRITE = 7; + private final static int NFSPROC3_CREATE = 8; + private final static int NFSPROC3_MKDIR = 9; + private final static int NFSPROC3_SYMLINK = 10; + private final static int NFSPROC3_MKNOD = 11; + private final static int NFSPROC3_REMOVE = 12; + private final static int NFSPROC3_RMDIR = 13; + private final static int NFSPROC3_RENAME = 14; + private final static int NFSPROC3_LINK = 15; + private final static int NFSPROC3_READDIR = 16; + private final static int NFSPROC3_READDIRPLUS = 17; + private final static int NFSPROC3_FSSTAT = 18; + private final static int NFSPROC3_FSINFO = 19; + private final static int NFSPROC3_PATHCONF = 20; + private final static int NFSPROC3_COMMIT = 21; + + private final static int NFS_OK = 0; + private final static int NFS3ERR_NOTSUPP = 10004; + + private final static int RWSIZE = 32768; + + private final static int DIRCOUNT = 1024; + private final static int MAXBSIZE = 8192; + + /* + * Used to set time in create and mkdir + */ + private final static int DONT_CHANGE = 0; + private final static int SERVER_TIME = 1; + private final static int CLIENT_TIME = 2; + + /* + * ACCESS bits + */ + private final static int ACCESS3_READ = 0x0001; + private final static int ACCESS3_LOOKUP = 0x0002; + private final static int ACCESS3_MODIFY = 0x0004; + private final static int ACCESS3_EXTEND = 0x0008; + private final static int ACCESS3_DELETE = 0x0010; + private final static int ACCESS3_EXECUTE = 0x0020; + + /* + * Types of create or mkdir + */ + private final static int UNCHECKED = 0; + private final static int GUARDED = 1; + private final static int EXCLUSIVE = 2; + + /* + * Types of write + */ + private final static int UNSTABLE = 0; + private final static int DATA_SYNC = 1; + private final static int FILE_SYNC = 2; + + int nra; // current reads-ahead + int nwb; // current writes-behind + + int prevWriteIndex = -1; + + Nfs3(Rpc rpc, byte[] fh, String name, Fattr3 attr) { + this.rpc = rpc; + this.fh = fh; + if (name.startsWith("./")) // normalize for cache lookup + name = name.substring(2); + this.name = name; + this.attr = attr == null ? new Fattr3() : attr; + this.rsize = RWSIZE; + NRA = 1; // Max reads-ahead + NWB = 4; // Max writes-behind + NWC = 10; // Max writes committed + } + + void getattr() throws IOException { + Xdr reply; + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NFSPROC3_GETATTR); + call.xdr_bytes(fh); + + try { + reply = rpc.rpc_call(call, 2 * 1000, 2); + } catch (IOException e) { + // don't let a mere getattr hang + // the app if the server is down. + return; + } + + int status = reply.xdr_int(); + if (status != NFS_OK) + throw new NfsException(status); + + attr.getFattr(reply); + } + + void checkAttr() throws IOException { + + if (! attr.valid()) + getattr(); + } + + boolean cacheOK(long t) throws IOException { + checkAttr(); + + return t == attr.mtime; + } + + void invalidate() { + attr.validtime = 0; + } + + /* + * Get the file modification time + * @return the time in milliseconds + */ + long mtime() throws IOException { + checkAttr(); + + return attr.mtime; + } + + /* + * Get the file size in bytes. + * + * Note that the size may be greater than that + * shown in the attributes if the file is being written. + * + * @return file size + */ + long length() throws IOException { + checkAttr(); + + return maxLength > attr.size ? maxLength : attr.size; + } + + /* + * Verify if file exists + * @return true if file exists + */ + boolean exists() throws IOException { + checkAttr(); + + return true; + } + + /* + * Check access permission to file or directory + */ + private boolean check_access(int mode) throws IOException { + + int rBits = ACCESS3_READ; + int wBits = ACCESS3_MODIFY | ACCESS3_EXTEND | ACCESS3_DELETE; + + /* + * Get access bits from the server if + * they're not already cached. + */ + if (accessBits < 0 || !cacheOK(accessTime)) { + Xdr call = new Xdr(rsize + 512); + rpc.rpc_header(call, NFSPROC3_ACCESS); + call.xdr_bytes(fh); + call.xdr_int(rBits | wBits); + + Xdr reply = rpc.rpc_call(call, 5 * 1000, 0); + + int status = reply.xdr_int(); + + if (reply.xdr_bool()) // post-op attrs + attr.getFattr(reply); + + if (status != NFS_OK) + throw new NfsException(status); + + accessBits = reply.xdr_int(); + accessTime = attr.mtime; + } + + if ((mode & RBIT) != 0) + return (accessBits & rBits) != 0; + + if ((mode & WBIT) != 0) + return (accessBits & wBits) != 0; + + return true; + } + + /* + * Verify if file can be created/updated + * @return true if file can be created/updated + */ + boolean canWrite() throws IOException { + + return check_access(WBIT); + } + + /* + * Verify if file can be read + * @return true if file can be read + */ + boolean canRead() throws IOException { + + return check_access(RBIT); + } + + /* + * Verify if this is a file (not a directory) + * @return true if a file + */ + boolean isFile() throws IOException { + checkAttr(); + + return attr.ftype == NFREG; + } + + /* + * Verify if this is a directory (not a file) + * @return true if a directory + */ + boolean isDirectory() throws IOException { + checkAttr(); + + return attr.ftype == NFDIR; + } + + /* + * Verify if this is a symbolic link + * @return true if a symbolic link + */ + boolean isSymlink() throws IOException { + checkAttr(); + + return attr.ftype == NFLNK; + } + + /* + * @return file attributes + */ + Fattr getAttr() throws IOException { + checkAttr(); + + return (Fattr)attr; + } + + /* + * Lookup a name in a directory + * + * If its a symbolic link - follow it + * + * @param name Name of entry in directory + * @returns Nfs object + * @exception java.io.IOException + */ + Nfs lookup(String name) + throws IOException { + byte[] newFh; + Fattr3 newattrs = null; + Nfs nfs; + String pathname; + + /* For multi-component lookup, the name would already be + * filled in when object is created and + * thus name passed in will be null. + */ + if (name == null) { + pathname = this.name; + name = this.name; + } else { /* Single component case */ + if (this.name == null) + pathname = name; + else + pathname = this.name + "/" + name; + } + + /* + * First check the cache to see + * if we already have this file/dir + */ + nfs = cache_get(rpc.conn.server, pathname); + if (nfs != null && nfs.cacheOK(cacheTime)) { + + // If a symbolic link then follow it + + if (((Nfs3)nfs).attr.ftype == NFLNK) + nfs = NfsConnect.followLink(nfs); + + return nfs; + } + + Xdr call = new Xdr(rsize + 512); + Xdr reply = null; + + /* + * If needed, give one try to get the security information + * from the server. + */ + for (int sec_tries = 1; sec_tries >= 0; sec_tries--) { + rpc.rpc_header(call, NFSPROC3_LOOKUP); + call.xdr_bytes(fh); + call.xdr_string(name); + + try { + reply = rpc.rpc_call(call, 5 * 1000, 0); + break; + } catch (MsgRejectedException e) { + if (fh.length == 0 && + e.why == MsgRejectedException.AUTH_TOOWEAK) { + String secKey = lookupSec(); + if (secKey != null && + NfsSecurity.getMech(secKey) != null) { + rpc.setCred(new CredGss("nfs", + NfsSecurity.getMech(secKey), + NfsSecurity.getService(secKey), + NfsSecurity.getQop(secKey))); + continue; + } else if (secKey != null && secKey.equals("1")) { + rpc.setCred(new CredUnix()); + continue; + } + } + throw e; + } catch (IOException e) { + throw e; + } + } // for + + int status = reply.xdr_int(); + if (status != NFS_OK) { + if (reply.xdr_bool()) + attr.getFattr(reply); + + throw new NfsException(status); + } + + newFh = reply.xdr_bytes(); + if (reply.xdr_bool()) + newattrs = new Fattr3(reply); + if (reply.xdr_bool()) + attr.getFattr(reply); + + nfs = new Nfs3(rpc, newFh, pathname, newattrs); + cache_put(nfs); + + // If a symbolic link then follow it + + if (((Nfs3)nfs).attr.ftype == NFLNK) + nfs = NfsConnect.followLink(nfs); + + return nfs; + } + + /* + * lookupSec() uses the WebNFS security negotiation protocol to + * to get nfs security flavor numbers from the server. + * + * Null string is returned if the server fails to return any + * security flavor numbers. + * + * If the server successfully returns a list of security modes, + * the client will use the preferred security mode that matches + * any security number found in the list, otherwise, it + * will use the first security number from the list that the + * client supports. + * + * Null string is returned if the client does not support any + * security numbers that the server requests. + * + * Here is an example of the WebNFS security negotiation protocol: + * + * Suppose the server shares /export/home as follows: + * + * share -o sec=sec_1:sec_2:sec_3 /export/secure + * + * Here is how to READ a file from server:/export/secure: + * + * Client Server + * ------ ------ + * + * LOOKUP 0x0, foo, "path" + * -----------> + * <----------- + * AUTH_TOOWEAK + * + * LOOKUP 0x0, foo, 0x81, , "path" + * -----------> + * <----------- + * FH = {...,sec_1, ..., sec_3} + * LOOKUP 0x0, foo, "path" + * use a selected sec flavor (sec_x) + * -----------> + * <----------- + * FH = 0x01 + * READ 0x01, sec_x, offset=0 for 32k + * -----------> + * <----------- + * + * Here is the contents of the FH returned from the server for the + * "0x81" V3 LOOKUP request: + * + * 1 4 + * +--+--+--+--+ + * | len | + * +--+--+--+--+ + * up to 64 + * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ + * |s | | | | sec_1 | sec_2 | ... | sec_n | + * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ + * + * len = 4 * (n+1), where n is the number of security flavors + * sent in the current overloaded filehandle. + * + * the status s indicates whether there are more security + * mechanisms (1 means yes, 0 means no) that require the client + * to perform another 0x81 LOOKUP to get them. Client uses + * to indicate the offset of the flavor number + * (sec_index + n). + * + * Three bytes are padded after s. + * + */ + public String lookupSec() throws IOException { + + int sec_index = 1; + boolean more = false; + String secmode, first_secmode = null; + Xdr call = new Xdr(rsize + 512); + + do { + rpc.rpc_header(call, NFSPROC3_LOOKUP); + call.xdr_bytes(new byte[0]); // v3 public file handle + + // send "0x81/sec_inext/pathname" over the wire + int len = name.getBytes().length + 2; + byte[] b = new byte[len]; + b[0] = (byte) 0x81; + b[1] = (byte) sec_index; + System.arraycopy(name.getBytes(), 0, b, 2, + name.getBytes().length); + call.xdr_bytes(b); + + Xdr reply = rpc.rpc_call(call, 5 * 1000, 3); + + int status = reply.xdr_int(); + + // If the server does not support the MClookup security + // negotiation, return null. + if (status != NFS_OK) { + return null; + } + + int numsec = reply.xdr_int()/4 - 1; + byte[] s = reply.xdr_raw(1); + if (s[0] == (byte) 0) { + more = false; + } else { + more = true; + sec_index = sec_index + numsec; + } + + String prefer = NfsSecurity.getPrefer(); + while (numsec-- > 0) { + secmode = Integer.toString(reply.xdr_int()); + + if ((prefer != null) && prefer.equals(secmode)) { + return prefer; + } + + if ((first_secmode == null) && + NfsSecurity.hasValue(secmode)) { + first_secmode = secmode; + } + } + } while (more); + + return first_secmode; + } + + /* + * Read a buffer from a file + */ + void read_otw(Buffer buf) throws IOException { + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NFSPROC3_READ); + call.xdr_bytes(fh); + call.xdr_hyper(buf.foffset); + call.xdr_int(rsize); + + Xdr reply = rpc.rpc_call(call, 1 * 1000, 0); + + int status = reply.xdr_int(); + + if (reply.xdr_bool()) // post-op attrs + attr.getFattr(reply); + + if (status != NFS_OK) + throw new NfsException(status); + + int bytesread = reply.xdr_int(); + buf.eof = reply.xdr_bool(); + if (bytesread != reply.xdr_u_int()) + throw new NfsException(NfsException.NFSERR_TOOSMALL); + + buf.buf = reply.xdr_buf(); + buf.bufoff = reply.xdr_offset(); + buf.buflen = bytesread; + cacheTime = attr.mtime; + } + + /* + * Write a buffer + */ + int write_otw(Buffer buf) throws IOException { + + Xdr call = new Xdr(wsize + 512); + + rpc.rpc_header(call, NFSPROC3_WRITE); + call.xdr_bytes(fh); + call.xdr_hyper(buf.foffset + buf.minOffset); + call.xdr_u_int(buf.maxOffset - buf.minOffset); + call.xdr_int(buf.syncType); + call.xdr_bytes(buf.buf, buf.bufoff + buf.minOffset, + buf.maxOffset - buf.minOffset); + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + + /* + * wcc_data + */ +// XXX if pre_op_attr show file changed then +// should invalidate cached non-dirty blocks. + if (reply.xdr_bool()) { // pre_op_attr + reply.xdr_hyper(); // size3; + reply.xdr_u_int(); // mtime + reply.xdr_u_int(); + reply.xdr_u_int(); // ctime + reply.xdr_u_int(); + } + + if (reply.xdr_bool()) { // post_op_attr + attr.getFattr(reply); + cacheTime = attr.mtime; + } + + if (status != NFS_OK) + throw new NfsException(status); + + int bytesWritten = reply.xdr_int(); + if (reply.xdr_int() == FILE_SYNC) // stable_how + buf.status = buf.LOADED; + else + buf.status = buf.COMMIT; + buf.writeVerifier = reply.xdr_hyper(); // writeverf3 + + return bytesWritten; + } + + /* + * Read a directory including entry filehandles and attributes. + * + * Entries are cached as Nfs objects - preempting any need + * for lookups within the directory - entries need be validated + * only with getattr. + * + * XXX Large directories or a file tree walk + * XXX could run us out of memory because of + * XXX the aggressive caching. + * + */ + String[] readdir() + throws IOException { + + long cookie = 0; + long cookieverf = 0; + boolean eof = false; + String[] s = new String[32]; + int i = 0; + Fattr3 eattr; + byte[] efh; + String ename; + String pathname; + + /* + * If we already have the directory entries + * cached then return them. + */ + if (dircache != null) { + if (cacheOK(cacheTime)) + return dircache; + + dircache = null; + + return readdir_old(); + } + + Xdr call = new Xdr(rsize + 512); + + while (!eof) { + rpc.rpc_header(call, NFSPROC3_READDIRPLUS); + call.xdr_bytes(fh); + call.xdr_hyper(cookie); + call.xdr_hyper(cookieverf); + call.xdr_u_int(DIRCOUNT); // number of directory bytes + call.xdr_u_int(MAXBSIZE); // max number of directory bytes + + Xdr reply = rpc.rpc_call(call, 3 * 1000, 0); + + int status = reply.xdr_int(); + + if (reply.xdr_bool()) // post-op dir attrs + attr.getFattr(reply); + + /* + * Some implementations don't support readdirplus + * so fall back to the old readdir if necessary. + */ + if (status == NFS3ERR_NOTSUPP) + return readdir_old(); + + if (status != NFS_OK) + throw new NfsException(status); + + cookieverf = reply.xdr_hyper(); + + /* + * Get directory entries + */ + while (reply.xdr_bool()) { + reply.xdr_hyper(); // skip fileid + ename = reply.xdr_string(); // entry filename + + cookie = reply.xdr_hyper(); + + eattr = null; + efh = null; + + if (reply.xdr_bool()) // entry attrs + eattr = new Fattr3(reply); + + if (reply.xdr_bool()) // entry filehandle + efh = reply.xdr_bytes(); + + if (ename.equals(".") || ename.equals("..")) // ignore entry + continue; + + s[i++] = ename; + if (i >= s.length) { // last elem in array ? + String[] tmp = s; + + s = new String[i*2]; // double its size + System.arraycopy(tmp, 0, s, 0, i); + } + + /* + * If we have both filehandle and attrs + * then stash the entry object in the cache + */ + if (efh != null && eattr != null) { + if (this.name == null) + pathname = ename; + else + pathname = this.name + "/" + ename; + + cache_put(new Nfs3(rpc, efh, pathname, eattr)); + } + } + eof = reply.xdr_bool(); // end of directory + } + + /* + * Trim array to exact size + */ + if (i < s.length) { + String[] tmp = s; + + s = new String[i]; + System.arraycopy(tmp, 0, s, 0, i); + } + + dircache = s; + cacheTime = attr.mtime; + + return s; + } + + /** + * Read a directory with just names and fileids + * + * @returns byte array of directory entries + * @exception java.io.IOException + */ + String[] readdir_old() throws IOException { + + long cookie = 0; + long cookieverf = 0; + boolean eof = false; + String ename; + String[] s = new String[32]; + int i = 0; + + /* + * If we already have the directory entries + * cached then return them. + */ + if (dircache != null && cacheOK(cacheTime)) + return (dircache); + + Xdr call = new Xdr(rsize + 512); + + while (!eof) { + rpc.rpc_header(call, NFSPROC3_READDIR); + call.xdr_bytes(fh); + call.xdr_hyper(cookie); + call.xdr_hyper(cookieverf); + call.xdr_u_int(MAXBSIZE); // number of directory bytes + + Xdr reply = rpc.rpc_call(call, 3 * 1000, 0); + + int status = reply.xdr_int(); + + if (reply.xdr_bool()) // post-op dir attrs + attr.getFattr(reply); + + if (status != NFS_OK) + throw new NfsException(status); + + cookieverf = reply.xdr_hyper(); + + /* + * Get directory entries + */ + while (reply.xdr_bool()) { + reply.xdr_hyper(); // skip fileid + ename = reply.xdr_string(); // filename + + if (! ename.equals(".") && ! ename.equals("..")) + s[i++] = ename; + + if (i >= s.length) { // last elem in array ? + String[] tmp = s; + + s = new String[i*2]; // double its size + System.arraycopy(tmp, 0, s, 0, i); + } + + cookie = reply.xdr_hyper(); + } + eof = reply.xdr_bool(); // end of directory + } + + if (i == 0) + return (null); + /* + * Trim array to exact size + */ + if (i < s.length) { + String[] tmp = s; + + s = new String[i]; + System.arraycopy(tmp, 0, s, 0, i); + } + + dircache = s; + cacheTime = attr.mtime; + + return (s); + } + + /* + * Read a symbolic link + * + */ + String readlink() throws IOException { + /* + * If we've already read the symlink + * then return the cached text. + */ + if (symlink != null && cacheOK(cacheTime)) + return symlink; + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NFSPROC3_READLINK); + call.xdr_bytes(fh); + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + if (reply.xdr_bool()) // post-op attr + attr.getFattr(reply); + + if (status != NFS_OK) + throw new NfsException(status); + + symlink = reply.xdr_string(); + cacheTime = attr.mtime; + + return symlink; + } + + /* + * Create a file + * + */ + Nfs create(String name, long mode) throws IOException { + + byte[] newFh = null; + Fattr3 newattrs = null; + Nfs nfs; + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NFSPROC3_CREATE); + call.xdr_bytes(fh); + call.xdr_string(name); + call.xdr_int(UNCHECKED); + + // sattr3 + call.xdr_bool(true); // mode3 + call.xdr_u_int(mode); + call.xdr_bool(true); // uid3 + call.xdr_u_int(NfsConnect.getCred().getUid()); + call.xdr_bool(true); // gid3 + call.xdr_u_int(NfsConnect.getCred().getGid()); + call.xdr_bool(true); // size3 + call.xdr_hyper(0); + call.xdr_int(SERVER_TIME); // atime + call.xdr_int(SERVER_TIME); // mtime + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + if (status != NFS_OK) { + + /* + * CREATE3resfail + */ + // wcc_data + // XXX If this were an exlusive create, then we + // should check whether the directory was modified, + // in such case, the file may have been created by another + // client. + + if (reply.xdr_bool()) { // pre_op_attr + reply.xdr_hyper(); // size3; + reply.xdr_u_int(); // mtime + reply.xdr_u_int(); + reply.xdr_u_int(); // ctime + reply.xdr_u_int(); + } + if (reply.xdr_bool()) // post_op_attr + attr.getFattr(reply); + throw new NfsException(status); + } + /* + * CREATE3resok + */ + if (reply.xdr_bool()) // post_op_fh3 + newFh = reply.xdr_bytes(); + + if (reply.xdr_bool()) // post_op_attr + newattrs = new Fattr3(reply); + /* + * wcc_data + */ + if (reply.xdr_bool()) { // pre_op_attr + reply.xdr_hyper(); // size3; + reply.xdr_u_int(); // mtime + reply.xdr_u_int(); + reply.xdr_u_int(); // ctime + reply.xdr_u_int(); + } + if (reply.xdr_bool()) // post_op_attr + attr.getFattr(reply); + + if (newFh != null && newattrs != null) { + String pathname = this.name + "/" + name; + nfs = new Nfs3(rpc, newFh, pathname, newattrs); + cache_put(nfs); + } else + nfs = null; + + return nfs; + } + + /* + * Create a directory + * + * @param name name of directory to create + * @returns true if successful, false otherwise + */ + Nfs mkdir(String name, long mode) throws IOException { + + byte[] newFh = null; + Fattr3 newattrs = null; + Nfs nfs = null; + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NFSPROC3_MKDIR); + call.xdr_bytes(fh); + call.xdr_string(name); + + // sattr3 + call.xdr_bool(true); // mode3 + call.xdr_u_int(mode); + call.xdr_bool(true); // uid3 + call.xdr_u_int(NfsConnect.getCred().getUid()); + call.xdr_bool(true); // gid3 + call.xdr_u_int(NfsConnect.getCred().getGid()); + call.xdr_bool(true); // size3 + call.xdr_hyper(0); + call.xdr_int(SERVER_TIME); // atime + call.xdr_int(SERVER_TIME); // mtime + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + if (status != NFS_OK) { + /* + * MKDIR3resfail + */ + // wcc_data + if (reply.xdr_bool()) { // pre_op_attr + reply.xdr_hyper(); // size3; + reply.xdr_u_int(); // mtime + reply.xdr_u_int(); + reply.xdr_u_int(); // ctime + reply.xdr_u_int(); + } + if (reply.xdr_bool()) // post_op_attr + attr.getFattr(reply); + throw new NfsException(status); + } + /* + * MKDIR3resok + */ + if (reply.xdr_bool()) // post_op_fh3 + newFh = reply.xdr_bytes(); + if (reply.xdr_bool()) // post_op_attr + newattrs = new Fattr3(reply); + /* + * wcc_data + */ + if (reply.xdr_bool()) { // pre_op_attr + reply.xdr_hyper(); // size3; + reply.xdr_u_int(); // mtime + reply.xdr_u_int(); + reply.xdr_u_int(); // ctime + reply.xdr_u_int(); + } + if (reply.xdr_bool()) // post_op_attr + attr.getFattr(reply); + + if (newFh != null && newattrs != null) { + String pathname = this.name + "/" + name; + nfs = new Nfs3(rpc, newFh, pathname, newattrs); + cache_put(nfs); + } + dircache = null; + + return nfs; + } + + /* + * Get Filesystem Information + * + */ + void fsinfo() throws IOException { + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NFSPROC3_FSINFO); + call.xdr_bytes(fh); + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + + if (reply.xdr_bool()) // post_op_attr + attr.getFattr(reply); + + if (status != NFS_OK) + throw new NfsException(status); + + reply.xdr_u_int(); // rtmax + reply.xdr_u_int(); // rtpref + reply.xdr_u_int(); // rtmult + reply.xdr_u_int(); // wtmax: maximum write size + wsize = reply.xdr_int(); // wtpref: preferred write size + + /* + * More attributes follow but we don't + * Need them so we don't XDR decode them. + */ + + //reply.xdr_hyper(); // maxfilesize + //reply.xdr_u_int(); // seconds + //reply.xdr_u_int(); // nseconds + //reply.xdr_u_int(); // properties + } + + /* + * Commit previous async writes to stable storage + */ + long commit(int foffset, int length) throws IOException { + + Xdr call = new Xdr(wsize + 512); + + rpc.rpc_header(call, NFSPROC3_COMMIT); + call.xdr_bytes(fh); + call.xdr_hyper(foffset); + call.xdr_u_int(length); + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + + /* + * wcc_data + */ +// XXX if pre_op_attr show file changed then +// should invalidate cached non-dirty blocks. + if (reply.xdr_bool()) { // pre_op_attr + reply.xdr_hyper(); // size3; + reply.xdr_u_int(); // mtime + reply.xdr_u_int(); + reply.xdr_u_int(); // ctime + reply.xdr_u_int(); + } + + if (reply.xdr_bool()) // post_op_attr + attr.getFattr(reply); + + if (status != NFS_OK) + throw new NfsException(status); + + return reply.xdr_hyper(); // return verifier + } + + /* + * Remove file + * + * @returns true if the file was removed + */ + boolean remove(String name) throws IOException { + return remove_otw(NFSPROC3_REMOVE, name); + } + + /** + * Remove directory + * + * @returns true if the directory could be deleted + * @exception java.io.IOException + */ + boolean rmdir(String name) throws IOException { + return remove_otw(NFSPROC3_RMDIR, name); + } + + /* + * Remove Nfs Object over-the-wire + * @param NfsOperation over-the-wire operation + * @param NfsP Nfs object of Parent directory + * @param name Name of file to delete (for Mount protocol, the + * name will not be filled out for this Nfs object) + * @returns true if the Nfs Object was deleted + */ + private boolean remove_otw(int NfsOperation, String name) throws IOException { + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NfsOperation); + call.xdr_bytes(fh); + call.xdr_string(name); + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + + /* + * wcc_data + */ + // should check whether the directory was modified, + // in such case, the file may have been deleted by another + // client. + if (reply.xdr_bool()) { // pre_op_attr + reply.xdr_hyper(); // size3 + reply.xdr_u_int(); // mtime + reply.xdr_u_int(); + reply.xdr_u_int(); // ctime + reply.xdr_u_int(); + } + if (reply.xdr_bool()) // post_op_attr + attr.getFattr(reply); + if (status != NFS_OK) + throw new NfsException(status); + + // Remove Nfs object from cache + cache_remove(this, name); + dircache = null; + return true; + } + + /* + * Rename file + * @param srcP Nfs obj of parent of src + * @param dstP Nfs obj of parent of dst + * @param sName src Name. + * @param dName destination filename. May be 'path/filename' or simply + * 'filename' + * @returns true if the file/directory was renamed + */ + boolean rename(Nfs dstP, String sName, String dName) throws IOException{ + + Xdr call = new Xdr(rsize + 512); + + rpc.rpc_header(call, NFSPROC3_RENAME); + call.xdr_bytes(fh); // Source dir filehandle + call.xdr_string(sName); // Source filename + call.xdr_bytes(dstP.getFH()); // Dest dir filehandle + call.xdr_string(dName); // Dest filename + + Xdr reply = rpc.rpc_call(call, 2 * 1000, 0); + + int status = reply.xdr_int(); + /* + * wcc_data - fromdir_wcc + */ + if (reply.xdr_bool()) { // pre_op_attr + reply.xdr_hyper(); // size3 + reply.xdr_u_int(); // mtime + reply.xdr_u_int(); + reply.xdr_u_int(); // ctime + reply.xdr_u_int(); + } + if (reply.xdr_bool()) + attr.getFattr(reply); + + /* + * Don't bother getting wcc_data for destDir since we have + * no method to update its attributes. + */ + + if (status != NFS_OK) + throw new NfsException(status); + + cache_remove(this, sName); // Remove Nfs object from cache + dircache = null; + dstP.dircache = null; + return true; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsConnect.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsConnect.java new file mode 100644 index 0000000000..e6dd9f3218 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsConnect.java @@ -0,0 +1,446 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.rpc.*; +import java.util.Hashtable; + +/** + * + * Connect to an NFS server and return an + * Nfs file object. + * + * @see Nfs + * @see Nfs2 + * @see Nfs3 + * @author Brent Callaghan + */ +public class NfsConnect { + + private static byte[] pubfh2 = new byte[32]; // v2 public filehandle + private static byte[] pubfh3 = new byte[0]; // v3 public filehandle + private static Hashtable cacheNfsConnect = new Hashtable(); + + static final int NFS_PORT = 2049; + static final int NFS_PROG = 100003; + static final int MAXBUF = 32768 + 512; // Max size of NFS reply + + String server; + int port; + int version; + String proto; + boolean pub; + static CredUnix cred = new CredUnix(); + static RpcHandler rhandler; + static String sec_flavor; + + NfsConnect(String server, int port, int version, String proto, boolean pub) + { + this.server = server; + this.port = port; + this.version = version; + this.proto = proto; + this.pub = pub; + } + + /** + * Return an Nfs object given an NFS URL + * + * This code will also obtain testing options + * if present in the URL and use them to set specific + * configurations. + * + * @param url NFS URL + * @returns The Nfs object + */ + static Nfs connect(String urlstr) throws IOException { + + NfsURL url = new NfsURL(urlstr); + + String server = url.getHost(); + int port = url.getPort(); + String path = url.getFile(); + + int version = url.getVersion(); + String proto = url.getProto(); + boolean pub = url.getPub(); + + NfsConnect n = null; + + if (server == null) + throw new java.net.UnknownHostException(); + + if (version == 0 && proto == null && pub) // no testing options + n = NfsConnect.cache_get(server); + + if (n == null) + return (connect(server, path, port, version, proto, pub)); + else + return (connect(server, path, n.port, n.version, n.proto, n.pub)); + } + + /** + * Return an Nfs object given a server and pathname + * + * We're not fussy about NFS version or whether TCP + * or UDP is used. + * + * @param server The server that hosts the object + * @param name The pathname of the object + * @returns The object + */ + static Nfs connect(String server, int port, String path) + throws IOException { + + NfsConnect n = NfsConnect.cache_get(server); + if (n == null) + return (connect(server, path, port, 0, null, true)); + else + return (connect(server, path, n.port, n.version, n.proto, n.pub)); + } + + /** + * Return an Nfs object given a server, pathname, version, and protocol + * + * Try to obtain the filehandle for the object via a public filehandle + * otherwise fall back to the mount protocol. + * + * @param server The server that hosts the object + * @param name The pathname of the object + * @param vers The version of NFS to be used. If zero then + * prefer v3 over v2. + * @param proto The transport protocol to be used: "tcp" or "udp." + * If this is null then prefer TCP over UDP. + * @param pub Boolean Public filehandle support. + */ + static Nfs connect(String server, String path, int port, int vers, + String proto, boolean pub) + throws IOException { + + if (port == 0) + port = NFS_PORT; + + if (path == null || path.length() == 0) + path = "."; + + /* + * Check first if we already have the file/dir cached + */ + Nfs nfs = Nfs.cache_get(server, path); + if (nfs != null) { + nfs.getattr(); // for close-to-open consistency + + if (nfs.isSymlink()) + return followLink(nfs); + + return (nfs); + } + + /* + * First set up a connection using the specified proto. + * If neither "tcp" or "udp" is specified, then try + * "tcp" and fall back to "udp" if that fails. + * + * Note that we check to see if there's an existing + * connection to the server and use that if available. + */ + + Connection conn; + + if (proto == null) { + conn = Connection.getCache(server, port, "tcp"); + if (conn == null) + conn = Connection.getCache(server, port, "udp"); + + if (conn == null) { // no cached connections + try { + conn = new ConnectSocket(server, port, MAXBUF); + Connection.putCache(conn); + proto = "tcp"; + + } catch (java.net.UnknownHostException e) { + throw e; // don't catch as an IOException + + } catch (IOException e) { + conn = new ConnectDatagram(server, port, MAXBUF); + Connection.putCache(conn); + proto = "udp"; + } + } + } else if (proto.equals("tcp")) { + conn = Connection.getCache(server, port, "tcp"); + if (conn == null) { + conn = new ConnectSocket(server, port, MAXBUF); + Connection.putCache(conn); + } + + } else if (proto.equals("udp")) { + conn = Connection.getCache(server, port, "udp"); + if (conn == null) { + conn = new ConnectDatagram(server, port, MAXBUF); + Connection.putCache(conn); + } + + } else { + throw new IOException("Unknown protocol: " + proto); + } + + + /* + * Try using the public filehandle + */ + + if (pub) { + try { + switch (vers) { + case 0: + try { + nfs = tryNfs(conn, pubfh3, path, 3, false); + vers = 3; + } catch (MsgAcceptedException e) { + if (e.error != e.PROG_MISMATCH) + throw e; + + vers = 2; + nfs = tryNfs(conn, pubfh2, path, 2, false); + } + break; + case 2: + nfs = tryNfs(conn, pubfh2, path, 2, false); + break; + case 3: + nfs = tryNfs(conn, pubfh3, path, 3, false); + break; + } + + } catch (MsgAcceptedException e) { + if (e.error != e.GARBAGE_ARGS) + throw e; + + // Not WebNFS but which version of NFS ? Assume 3 + + if (vers == 0) + vers = 3; + + } catch (NfsException e) { + if (e.error != e.NFSERR_STALE && e.error != e.NFSERR_BADHANDLE) + throw e; + + if (vers == 0) + vers = 3; // if we get here then server must be v3 + } + + if (nfs != null) { // public fh worked + NfsConnect.cache_put(new NfsConnect(server, port, vers, proto, true)); + return (nfs); + } + } + + /* + * Server doesn't accept public filehandles + * Resort to using the MOUNT protocol + */ + if (path.equals(".")) + path = "/"; + + Mount m = new Mount(); + byte[] fh = m.getFH(server, path, vers); + sec_flavor = m.getSec(); + + NfsConnect.cache_put(new NfsConnect(server, port, vers, proto, false)); + + return (tryNfs(conn, fh, path, vers, true)); + } + + private static Nfs tryNfs(Connection conn, byte[] pubfh, String path, + int vers, boolean mount) + throws IOException { + + Nfs pubnfs; + + Rpc rpc = new Rpc(conn, NFS_PROG, vers); + /* + * Use the default security flavor. + */ + String defaultSec = NfsSecurity.getDefault(); + if (defaultSec.equals("1")){ + // AUTH_SYS + rpc.setCred(cred); + } else { + if (NfsSecurity.getMech(defaultSec) != null) { + // if there is a mechOid, use RPCSEC_GSS + rpc.setCred(new CredGss("nfs", + NfsSecurity.getMech(defaultSec), + NfsSecurity.getService(defaultSec), + NfsSecurity.getQop(defaultSec))); + } else { + // not RPCSEC_GSS; use AUTH_SYS for now + rpc.setCred(cred); + } + } + rpc.setRpcHandler(rhandler); + + if (vers == 2) + pubnfs = new Nfs2(rpc, pubfh, path, null); + else + pubnfs = new Nfs3(rpc, pubfh, path, null); + + if (path.equals("/.")) // special path for testing + return pubnfs; + + if (mount) { + if (NfsSecurity.getMech(sec_flavor) != null) { + rpc.setCred(new CredGss("nfs", + NfsSecurity.getMech(sec_flavor), + NfsSecurity.getService(sec_flavor), + NfsSecurity.getQop(sec_flavor))); + } + + pubnfs.getattr(); + Nfs.cache_put(pubnfs); + + return (pubnfs); + } + /* The path passed to lookup will be null since it + * has been filled in when object has been created. + */ + return (pubnfs.lookup(null)); + } + + + /* + * Given a symbolic link - read its text + * find the NFS object it refers to. + * + * XXX needs to contain a loop (max 30x) to follow + * chains of symlinks properly. + */ + static Nfs followLink(Nfs link) throws IOException { + + String base = link.name; + String text = link.readlink(); + + String server = link.rpc.conn.server; + int port = link.rpc.conn.port; + String newpath; + + if (text.startsWith("nfs://")) { // NFS URL + NfsURL url = new NfsURL(text); + server = url.getHost(); + port = url.getPort(); + newpath = url.getFile(); + + } else if (text.startsWith("/")) { // absolute path + newpath = text; + + } else { + + /* + * Combine base path with relative path + * according to rules in RFCs 1808 & 2054 + * + * e.g. /a/b/c + x = /a/b/x + * /a/b/c + /y = /z + * /a/b/c + ../z = /a/z + */ + int head = 0; + int tail = base.lastIndexOf('/'); + int len = text.length(); + + while (text.regionMatches(head, "..", 0, len - head) || + text.startsWith("../", head)) { + head += 3; + if (head >= len) + break; + tail = base.lastIndexOf('/', tail - 1); + } + if (head > len) + head = len; + if (tail < 0) + tail = 0; + else + tail++; + + newpath = base.substring(0, tail) + text.substring(head); + } + + try { + return (NfsConnect.connect(server, port, newpath)); + } catch (IOException e) { + System.err.println(e + ": symbolic link: " + + base + " -> " + text); + return (link); + } + } + + /** + * Cache an NfsConnect object + * + * @param n the object to be cached + */ + private static void cache_put(NfsConnect n) { + cacheNfsConnect.put(n.server, n); + } + + /** + * Retrieve a cached NfsConnect object + * + * @param server The server that hosts the object + * @returns The object - or null if not cached + */ + private static NfsConnect cache_get(String server) { + return ((NfsConnect)cacheNfsConnect.get(server)); + } + + /** + * Get the credential as a Unix cred + * + * @returns The credential stored for Nfs operations + */ + public static CredUnix getCred() { + return (cred); + } + + /** + * Set the timeout handler + */ + public static void setRpcHandler(RpcHandler r) { + rhandler = r; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsException.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsException.java new file mode 100644 index 0000000000..bf4199f383 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsException.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +/** + * This exception is thrown whenever an NFS error occurs. + */ +public class NfsException extends java.io.IOException { + int error; + + /* + * We're fortunate that NFS v2 and v3 + * share the same error codes + */ + public static final int NFS_OK = 0; + public static final int NFSERR_PERM = 1; + public static final int NFSERR_NOENT = 2; + public static final int NFSERR_IO = 5; + public static final int NFSERR_NXIO = 6; + public static final int NFSERR_ACCES = 13; + public static final int NFSERR_EXIST = 17; + public static final int NFSERR_XDEV = 18; + public static final int NFSERR_NODEV = 19; + public static final int NFSERR_NOTDIR = 20; + public static final int NFSERR_ISDIR = 21; + public static final int NFSERR_INVAL = 22; + public static final int NFSERR_FBIG = 27; + public static final int NFSERR_NOSPC = 28; + public static final int NFSERR_ROFS = 30; + public static final int NFSERR_MLINK = 31; + public static final int NFSERR_NAMETOOLONG = 63; + public static final int NFSERR_NOTEMPTY = 66; + public static final int NFSERR_DQUOT = 69; + public static final int NFSERR_STALE = 70; + public static final int NFSERR_REMOTE = 71; + public static final int NFSERR_BADHANDLE = 10001; + public static final int NFSERR_NOT_SYNC = 10002; + public static final int NFSERR_BAD_COOKIE = 10003; + public static final int NFSERR_NOTSUPP = 10004; + public static final int NFSERR_TOOSMALL = 10005; + public static final int NFSERR_SERVERFAULT = 10006; + public static final int NFSERR_BADTYPE = 10007; + public static final int NFSERR_JUKEBOX = 10008; + + /** + * Create a new NfsException + * + * @param NFS error number for this error + */ + public NfsException(int error) { + super("NFS error: " + error); + this.error = error; + } + + public String toString() { + + switch (error) { + case NFS_OK: + return ("OK"); + case NFSERR_PERM: + return ("Not owner"); + case NFSERR_NOENT: + return ("No such file or directory"); + case NFSERR_IO: + return ("I/O error"); + case NFSERR_NXIO: + return ("No such device or address"); + case NFSERR_ACCES: + return ("Permission denied"); + case NFSERR_EXIST: + return ("File exists"); + case NFSERR_XDEV: + return ("Attempted cross-device link"); + case NFSERR_NODEV: + return ("No such device"); + case NFSERR_NOTDIR: + return ("Not a directory"); + case NFSERR_ISDIR: + return ("Is a directory"); + case NFSERR_INVAL: + return ("Invalid argument"); + case NFSERR_FBIG: + return ("File too large"); + case NFSERR_NOSPC: + return ("No space left on device"); + case NFSERR_ROFS: + return ("Read-only file system"); + case NFSERR_MLINK: + return ("Too many links"); + case NFSERR_NAMETOOLONG: + return ("File name too long"); + case NFSERR_NOTEMPTY: + return ("Directory not empty"); + case NFSERR_DQUOT: + return ("Disk quota exceeded"); + case NFSERR_STALE: + return ("Stale NFS file handle"); + case NFSERR_REMOTE: + return ("Too many levels of remote in path"); + case NFSERR_BADHANDLE: + return ("Illegal NFS file handle"); + case NFSERR_NOT_SYNC: + return ("Update sync mismatch"); + case NFSERR_BAD_COOKIE: + return ("Readdir cookie is stale"); + case NFSERR_NOTSUPP: + return ("Operation not supported"); + case NFSERR_TOOSMALL: + return ("Buffer/request too small"); + case NFSERR_SERVERFAULT: + return ("Server fault"); + case NFSERR_BADTYPE: + return ("Bad type"); + case NFSERR_JUKEBOX: + return ("Jukebox error: try later"); + } + return ("Unknown NFS error: " + error); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsHandler.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsHandler.java new file mode 100644 index 0000000000..33884e41b0 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsHandler.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.rpc.*; + +/** + * This handler is implemented by the NFS application + * if it wishes to be notifed of retransmissions. + * A good example is an NFS client that displays + * "NFS Server not responding" and "NFS server OK" + */ +public abstract class NfsHandler extends RpcHandler { + + /** + * Called when an NFS request has timed out + * + * The RPC code will retransmit NFS requests + * until the server responds. The initial + * retransmission timeout is set by the NFS + * code and increases exponentially with + * each retransmission until an upper bound + * of 30 seconds is reached, e.g. timeouts + * will be 1, 2, 4, 8, 16, 30, 30, ... sec. + *

+ * An instance of the NfsHandler class is + * registered with the setHandler method of + * the NFS XFileExtensionAccessor. + * + * @param server The name of the server to which the + * request was sent. + * @param retries The number of times the request has + * been retransmitted. After the first timeout + * retries will be zero. + * @param wait Total time since first call in milliseconds + * (cumulative value of all retransmission timeouts). + * @return false if retransmissions are to continue. + * If the method returns true, the RPC layer will + * abort the retransmissions and return an + * InterruptedIOException to the application. + */ + public abstract boolean timeout(String server, int retries, int wait); + + /** + * Called when a server reply is recieved after a timeout. + * + * @param server The name of the server that returned + * the reply. + */ + public abstract void ok(String server); +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsSecurity.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsSecurity.java new file mode 100644 index 0000000000..1188e8450b --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsSecurity.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import java.util.*; +import com.sun.rpc.*; + +/** + * NfsSecurity is a static class. It reads in the com.sun.properties.nfssec + * properties file and provides the vehicle to retrieve properties values + * which are the (mechanism, service, qop) mappings for the NFS security pseudo + * flavor numbers. + * + * @author Lin Ling + */ +public final class NfsSecurity { + + static ResourceBundle props; + static String secName, secMode, mech; + static int service, qop; + static { + initialize(); + } + + private static void initialize() { + + try { + props = ResourceBundle.getBundle("com.sun.nfs.nfssec"); + } catch (MissingResourceException e) { + props = null; + } + } + + /* + * Parse the string value using ":" as the delimiter. + * + * nfsSecName:mechanismOID:service:qualityProtection + * + * (e.g. dummyp:1.3.6.1.4.1.42.2.26.1.2:privacy:0) + * + */ + private static void parseValue(String value) { + + StringTokenizer parser = new StringTokenizer(value, ":\n\r"); + + secName = parser.nextToken(); + + try { + mech = parser.nextToken(); + } catch (NoSuchElementException e) { + // non-RPCSEC_GSS flavors + mech = null; + service = 0; + qop = 0; + return; + } + + String serviceString = parser.nextToken(); + if (serviceString.equals("none")) + service = Cred.SVC_NONE; + else if (serviceString.equals("integrity")) + service = Cred.SVC_INTEGRITY; + else if (serviceString.equals("privacy")) + service = Cred.SVC_PRIVACY; + else + service = Cred.SVC_PRIVACY; // just use privacy service + + qop = Integer.parseInt(parser.nextToken()); + + } + + /** + * Does the key have a value defined in the nfssec.properties file? + * (i.e. is key=value defined in the properties list?) + * + * @param key the key to be searched + * @returns true or false + */ + public static boolean hasValue(String key) { + + if (props == null) + return false; + + try { + props.getString(key); + return true; + + } catch (MissingResourceException e) { + return false; + } + } + + /** + * Get the default security flavor number if it is specified in the + * nfssec.properties file, otherwise, simply return "1" for AUTH_SYS. + */ + public static String getDefault() { + + if (props == null) + return "1"; + + try { + return props.getString("default"); + } catch (MissingResourceException e) { + return "1"; + } + } + + /** + * Get the preferred nfs security flavor number if it is specified + * in the nfssec.properties file, otherwise, return null. + */ + public static String getPrefer() { + + if (props == null) + return null; + + try { + return props.getString("prefer"); + } catch (MissingResourceException e) { + return null; + } + } + + /** + * getName will get the NFS security flavor name from the first token + * in the value. + * + * key=nfsSecName:mechOid:service:qop + * ^^^^^^^^^^ + * + * @param key the key to be searched + * @returns NFS Security flavor name + */ + public static String getName(String key) { + + if (key.equals(secMode)) { + return secName; + } + + parseValue(props.getString(key)); + secMode = key; + return secName; + } + + /** + * getMech will get the security mechanism OID string from the second token + * in the value. + * + * key=nfsSecName:mechOid:service:qop + * ^^^^^^^ + * + * @param key the key to be searched + * @returns security mechansim OID string + */ + public static String getMech(String key) { + + if (key.equals(secMode)) { + return mech; + } + + parseValue(props.getString(key)); + secMode = key; + return mech; + } + + /** + * getService will get the security service type from the third token + * in the value. + * + * key=nfsSecName:mechOid:service:qop + * ^^^^^^^ + * + * @param key the key to be searched + * @returns one of (none, integrity, privacy); if the third token + * in the value does not have the expected data, simply + * returns the privacy service number. + */ + public static int getService(String key) { + + if (key.equals(secMode)) { + return service; + } + + parseValue(props.getString(key)); + secMode = key; + return service; + } + + /** + * getQop will get the Quality of Protection number from the fourth token + * in the value. + * + * key=nfsSecName:mechOid:service:qop + * ^^^ + * + * @param key the key to be searched + * @returns qop number; 0 means the mechanism-specific default qop + */ + public static int getQop(String key) { + + if (key.equals(secMode)) { + return qop; + } + + parseValue(props.getString(key)); + secMode = key; + return qop; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsURL.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsURL.java new file mode 100644 index 0000000000..10107b2858 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/NfsURL.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.net.MalformedURLException; + +/** + * This is just a dumb URL parser class. + * I wrote it because I got fed up with the + * JDK URL class calling NFS URL's "invalid" + * simply because the Handler wasn't installed. + * + * This URL parser also handles undocumented + * testing options inserted in the URL in the + * port field. The following sequence of option + * letters may appear before or after the port + * number, or alone if the port number is not + * given. + * vn - NFS version, e.g. "v3" + * u - Force UDP - normally TCP is preferred + * t - Force TDP - don't fall back to UDP + * m - Force Mount protocol. Normally public filehandle + * is preferred + * + * Option ordering is not important. + * + * Example: + * nfs://server:123v2um/path + * + * Use port 123 with NFS v2 over UDP and Mount protocol + * + * nfs://server:m/path + * + * Use default port, prefer V3/TCP but use Mount protocol + * + * @author Brent Callaghan + */ + +public class NfsURL { + + private String url; + private String protocol; + private String host; + private String location; + private int port; + private String file; + + /* + * Undocumented testing options + */ + private int version; + private String proto; + private boolean pub = true; + + public NfsURL(String url) throws MalformedURLException { + int p, q, r; + + url = url.trim(); // remove leading & trailing spaces + this.url = url; + int end = url.length(); + + p = url.indexOf(':'); + if (p < 0) + throw new MalformedURLException("colon expected"); + protocol = url.substring(0, p); + p++; // skip colon + if (url.regionMatches(p, "//", 0, 2)) { // have hostname + p += 2; + q = url.indexOf('/', p); + if (q < 0) + q = end; + location = url.substring(0, q); + r = url.indexOf(':', p); + if (r > 0 && r < q) { + byte[] opts = url.substring(r + 1, q).toLowerCase().getBytes(); + for (int i = 0; i < opts.length; i++) { + if (opts[i] >= '0' && opts[i] <= '9') { + port = (port * 10) + (opts[i] - '0'); + } else { + switch (opts[i]) { + case 'v': // NFS version + version = opts[++i] - '0'; + break; + case 't': // Force TCP only + proto = "tcp"; + break; + case 'u': // Force UDP only + proto = "udp"; + break; + case 'w': // Force WebNFS only + pub = true; + break; + case 'm': // Force MOUNT protocol only + pub = false; + break; + default: + throw new MalformedURLException( + "invalid port number"); + } + } + } + } else { + r = q; // no port + } + if (p < r) + host = url.substring(p, r); + } else { + q = p; + } + + if (q < end) + file = url.substring(q + 1, end); + + } + + public String getProtocol() { + return (protocol); + } + + public String getLocation() { + return (location); + } + + public String getHost() { + return (host); + } + + public int getPort() { + return (port); + } + + public String getFile() { + return (file); + } + + /* + * Undocumented options for testing + */ + int getVersion() { + return (version); + } + + String getProto() { + return (proto); + } + + boolean getPub() { + return (pub); + } + + + public String toString() { + String s = getProtocol() + ":"; + + if (host != null) + s += "//" + host; + + if (port > 0) + s += ":" + port; + + if (file != null) + s += "/" + file; + + return (s); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/XFileAccessor.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/XFileAccessor.java new file mode 100644 index 0000000000..348ee3af05 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/XFileAccessor.java @@ -0,0 +1,387 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import com.sun.xfile.*; +import java.io.*; +import java.net.*; + +/** + * The XFileAccessor interface is implemented by filesystems that + * need to be accessed via the XFile API. + * + * @author Brent Callaghan + * @version 1.0, 04/08/98 + * @see com.sun.xfile.XFile + */ +public +class XFileAccessor implements com.sun.xfile.XFileAccessor { + + XFile xf; + boolean serial; + boolean readOnly; + Nfs nfs; + + /** + * Open this NFS object + * + * @param xf the XFile object + * @param serial true if serial access + * @param readOnly true if read only + */ + public boolean open(XFile xf, boolean serial, boolean readOnly) { + this.xf = xf; + try { + nfs = NfsConnect.connect(xf.getAbsolutePath()); + return true; + } catch (IOException e) { + return false; + } + } + + public XFile getXFile() { + return xf; + } + + protected Nfs getParent(XFile xf) throws IOException { + XFile xfp = new XFile(xf.getParent()); + XFileAccessor nfsx = new XFileAccessor(); + nfsx.open(xfp, serial, readOnly); + + return nfsx.getNfs(); + } + + protected Nfs getNfs() { + return nfs; + } + + /** + * Tests if this XFileAccessor object exists. + * + * @return true if the file specified by this object + * exists; false otherwise. + */ + public boolean exists() { + try { + return nfs.exists(); + } catch (Exception e) { + return false; + } + } + + + /** + * Tests if the application can write to this file. + * + * @return true if the application is allowed to + * write to a file whose name is specified by this + * object; false otherwise. + */ + public boolean canWrite() { + try { + return nfs.canWrite(); + } catch (IOException e) { + return false; + } + } + + + /** + * Tests if the application can read from the specified file. + * + * @return true if the file specified by this + * object exists and the application can read the file; + * false otherwise. + */ + public boolean canRead() { + try { + return nfs.canRead(); + } catch (IOException e) { + return false; + } + } + + /** + * Tests if the file represented by this + * object is a "normal" nfs. + *

+ * A file is "normal" if it is not a directory and, in + * addition, satisfies other system-dependent criteria. Any + * non-directory file created by a Java application is + * guaranteed to be a normal nfs. + * + * @return true if the file specified by this + * XFile object exists and is a "normal" + * file; false otherwise. + */ + public boolean isFile() { + try { + return nfs.isFile(); + } catch (IOException e) { + return false; + } + } + + + /** + * Tests if the file represented by this XFileAccessor + * object is a directory. + * + * @return true if this XFileAccessor object + * exists and is a directory; false + * otherwise. + */ + public boolean isDirectory() { + try { + return nfs.isDirectory(); + } catch (IOException e) { + return false; + } + } + + + /** + * Returns the time that the file represented by this + * XFile object was last modified. + *

+ * The return value is system dependent and should only be + * used to compare with other values returned by last modified. + * It should not be interpreted as an absolute time. + * + * @return the time the file specified by this object was last + * modified, or 0L if the specified file + * does not exist. + */ + public long lastModified() { + try { + return nfs.mtime(); + } catch (IOException e) { + return 0L; + } + } + + + /** + * Returns the length of the file represented by this + * XFileAccessor object. + * + * @return the length, in bytes, of the file specified by + * this object, or 0L if the specified + * file does not exist. + */ + public long length() { + try { + return nfs.length(); + } catch (IOException e) { + return 0L; + } + } + + + /** + * Creates a file whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the file could be created; + * false otherwise. + */ + public boolean mkfile() { + try { + nfs = getParent(xf).create(xf.getName(), (long)0666); + return true; + + } catch (Exception e) { + return false; + } + } + + + /** + * Creates a directory whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the directory could be created; + * false otherwise. + */ + public boolean mkdir() { + try { + nfs = getParent(xf).mkdir(xf.getName(), (long)0777); + return true; + + } catch (Exception e) { + return false; + } + } + + + /** + * Renames the file specified by this XFileAccessor object to + * have the pathname given by the XFileAccessor object argument. + * + * @param dest the new filename. + * @return true if the renaming succeeds; + * false otherwise. + */ + public boolean renameTo(XFile dest) { + try { + Nfs sParent = getParent(xf); + Nfs dParent = getParent(dest); + + return sParent.rename(dParent, xf.getName(), dest.getName()); + } catch (Exception e) { + return false; + } + } + + + /** + * Returns a list of the files in the directory specified by + * this XFileAccessor object. + * + * @return an array of file names in the specified directory. + * This list does not include the current directory or + * the parent directory ("." and + * ".." on Unix systems). + */ + public String[] list() { + try { + return nfs.readdir(); + } catch (IOException e) { + return null; + } + } + + + /** + * Deletes the file specified by this object. If the target + * file to be deleted is a directory, it must be empty for + * deletion to succeed. + * + * @return true if the file is successfully deleted; + * false otherwise. + */ + public boolean delete() { + boolean ok; + + try { + if (isFile()) + ok = getParent(xf).remove(xf.getName()); + else + ok = getParent(xf).rmdir(xf.getName()); + + // Purge cached attrs & filehandle + + if (ok) { + nfs.invalidate(); + nfs = null; + } + + return ok; + + } catch (Exception e) { + return false; + } + } + + + /** + * Reads a subarray as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param foff the offset into the file + * @exception java.io.IOException If an I/O error has occurred. + */ + public int read(byte b[], int off, int len, long foff) + throws IOException { + + int c = nfs.read(b, off, len, foff); + return c; + } + + + /** + * Writes a sub array as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param foff the offset into the file + * @exception java.io.IOException If an I/O error has occurred. + */ + public void write(byte b[], int off, int len, long foff) + throws IOException { + + nfs.write(b, off, len, foff); + } + + + /** + * Forces any buffered output bytes to be written out. + *

+ * + * @exception java.io.IOException if an I/O error occurs. + */ + public void flush() throws IOException { + nfs.flush(); + } + + + /** + * Close the file + * + * Since NFS has no concept of file close, we just + * flush any buffered data. + * + * @exception java.io.IOException If an I/O error has occurred. + */ + public void close() throws IOException { + nfs.close(); + } + + + /** + * Returns a string representation of this object. + * + * @return a string giving the pathname of this object. + */ + public String toString() { + return nfs.toString(); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/XFileExtensionAccessor.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/XFileExtensionAccessor.java new file mode 100644 index 0000000000..0ac6e86f4e --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/XFileExtensionAccessor.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +import java.io.*; +import com.sun.xfile.*; + +public class XFileExtensionAccessor + extends com.sun.xfile.XFileExtensionAccessor { + + XFile xf; + + public XFileExtensionAccessor(XFile xf) { + + super(xf); + if (! xf.getFileSystemName().equals("nfs")) + throw new IllegalArgumentException("Invalid argument"); + + this.xf = xf; + } + + /** + * Sets the user's RPC credential from Login name and password. + * + * Every NFS request includes a "credential" that identifies the user. + * An AUTH_SYS credential includes the user's UID and GID values. + * These are determined from the user's login name (and password) + * by the PCNFSD service that must be available on a local server. + * Once the credential is set, it is assigned globally to all + * future NFS XFile objects. + *

+ * If this method is not called, a default credential is assigned + * with a UID and GID of "nobody". + * + * @param host The name of the host that runs the PCNFSD service. + * This does not have to be an NFS server. + * @param username The user's login name. + * @param password The user's password. + * This is obscured before transmission to the PCNFSD server. + * @return true if the login succeeded, false otherwise. + */ + public boolean loginPCNFSD(String host, String username, String password) { + return NfsConnect.getCred().fetchCred(host, username, password); + } + + /** + * Sets the user's RPC credential to "nobody" + */ + + public void logoutPCNFSD() { + NfsConnect.getCred().setCred(); + } + + + /** + * Sets the user's RPC credential to a known uid/gid. + * + * Assumes that the calling application has already + * authenticated the user and has obtained to uid/gid + * itself. + *

+ * Note: This credential setting method exposes an + * inherent security hole in RPC AUTH_SYS authentication. + * The server trusts the client to authenticate the + * user before setting the UID and GID values. It is + * possible for a malicious client to allow the UID and/or + * group ids to be set to allow unauthorized access to + * other user's files on the server. + *

+ * Servers can avoid this security hole by exporting NFS + * filesystem securely - requiring clients to use secure + * Diffie-Hellman or Kerberos credentials. + * + *

+ * If this method is not called, a default credential is assigned + * with a UID and GID of "nobody". + * + * @param uid The user-ID. + * @param gid The group-ID. + * @param gids The group-ID list. + */ + public void loginUGID(int uid, int gid, int[] gids) { + NfsConnect.getCred().setCred(uid, gid, gids); + } + + /** + * Sets the user's RPC credential to "nobody" + */ + + public void logoutUGID() { + NfsConnect.getCred().setCred(); + } + + /** + * Assigns an NfsHandler class that allows + * the application to receive RPC timeout + * notifications. The handler is used for all + * NFS files accessed by the application. + * The default handler can be restored by + * passing a null handler argument. + * + * @param handler An instance of the NfsHandler class. + */ + public void setNfsHandler(NfsHandler handler) { + NfsConnect.setRpcHandler(handler); + } + + /** + * Get server's export list + */ + public String[] getExports() + throws java.net.UnknownHostException, IOException { + + return new Mount().getExports(new NfsURL(xf.toString()).getHost()); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/nfs/nfsXFileExtensionAccessor.java b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/nfsXFileExtensionAccessor.java new file mode 100644 index 0000000000..01c50f5148 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/nfs/nfsXFileExtensionAccessor.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.nfs; + +/** + * This is a compatibility stub for the NFS XFileExtensionAccessor + * + * @see com.sun.nfs.XFileExtensionAccessor + * @deprecated The more generic XFileExtensionAccessor class + * should be used instead. + */ +public class nfsXFileExtensionAccessor + extends com.sun.nfs.XFileExtensionAccessor { + + public nfsXFileExtensionAccessor(com.sun.xfile.XFile xf) { + super(xf); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/ConnectDatagram.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/ConnectDatagram.java new file mode 100644 index 0000000000..100d56d529 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/ConnectDatagram.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +import java.io.*; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; + +/** + * Sets up a UDP connection to the server. + * Since UDP is really connectionless, we + * don't really have a connection, so perhaps + * describing this as an association + * is more accurate. + * + * This class lets us transmit and receive buffers + * of data to a port on a remote server. + * + * @see Connection + * @author Brent Callaghan + */ +public class ConnectDatagram extends Connection { + + DatagramSocket ds; + DatagramPacket dp; + InetAddress addr; + + /** + * Construct a new connection to a specified server and port. + * @param server The hostname of the server + * @param port The port number on the server + * @param maxSize The maximum size in bytes of the received message + * @exception IOException if the server does not exist + */ + public ConnectDatagram (String server, int port, int maxSize) + throws IOException { + + super(server, port, "udp", maxSize); + + ds = new DatagramSocket(); + addr = InetAddress.getByName(server); + start(); + } + + void sendOne(Xdr x) throws IOException { + + /* + * The interrupt call here is to break the listener + * thread from its socket read. For some unknown + * reason a datagram socket read blocks threads + * attempting to send. The interrupt unblocks the + * listener briefly so we can do the send. + * + * The blocking problem appears to be fixed as + * of JDK 1.1.6, so the interrupt is skipped removed. + */ + //interrupt(); + + ds.send(new DatagramPacket(x.xdr_buf(), x.xdr_offset(), addr, port)); + } + + void receiveOne(Xdr x, int timeout) throws IOException { + ds.setSoTimeout(timeout); + dp = new DatagramPacket(x.xdr_buf(), x.xdr_buf().length); + ds.receive(dp); + } + + InetAddress getPeer() { + return dp.getAddress(); + } + + /* + * No connection to drop. + */ + void dropConnection() { + } + + /* + * No connection to check + */ + void checkConnection() { + } + + protected void finalize() throws Throwable { + if (ds != null) { + ds.close(); + ds = null; + } + super.finalize(); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/ConnectSocket.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/ConnectSocket.java new file mode 100644 index 0000000000..595cba8e2c --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/ConnectSocket.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +import java.io.*; +import java.net.Socket; +import java.net.InetAddress; + +/** + * Sets up a TCP connection to the server. + * + * This class lets us transmit and receive buffers + * of data to a port on a remote server. + * It also handles reconnection of broken TCP links. + * + * @see Connection + * @author Brent Callaghan + */ +public class ConnectSocket extends Connection { + + static final int LAST_FRAG = 0x80000000; + static final int SIZE_MASK = 0x7fffffff; + static final int MTUSZ = 1460 - 4; // good for Ethernet + + private OutputStream outs; + private InputStream ins; + private Socket sock; + Xdr rcv_mark = new Xdr(4); + + /** + * Construct a new connection to a specified server and port. + * + * @param server The hostname of the server + * @param port The port number on the server + * @param maxSize The maximum size of the received reply + * @exception IOException if the connection cannot be made + */ + public ConnectSocket (String server, int port, int maxSize) + throws IOException { + + super(server, port, "tcp", maxSize); + doConnect(); + start(); // the listener + } + + private void doConnect() + throws IOException { + + if (server == null) + throw new java.net.UnknownHostException("null host"); + + sock = new Socket(server, port); + sock.setTcpNoDelay(true); + ins = sock.getInputStream(); + outs = sock.getOutputStream(); + } + + private void doClose() throws IOException { + if (ins != null) { + ins.close(); + ins = null; + } + + if (outs != null) { + outs.close(); + outs = null; + } + + if (sock != null) { + sock.close(); + sock = null; + } + } + + void sendOne(Xdr x) throws IOException { + int recsize; + int lastbit = 0; + int bufsiz = x.xdr_offset(); + int save; + + /* + * Use the connection only if unlocked. + * Otherwise we risk attempting a sendOne() + * while it's being reconnected. We also + * need to protect threads from a concurrent + * sendOne that may interleave record data. + */ + synchronized (this) { + /* + * The XDR buffer needs to be transmitted on the + * socket outputstream in MTUSZ records. In RPC + * over TCP each of these records begins with a + * 32 bit record mark which comprises a byte + * count for the record and a LAST_FRAG bit which + * is set on the last record. + * + * You'll notice that the code goes through some + * hoops to prepend this record mark on each of + * the records transmitted from the XDR buffer + * WITHOUT COPYING THE DATA. + * Notice that there's a 4 octet space inserted at + * the front of the buffer for the first record + * mark by the code that builds the RPC header. + * Space is taken from the buffer for subsequent + * record marks and the data in this space is + * saved and restored after the record is sent, + * so hopefully we leave things as they were + * when we're done. + * + * BTW: this code originally wrote the record + * mark to the OutputStream separately, but the + * JVM doesn't seem to be doing Nagle and the + * record mark sailed off in its own tiny TCP + * segment separate from the rest of the record, + * which wasn't what I had in mind. + */ + for (int off = 4; off < bufsiz; off += recsize) { + /* + * Insert the record mark + */ + recsize = bufsiz - off; + if (recsize > MTUSZ) + recsize = MTUSZ; + if ((off + recsize) >= bufsiz) + lastbit = LAST_FRAG; + x.xdr_offset(off-4); + save = x.xdr_int(); + x.xdr_offset(off-4); + x.xdr_int(lastbit | recsize); + + /* + * then send the record data + */ + outs.write(x.xdr_buf(), off-4, recsize+4); + outs.flush(); + x.xdr_offset(off-4); + x.xdr_int(save); + } + x.xdr_offset(bufsiz); // restore XDR offset + } + } + + void receiveOne(Xdr x, int timeout) throws IOException { + int off; + int rcount; + boolean lastfrag = false; + long recsize; + + sock.setSoTimeout(timeout); + + try { + for (off = 0; !lastfrag; off += recsize) { + /* + * Read the record mark + */ + if (ins.read(rcv_mark.xdr_buf()) != 4) + throw new IOException("TCP record mark: lost connection"); + rcv_mark.xdr_offset(0); + recsize = rcv_mark.xdr_u_int(); + lastfrag = (recsize & LAST_FRAG) != 0; + recsize &= SIZE_MASK; + + /* + * then read the record data + */ + for (int i = 0; i < recsize; i += rcount) { + rcount = ins.read(x.xdr_buf(), off + i, (int) recsize - i); + if (rcount < 0) + throw new IOException("TCP data: lost connection"); + } + } + x.xdr_size(off); + } catch (java.io.InterruptedIOException e) { + throw e; + + } catch (IOException e) { + /* + * Assume something bad happened to the connection. + * Close the connection and attempt to reconnect. + */ + reconnect(); + throw e; + } + } + + /* + * Get the address of the caller. + * This is needed when we get a reply from + * and RPC to a broadcast address. + */ + InetAddress getPeer() { + return sock.getInetAddress(); + } + + /* + * This method is called when it is suspected that + * the connection has been broken. It keeps retrying + * connection attempts until it is successful. + */ + void reconnect() { + + System.err.println("Lost connection to " + server + + " - attempting to reconnect"); + + /* + * Lock the connection while we're messing + * with it so that another thread can't + * attempt a sendOne() on it. + */ + synchronized (this) { + while (true) { + try { + doClose(); // make sure we're at a known state + doConnect(); + break; // success + + } catch (IOException e) { + + /* + * Wait here for 5 sec so's we don't + * overwhelm the server with connection requests. + */ + try { + java.lang.Thread.sleep(5000); + } catch (java.lang.InterruptedException i) { + } + } + } + } + + System.err.println("Reconnected to " + server); + } + + /* + * The listener calls this after an idle timeout. + * Be kind to the server and drop the connection. + */ + void dropConnection() { + try { + doClose(); + } catch (IOException e) {}; + } + + /* + * Check to make sure that the connection is up. + * If not, then reconnect and resume the listener. + */ + void checkConnection() { + if (sock != null) + return; + + reconnect(); + } + + protected void finalize() throws Throwable { + doClose(); + super.finalize(); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Connection.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Connection.java new file mode 100644 index 0000000000..5a37acc587 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Connection.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +import java.io.*; +import java.util.Hashtable; +import java.net.InetAddress; + +/** + * Sets up a connection to the server using + * either UDP or TCP as determined by the + * subclass. + * + * This class also handles the connection caching. + * + * @see ConnectSocket + * @see ConnectDatagram + * @author Brent Callaghan + */ +public abstract class Connection extends Thread { + + static Hashtable connections = new Hashtable(); + public String server; + public int port; + String proto; + Hashtable waiters = new Hashtable(); + static final int IDLETIME = 300 * 1000; // idle connection after 5 min + int xid; // transaction id + Xdr reply; + int maxSize; // size of reply Xdr buffer + Error err; // might get thrown by the thread + + /** + * Construct a new connection to a specified server + * and port using protocol proto with a + * reply buffer of size maxsize. + * + * @param server The hostname of the server + * @param port The port number on the server + */ + public Connection (String server, int port, String proto, int maxSize) { + this.server = server; + this.port = port; + this.proto = proto; + this.maxSize = maxSize; + + setName("Listener-" + server); + setDaemon(true); + } + + /** + * Get a cached connection for the specified server, port and protocol + * + * @param server The hostname of the server + * @param port The port number on the server + * @param proto The connection type: "tcp" or "udp" + * @returns null If there is no cached connection + */ + public static Connection getCache(String server, int port, String proto) { + Connection conn = (Connection) connections.get( + server + ":" + port + ":" + proto); + + return conn; + } + + /** + * Stash a new connection in the cache + * + * @param The connection to be cached + */ + public static void putCache(Connection conn) { + connections.put(conn.server + ":" + conn.port + ":" + conn.proto, conn); + } + + abstract void sendOne(Xdr call) throws IOException; + + abstract void receiveOne(Xdr reply, int timeout) throws IOException; + + abstract InetAddress getPeer(); + + abstract void dropConnection(); + + abstract void checkConnection(); + + /** + * Return information about the connection + * + * @returns server, port number and protocol info. + */ + public String toString() { + return (server + ":" + port + ":" + proto); + } + + private boolean running; + + synchronized void suspendListener() { + running = false; + + while (!running) { + try { + wait(); + } catch (InterruptedException e) {} + } + } + + synchronized void resumeListener() { + running = true; + notifyAll(); + } + + synchronized Xdr send(Xdr call, int timeout) + throws IOException { + + checkConnection(); + resumeListener(); + sendOne(call); + + waiters.put(new Integer(call.xid), new Integer(timeout)); + + /* + * Now sleep until the listener thread posts + * my XID and notifies me - or I time out. + */ + while (xid != call.xid) { + long t = System.currentTimeMillis(); + + if (err != null) + throw err; + + try { + wait(timeout); + } catch (InterruptedException e) {} + + if (err != null) + throw err; + + timeout -= (System.currentTimeMillis() - t); + if (timeout <= 0) { + waiters.remove(new Integer(call.xid)); + throw new InterruptedIOException(); // timed out + } + } + + /* + * My reply has come in. + */ + xid = 0; + waiters.remove(new Integer(call.xid)); + notifyAll(); // wake the listener + + return reply; + } + + /* + * This is the code for the listener thread. + * It blocks in a receive waiting for an RPC + * reply to come in, then delivers it to the + * appropriate thread. + */ + public void run() { + + try { + while (true) { + + synchronized (this) { + while (xid != 0) { + try { + wait(); + } catch (InterruptedException e) {} + } + } + + reply = new Xdr(maxSize); + + /* + * The listener thread now blocks reading + * from the socket until either a packet + * comes in - or it gets an idle timeout. + */ + try { + receiveOne(reply, IDLETIME); + } catch (InterruptedIOException e) { + + /* + * Got an idle timeout. If there's + * no threads waiting then drop the + * connection and suspend. + */ + if (waiters.isEmpty()) + dropConnection(); + suspendListener(); + } catch (IOException e) { + continue; + } + + /* + * Have received an Xdr buffer. + * Extract the xid and check the hashtable + * to see if there's thread waiting for that reply. + * If there is, then notify the thread. If not + * then ignore the reply (its thread may + * have timed out and gone away). + */ + synchronized (this) { + xid = reply.xdr_int(); + if (waiters.containsKey(new Integer(xid))) + notifyAll(); + else + xid = 0; // ignore it + } + } + } catch (Error e) { + /* + * Need to catch errors here, e.g. OutOfMemoryError + * and notify threads before this listener thread dies + * otherwise they'll wait forever. + */ + this.err = e; + synchronized (this) { + notifyAll(); + } + throw e; + } + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Cred.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Cred.java new file mode 100644 index 0000000000..c6a9c5f13d --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Cred.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +/** + * RPC Credentials + * + * Extended by each credential class + */ + +public abstract class Cred { + + // service types: authentication, integrity and privacy + public static final int SVC_NONE = 1; + public static final int SVC_INTEGRITY = 2; + public static final int SVC_PRIVACY = 3; + + /** + * Put creds into an XDR buffer + */ + abstract void putCred(Xdr x) throws RpcException; + + /** + * Get creds from an XDR buffer + */ + abstract void getCred(Xdr x); + + /** + * Initiate a security context with peers + */ + abstract void init(Connection conn, int prog, int vers) + throws RpcException; + + /** + * Refresh the cred + */ + abstract boolean refresh(Connection conn, int prog, int vers); + + /** + * Encrypt an XDR buffer + */ + abstract void wrap(Xdr x, byte[] arg) throws RpcException; + + /** + * Descrypt an XDR buffer + */ + abstract int unwrap(Xdr x) throws RpcException; + + /** + * Validate the response verifier from server + */ + abstract void validate(byte[] verifier, int verifiee) + throws RpcException; + + /** + * Destroy the cred data and its security context with the server + */ + abstract void destroy(Rpc rpc) throws RpcException; + +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/CredGss.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/CredGss.java new file mode 100644 index 0000000000..eb982f327b --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/CredGss.java @@ -0,0 +1,600 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +import java.io.*; +import com.sun.gssapi.*; + +/** + * The credential class for the RPCSEC_GSS security flavor. + * + * @see Cred + * @author Lin Ling + * + */ + +public class CredGss extends Cred { + + /* + * These are the data needed for setting up RPCSEC_GSS dialog. + */ + public int serviceType; // authenticate, integrity or privacy + + Oid mechOid; + int qop; + String serviceName; // e.g. "nfs" is a service name + int seq_num_out; // sequence number in the out going request + int seq_window; + int control; // RPCSEC_GSS_INIT or RPCSEC_GSS_DATA ...etc + GSSContext gssCtx; // context object for gss operations + byte[] ctx_handle; // context handle for the security context + + public static final int RPCSEC_GSS = 6; + public static final int RPCSEC_GSS_DATA = 0; + public static final int RPCSEC_GSS_INIT = 1; + public static final int RPCSEC_GSS_CONTINUE_INIT = 2; + public static final int RPCSEC_GSS_DESTROY = 3; + + public static final int RPCSEC_GSS_VERS_1 = 1; + + private static final int RPCGSS_MAXSZ = 1024; + private static final int PROC_NULL = 0; + + + /** + * Constructor creates an instance of RPCSEC_GSS credential with + * given service name, mechanism, service type and qop number. + * + * @param svcName the target service name + * @param mech the string format of mech oid; e.g. "1.2.3.4.5" + * @param svcType none, integrity or privacy + * @param qop_num the number of quality protection + */ + public CredGss(String svcName, String mech, int svcType, int qop_num) + throws IOException { + + try { + mechOid = new Oid(mech); + } catch (GSSException e) { + throw new IOException ("can not construct CredGss object"); + } + serviceName = svcName; + serviceType = svcType; + qop = qop_num; + seq_num_out = 0; + ctx_handle = null; + gssCtx = null; + control = RPCSEC_GSS_INIT; + } + + /** + * Constructor creates an instance of RPCSEC_GSS credential with + * given service name, mechanism, service type and qop number. + * + * @param svcName the target service name + * @param mech the GSS Oid object of the mech + * @param svcType none, integrity or privacy + * @param qop_num the number of quality protection + */ + public CredGss(String svcName, Oid mech, int svcType, int qop_num) { + + mechOid = mech; + serviceName = svcName; + serviceType = svcType; + qop = qop_num; + seq_num_out = 0; + ctx_handle = null; + gssCtx = null; + control = RPCSEC_GSS_INIT; + } + + /** + * Put RPCSEC_GSS cred/verf into an XDR buffer + * + * @param xdr buffer + */ + synchronized void putCred(Xdr x) throws RpcException { + + MessageProp mInfo = new MessageProp(qop, false); + + /* + * Marshalling the cred field + */ + x.xdr_int(RPCSEC_GSS); + + /* + * For every data request (including retransmit) + * use a different sequence number. + */ + if (control == RPCSEC_GSS_DATA || control == RPCSEC_GSS_DESTROY) + seq_num_out++; + + /* + * If a context is established, encode the context handle. + * otherwise, encode a 0 length field. + */ + if (ctx_handle != null) { + // length = 20 + ctx_handle.length + x.xdr_int(20 + ctx_handle.length); + x.xdr_int(RPCSEC_GSS_VERS_1); + x.xdr_int(control); + x.xdr_int(seq_num_out); + x.xdr_int(serviceType); + x.xdr_bytes(ctx_handle); + } else { + // length = 20 + x.xdr_int(20); + x.xdr_int(RPCSEC_GSS_VERS_1); + x.xdr_int(control); + x.xdr_int(seq_num_out); + x.xdr_int(serviceType); + x.xdr_int(0); + } + + /* + * Marshalling the verifier field + */ + if (gssCtx != null) { + // Checksum the header data upto cred field. + try { + byte[] headerMIC = gssCtx.getMIC(x.xdr_buf(), 0, + x.xdr_offset(), mInfo); + x.xdr_int(RPCSEC_GSS); + x.xdr_bytes(headerMIC); + } catch (GSSException e) { + throw new RpcException("can not checksum the header"); + } + } else { + // if context is not established yet, use null verifier + x.xdr_int(CredNone.AUTH_NONE); + x.xdr_int(0); + } + + x.xdr_wrap_offset(x.xdr_offset()); + if (control == RPCSEC_GSS_DATA && serviceType != SVC_NONE) { + x.xdr_int(seq_num_out); + } + } + + public void getCred(Xdr x) { + // No-Op + } + + /* + * Send rpcsec_gss init control requests. Retry if time out. + * + * This routine is similar to rpc.rpc_call() but is customized for the + * rpcsec_gss init sec context handshakes. + * + * For init control requests, when it needs to do a refresh, it does + * not need to retry the original init call after the cred is refreshed. + * (upon a successful refresh, a context is established) + * Use this routine instead of rpc_call() to avoid confusion. + */ + private Xdr rpc_send(Rpc rpc, Xdr call, int timeout, int retries) + throws RpcException, IOException { + + Xdr reply = null; + + if (retries == 0) { + retries = Integer.MAX_VALUE; //retry forever + } + + for (int c = 0; c < retries; c++) { + + /* + * This is for init control requests, not a data request. + * No argument for wrapping. + */ + try { + reply = rpc.rpc_call_one(call, null, timeout); + break; // reply received OK + + } catch (RpcException e) { + throw e; + + } catch (IOException e) { + // probably a timeout. retry + continue; + } + } + + if (reply == null) // reached retry limit + throw new InterruptedIOException(); + + return reply; + } + + /** + * Init a security context using the given connection instance. + * + * @param conn The connection to the server + * @param prog The program number of the rpc service + * @param vers The version number of the rpc service + */ + synchronized void init(Connection conn, int prog, int vers) + throws RpcException { + + byte[] inTok = new byte[0]; + Rpc secRpc; + Xdr secCall, secReply; + CredGss initCred; + int major = 0, minor = 0; + + try { + GSSContext ctx = new GSSContext(new GSSName(serviceName, + GSSName.NT_HOSTBASED_SERVICE), + mechOid, null, 0); + + // set context options + ctx.requestConf(true); + ctx.requestInteg(true); + ctx.requestMutualAuth(true); + ctx.requestReplayDet(true); + ctx.requestSequenceDet(true); + + initCred = new CredGss(serviceName, mechOid, serviceType, qop); + secRpc = new Rpc(conn, prog, vers, initCred); + secCall = new Xdr(RPCGSS_MAXSZ); + + /* + * gss token exchange semantics: + * + * (1 token) + * Client Server + * init stat = complete + * token length > 0 ---> token --> accept stat = complete + * token.len = 0 + * + * (2 tokens) + * Client Server + * init stat = cont + * token.length > 0 ---> token ---> accept stat = complete + * token.len > 0 + * <--- token <--- + * init stat = complete + * token.length = 0 + * + * (3 tokens) + * Client Server + * init stat = cont + * token.length > 0 ---> token ---> accept stat = cont + * token.length > 0 + * <--- token <--- + * init stat = complete + * token.length > 0 ---> token ---> accept stat = complete + * token.length = 0 + */ + initCred.control = RPCSEC_GSS_INIT; + int num_refresh = 2; + do { + byte[] outTok = ctx.init(inTok, 0, inTok.length); + + if (outTok != null) { + secRpc.rpc_header(secCall, PROC_NULL); + secCall.xdr_bytes(outTok); + + try { + secReply = rpc_send(secRpc, secCall, 30 * 1000, 5); + + } catch (MsgRejectedException e) { + + if (num_refresh > 0 && + (e.why == MsgRejectedException.RPCSEC_GSS_NOCRED || + e.why == MsgRejectedException.RPCSEC_GSS_FAILED)) { + + // reset the parameters and retry (refresh) + inTok = new byte[0]; + ctx = new GSSContext(new GSSName(serviceName, + GSSName.NT_HOSTBASED_SERVICE), + mechOid, null, 0); + ctx.requestConf(true); + ctx.requestInteg(true); + ctx.requestMutualAuth(true); + ctx.requestReplayDet(true); + ctx.requestSequenceDet(true); + initCred.gssCtx = null; + initCred.ctx_handle = null; + initCred.control = RPCSEC_GSS_INIT; + num_refresh--; + continue; + + } else { + throw e; + } + } catch (RpcException e) { + throw e; + } + + // decode the result and get the context id + this.ctx_handle = secReply.xdr_bytes(); + major = secReply.xdr_int(); + minor = secReply.xdr_int(); + if (major != GSSContext.COMPLETE && + major != GSSContext.CONTINUE_NEEDED) { + + throw new RpcException("cred.init server failed"); + } + + this.seq_window = secReply.xdr_int(); + inTok = secReply.xdr_bytes(); // token from the server + + if (!ctx.isEstablished() && inTok == null) { + throw new RpcException("cred.init:bad token"); + } + + } else if (major == GSSContext.CONTINUE_NEEDED) { + // no more token, but server is waiting for one + throw new RpcException("cred.init:server needs token"); + } + + initCred.control = RPCSEC_GSS_CONTINUE_INIT; + initCred.ctx_handle = ctx_handle; + + } while (!ctx.isEstablished()); + + this.gssCtx = ctx; + this.control = RPCSEC_GSS_DATA; + + } catch (IOException e) { + throw new RpcException("cred.init: io errors "); + } catch (GSSException e) { + throw new RpcException("cred.init: gss errors"); + } + } + + /** + * Refresh the RPCSEC_GSS credential. + * Nulled context and ctx_handle and re-try init sec context. + * + * @param conn The connection to the server + * @param prog The program number of the rpc service + * @param vers The version number of the rpc service + * @return true if success + */ + synchronized boolean refresh(Connection conn, int prog, int vers) { + + // If no context has established, don't try to recreate it. + if (ctx_handle == null) { + return false; + } + + gssCtx = null; + ctx_handle = null; + try { + init(conn, prog, vers); + return true; + } catch (RpcException e) { + return false; + } + } + + /** + * Use this cred object to encrypt the given xdr buffer. + * + * @param call xdr buffer + * @param arg the rpc argument to be encrypted + * @return the xdr buffer with the encrypted data + */ + synchronized void wrap(Xdr call, byte[] arg) throws RpcException { + byte[] argTok; + MessageProp mInfo = new MessageProp(qop, false); + + if (control != RPCSEC_GSS_DATA) { + return; + } + + try { + switch (serviceType) { + case SVC_NONE: + break; + + case SVC_INTEGRITY: + argTok = gssCtx.getMIC(arg, 0, arg.length, mInfo); + call.xdr_offset(call.xdr_wrap_offset()); + call.xdr_bytes(arg); + call.xdr_bytes(argTok); + break; + + case SVC_PRIVACY: + mInfo.setPrivacy(true); + argTok = gssCtx.wrap(arg, 0, arg.length, mInfo); + call.xdr_offset(call.xdr_wrap_offset()); + call.xdr_bytes(argTok); + break; + } + + } catch (GSSException e) { + throw new RpcException("wrap: Can not wrap RPC arg"); + } + } + + /** + * Use this cred object to decrypt the given xdr buffer. + * + * @param reply xdr buffer + * @return the xdr buffer with the unencrypted data + */ + synchronized int unwrap(Xdr reply) throws RpcException { + int result_off, result_len, verify_off, csum_len, seq_num_in = 0; + byte[] result; + MessageProp mInfo = new MessageProp(); + + if (control != RPCSEC_GSS_DATA) { + return 0; + } + + result_off = reply.xdr_offset(); + + switch (serviceType) { + case SVC_NONE: + return 0; + + case SVC_INTEGRITY: + result_len = reply.xdr_int(); + if (result_len <= 4) // length of (seq num + rpc arg) is 0 or 4 + return 0; + + verify_off = reply.xdr_offset(); // offset of (seq num + rpc arg) + seq_num_in = reply.xdr_int(); + /* + * When server is slow, it is possible that client will + * receive packets in different order. Seqence window should be + * the maximum number of client requests that maybe outstanding + * for this context. The this.seq_window is set to the sequence + * window length supported by the server for this context. + */ + if ((seq_num_in < (seq_num_out - seq_window)) || + (seq_num_in > seq_num_out)) { + throw new RpcException("unwrap: bad sequence number"); + } + + result = reply.xdr_raw(result_len - 4); // 4-length of seq num + csum_len = reply.xdr_int(); + + try { + gssCtx.verifyMIC(reply.xdr_buf(), reply.xdr_offset(), + csum_len, reply.xdr_buf(), verify_off, + result_len, mInfo); + } catch (GSSException e) { + throw new RpcException("unwrap: gss_verifyMIC failed"); + } + + if (mInfo.getQOP() != qop) { + throw new RpcException("unwrap: unexpected qop"); + } + + reply.xdr_offset(result_off); + reply.xdr_raw(result); + reply.xdr_offset(result_off); + break; + + case SVC_PRIVACY: + result_len = reply.xdr_int(); + if (result_len == 0) + return 0; + + try { + result = gssCtx.unwrap(reply.xdr_buf(), reply.xdr_offset(), + result_len, mInfo); + } catch (GSSException e) { + throw new RpcException("unwrap: gss_unwrap failed"); + } + + if (mInfo.getQOP() != qop) { + throw new RpcException("unwrap: unexpected qop"); + } + + reply.xdr_offset(result_off); + reply.xdr_raw(result); + reply.xdr_offset(result_off); + seq_num_in = reply.xdr_int(); + if ((seq_num_in < (seq_num_out - seq_window)) || + (seq_num_in > seq_num_out)) { + throw new RpcException("unwrap: bad sequence number"); + } + break; + } + + return seq_num_in; + } + + + /** + * Validate RPC response verifier from server. The response verifier + * is the checksum of the request sequence number. + * + * @param snumber the sequence number + * @param token the verifier + */ + synchronized void validate(byte[] token, int snumber) + throws RpcException { + + if (control != RPCSEC_GSS_DATA) + return; + + MessageProp mInfo = new MessageProp(); + + // create a buffer for the sequence number in the net order + byte[] msg = new byte[4]; + msg[0] = (byte)(snumber >>> 24); + msg[1] = (byte)(snumber >> 16); + msg[2] = (byte)(snumber >> 8); + msg[3] = (byte)snumber; + + try { + gssCtx.verifyMIC(token, 0, token.length, + msg, 0, msg.length, mInfo); + } catch (GSSException e) { + throw new RpcException("CredGss: validate failed"); + } + } + + /** + * Delete the RPC credential data and destroy its security + * context with the server. + * + * @param rpc delete the security context of this Rpc object + */ + synchronized void destroy(Rpc rpc) + throws RpcException { + + if (gssCtx != null) { + try { + Xdr secCall = new Xdr(RPCGSS_MAXSZ); + control = CredGss.RPCSEC_GSS_DESTROY; + rpc.rpc_header(secCall, PROC_NULL); + rpc.rpc_call(secCall, 30 * 1000, 5); + gssCtx.dispose(); + mechOid = null; + gssCtx = null; + ctx_handle = null; + } catch (IOException e) { + } catch (GSSException e) { + /* + * If the request to destroy the context fails for some + * reason, the client need not take any special action. + * The server must be prepared to deal with situations + * where clients never inform the server to maintain + * a context. + */ + return; + } + } + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/CredNone.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/CredNone.java new file mode 100644 index 0000000000..8221fa3a91 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/CredNone.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +import java.io.*; + +/** + * This is the "NONE" credential, i.e. no credential + * It's the default credential for RPC unless set + * to something else. + */ + +public class CredNone extends Cred { + + static final int AUTH_NONE = 0; + + /** + * Put "no" creds into an XDR buffer + */ + void putCred(Xdr x) { + + x.xdr_int(AUTH_NONE); + x.xdr_int(0); // no cred data + x.xdr_int(0); // no verifier + x.xdr_int(0); // no verifier + } + + /** + * Get "no" creds from an XDR buffer + */ + void getCred(Xdr x) { + + x.xdr_int(); // assume it's AUTH_NONE + x.xdr_int(); // cred length == 0 + x.xdr_int(); // no verifier + x.xdr_int(); // no verifier + } + + void init(Connection conn, int prog, int vers) { + // No-op + } + + + boolean refresh(Connection conn, int prog, int vers) { + // No-op + return true; + } + + void wrap(Xdr x, byte[] arg) { + // No-op + } + + int unwrap(Xdr x) { + // No-op + return 0; + } + + void validate(byte[] verifier, int verifiee) { + // No-op + } + + void destroy(Rpc rpc) { + // No-op + } + +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/CredUnix.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/CredUnix.java new file mode 100644 index 0000000000..9c1bd5e5f8 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/CredUnix.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +import java.io.*; + +/** + * The Unix credential. Contains information specific + * to Unix users and NFS: uid/gid/grplist + */ + +public class CredUnix extends Cred { + + /* + * These are the data normally + * found in a Unix credential. + */ + private int uid; + private int gid; + private int[] gids; + + /* + * These are additional info provided by + * version 2 of PCNFSD. + */ + private String home; + private int def_umask; + public int status; + + /* + * Default credential values + */ + static final int AUTH_UNIX = 1; + static final int UID_NOBODY = 60001; + static final int GID_NOBODY = 60001; + + /* + * Constants for PCNFSD protocol + */ + private static final int PCNFSDPROG = 150001; + private static final int PCNFSD_AUTH = 1; + private static final int PCNFSD2_AUTH = 13; + private static final int MAXREPLY = 512; + + static final int AUTH_RES_OK = 0; + static final int AUTH_RES_FAKE = 1; + static final int AUTH_RES_FAIL = 2; + + private Xdr cr = new Xdr(64); + + /** + * Constructor creates an instance of + * Unix credential with given uid/gid + */ + public CredUnix(int uid, int gid) { + this.uid = uid; + this.gid = gid;; + } + + /** + * Constructor creates an instance of + * Unix credential and sets default uid/gid + * to "nobody". + */ + public CredUnix() { + this(UID_NOBODY, GID_NOBODY); + } + + /** + * Put Unix creds into an XDR buffer + * + * @param xdr buffer + */ + synchronized void putCred(Xdr x) { + + x.xdr_int(AUTH_UNIX); + + cr.xdr_offset(0); + cr.xdr_int((int) (System.currentTimeMillis()/1000)); + cr.xdr_string("javaclient"); + cr.xdr_int(uid); + cr.xdr_int(gid); + if (gids == null) + cr.xdr_int(0); + else { + cr.xdr_int(gids.length); + for (int i = 0; i < gids.length; i++) + cr.xdr_int(gids[i]); + } + + x.xdr_bytes(cr); + + x.xdr_int(0); // no verifier + x.xdr_int(0); // no verifier + } + + /** + * Get Unix creds from an XDR buffer + * + * @param xdr buffer + */ + void getCred(Xdr x) { + + x.xdr_int(); // assume it's AUTH_UNIX + x.xdr_int(); // cred length + x.xdr_int(); // timestamp + x.xdr_string(); // hostname + uid = x.xdr_int(); + gid = x.xdr_int(); + int count = x.xdr_int(); + if (count > 0) { + gids = new int[count]; + for (int i = 0; i < count; i++) + gids[i] = x.xdr_int(); + } + x.xdr_int(); // no verifier + x.xdr_int(); // no verifier + } + + /** + * Given a username and passwd, obtain Unix creds + * from the named server. This is not necessarily + * an NFS server. + * + * If we fail then the creds are unaffected. + * + * @param server Name of the pcnfsd server that will return the creds. + * @param username the login name of the user. + * @param passwd of the user. + * + */ + public boolean fetchCred(String server, String username, String passwd) { + + username = disguise(username); + passwd = disguise(passwd); + + try { + try { + return (callV2(server, username, passwd)); + } catch (MsgAcceptedException e) { + if (e.error != e.PROG_MISMATCH) + return false; + + return (callV1(server, username, passwd)); + } + } catch (IOException e) { + return false; + } + } + + /** + * Set the cred back to the default: nobody/nobody + */ + public void setCred() { + uid = UID_NOBODY; + gid = GID_NOBODY; + gids = null; + } + + /** + * Set the uid, gid + */ + public void setCred(int uid, int gid, int[] gids) { + this.uid = uid; + this.gid = gid; + this.gids = gids; + } + + /* + * Disguise the string so that it's not + * obvious to a casual snooper. + */ + private String disguise(String s) { + byte[] b = s.getBytes(); + + for (int i = 0; i < b.length; i++) + b[i] = (byte)((b[i] & 0x7f) ^ 0x5b); + + return (new String(b)); + } + + /** + * Get the Unix user id for the user + * @return uid + */ + public int getUid() { + return uid; + } + + /** + * Get the Unix group id for the user + * @return gid + */ + public int getGid() { + return gid; + } + + /** + * Get the Unix group list for the user + * @return gids + */ + public int[] getGids() { + return gids; + } + + /** + * Get the user's home directory path + * @return pathname of home directory. + */ + public String getHome() { + return home; + } + + /** + * Get the user's home Unix umask + * @return umask + */ + public int getUmask() { + return def_umask; + } + + private boolean callV1(String server, String username, String passwd) + throws java.net.UnknownHostException, IOException { + + Rpc pc = new Rpc(server, 0, PCNFSDPROG, 1, "udp", MAXREPLY); + Xdr call = new Xdr(MAXREPLY); + pc.rpc_header(call, PCNFSD_AUTH); + + call.xdr_string(username); + call.xdr_string(passwd); + + Xdr reply = pc.rpc_call(call, 10 * 1000, 2); + + status = reply.xdr_int(); + if (status == AUTH_RES_FAIL) + return false; + + uid = reply.xdr_int(); + gid = reply.xdr_int(); + gids = null; + home = null; + def_umask = 0; + + return true; + } + + private boolean callV2(String server, String username, String passwd) + throws java.net.UnknownHostException, IOException { + + Rpc pc = new Rpc(server, 0, PCNFSDPROG, 2, "udp", MAXREPLY); + Xdr call = new Xdr(MAXREPLY); + pc.rpc_header(call, PCNFSD2_AUTH); + + call.xdr_string("(anyhost)"); // XXX should be hostname + call.xdr_string(username); + call.xdr_string(passwd); + call.xdr_string("Java client"); // comment + + Xdr reply = pc.rpc_call(call, 10 * 1000, 2); + + status = reply.xdr_int(); + if (status == AUTH_RES_FAIL) + return false; + + uid = reply.xdr_int(); + gid = reply.xdr_int(); + gids = new int[reply.xdr_int()]; + for (int i = 0; i < gids.length; i++) + gids[i] = reply.xdr_int(); + home = reply.xdr_string(); + def_umask = reply.xdr_int(); + + return true; + } + + public String toString() { + String s = "AUTH_UNIX:\n uid=" + uid + ",gid=" + gid + "\n"; + if (gids != null) { + s += " gids="; + for (int i = 0; i < gids.length; i++) + s += gids[i] + " "; + } + if (home != null) + s += "\n home=" + home; + if (def_umask != 0) + s += "\n umask=0" + Long.toOctalString(def_umask); + + return s; + } + + public void init(Connection conn, int prog, int vers) { + // No-op + } + + public boolean refresh(Connection conn, int prog, int vers) { + // No-op + return true; + } + + public void wrap(Xdr x, byte[] arg) { + // No-op + } + + public int unwrap(Xdr x) { + // No-op + return 0; + } + + public void validate(byte[] verifier, int verifiee) { + // No-op + } + + public void destroy(Rpc rpc) { + // No-op + } + +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/MsgAcceptedException.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/MsgAcceptedException.java new file mode 100644 index 0000000000..b98a4fb0ce --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/MsgAcceptedException.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1997, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +/** + * + * Handle the RPC "message accepted" class of errors. + * + * Note that some of the errors also convey low and high + * version information. + * + * @see RpcException + * @author Brent Callaghan + */ +public class MsgAcceptedException extends RpcException { + int lo, hi; + + public static final int PROG_UNAVAIL = 1; + public static final int PROG_MISMATCH = 2; + public static final int PROC_UNAVAIL = 3; + public static final int GARBAGE_ARGS = 4; + public static final int SYSTEM_ERR = 5; + + /* + * Construct a new Exception for the specified RPC accepted error + * @param error The RPC error number + */ + public MsgAcceptedException(int error) { + super(error); + } + + /* + * Construct a new RPC error with the given low and high parameters + * @param error The RPC error number + * @param lo The low version number + * @param hi The high version number + */ + public MsgAcceptedException(int error, int lo, int hi) { + super(error); + this.lo = lo; + this.hi = hi; + } + + public String toString() { + switch (error) { + + case PROG_UNAVAIL: + return "Program unavailable"; + + case PROG_MISMATCH: + return "Program number mismatch: " + + "low=" + lo + ",high=" + hi; + + case PROC_UNAVAIL: + return "Procedure Unavailable: " + + "low=" + lo + ",high=" + hi; + + case GARBAGE_ARGS: + return "Garbage Arguments"; + + case SYSTEM_ERR: + return "System error"; + + default: + return "Unknown RPC Error = " + error; + } + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/MsgRejectedException.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/MsgRejectedException.java new file mode 100644 index 0000000000..366230db5c --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/MsgRejectedException.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +/** + * + * Handle the RPC "message rejected" class of errors. + * + * Note that some of the errors also convey low and high + * version information or an authentication sub-error. + * + * @see RpcException + * @author Brent Callaghan + */ +public class MsgRejectedException extends RpcException { + + public static final int RPC_MISMATCH = 0; + public static final int AUTH_ERROR = 1; + + public static final int AUTH_BADCRED = 1; + public static final int AUTH_REJECTEDCRED = 2; + public static final int AUTH_BADVERF = 3; + public static final int AUTH_REJECTEDVERF = 4; + public static final int AUTH_TOOWEAK = 5; + public static final int AUTH_INVALIDRESP = 6; + public static final int AUTH_FAILED = 7; + + public static final int RPCSEC_GSS_NOCRED = 13; + public static final int RPCSEC_GSS_FAILED = 14; + + /* + * Construct a new Exception for the specified RPC accepted error + * @param error The RPC error number + */ + public MsgRejectedException(int error) { + super(error); + } + + /* + * Construct a new RPC error with the given auth sub-error + * @param error The RPC error number + * @param why The auth sub-error + */ + public MsgRejectedException(int error, int why) { + super(error); + this.why = why; + } + + /* + * Construct a new RPC error with the given low and high parameters + * @param error The RPC error number + * @param lo The low version number + * @param hi The high version number + */ + public MsgRejectedException(int error, int lo, int hi) { + super(error); + this.lo = lo; + this.hi = hi; + } + + public String toString() { + switch (error) { + + case RPC_MISMATCH: + return "Version mismatch: " + + "low=" + lo + ",high=" + hi; + + case AUTH_ERROR: + String msg = "Authentication error: "; + switch (why) { + case AUTH_BADCRED: + msg += "bogus credentials (seal broken)"; + break; + case AUTH_REJECTEDCRED: + msg += "client should begin new session"; + break; + case AUTH_BADVERF: + msg += "bogus verifier (seal broken)"; + break; + case AUTH_REJECTEDVERF: + msg += "verifier expired or was replayed"; + break; + case AUTH_TOOWEAK: + msg += "too weak"; + break; + case AUTH_INVALIDRESP: + msg += "bogus response verifier"; + break; + case RPCSEC_GSS_NOCRED: + msg += "no credentials for user"; + break; + case RPCSEC_GSS_FAILED: + msg += "GSS failure, credentials deleted"; + break; + case AUTH_FAILED: + default: + msg += "unknown reason"; + break; + } + return msg; + + default: + return "Unknown RPC Error = " + error; + } + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Rpc.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Rpc.java new file mode 100644 index 0000000000..47f233c942 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Rpc.java @@ -0,0 +1,520 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +import java.io.*; +import java.net.InetAddress; + +/** + * + * This class transmits and receives RPC calls to an RPC service + * at a specific host and port. + * + * @see Connection + * @see RpcException + * @see MsgAcceptedException + * @see MsgDeniedException + * @author Brent Callaghan + */ +public class Rpc { + public Connection conn; + int prog; + int vers; + Cred cred; + RpcHandler rhandler = new RpcHandler(); + + private static int xid = (int) System.currentTimeMillis() & 0x0fffffff; + + private static final int PMAP_PROG = 100000; + private static final int PMAP_PORT = 111; + private static final int PMAP_VERS = 2; + private static final int PMAP_GETPORT = 3; + private static final int PMAP_MAXSZ = 128; + + private static final int MAX_TIMEOUT = 30 * 1000; // 30 sec + private static final int MAX_REPLY = 8192 + 256; + + /** + * Construct a new Rpc object - equivalent to a "client handle" + * using an AUTH_NONE cred handle. + * + * @param conn A connection to the server + * @param prog The program number of the service + * @param vers The version number of the service + */ + public Rpc(Connection conn, int prog, int vers) { + this.conn = conn; + this.prog = prog; + this.vers = vers; + cred = new CredNone(); + } + + /** + * Construct a new Rpc object - equivalent to a "client handle" + * using a given cred handle "cr" + * + * @param conn A connection to the server + * @param prog The program number of the service + * @param vers The version number of the service + * @param cr The cred to be used: CredUnix or CredGss + */ + public Rpc(Connection conn, int prog, int vers, Cred cr) { + this.conn = conn; + this.prog = prog; + this.vers = vers; + cred = cr; + } + + /** + * Construct a new Rpc object - equivalent to a "client handle" + * + * @param server The hostname of the server + * @param port The port number for the service + * @param prog The program number of the service + * @param vers The version number of the service + * @param proto The protocol to be used: "tcp" or "udp" + * @param maxReply The maximum size of the RPC reply + * @exception IOException if an I/O error occurs + */ + public Rpc(String server, int port, int prog, int vers, + String proto, int maxReply) + throws IOException { + this.conn = getConnection(server, port, prog, vers, + proto, maxReply); + this.prog = prog; + this.vers = vers; + cred = new CredNone(); + } + + + private Connection getConnection(String server, int port, int prog, + int vers, String proto, int maxReply) + throws IOException { + + if (port == 0) { + Rpc pmap = new Rpc(server, PMAP_PORT, PMAP_PROG, PMAP_VERS, + "udp", PMAP_MAXSZ); + Xdr call = new Xdr(PMAP_MAXSZ); + + pmap.rpc_header(call, PMAP_GETPORT); + + call.xdr_int(prog); + call.xdr_int(vers); + call.xdr_int(proto.equals("tcp") ? 6 : 17); + call.xdr_int(0); // no port + + Xdr reply = pmap.rpc_call(call, 5 * 1000, 3); + + port = reply.xdr_int(); + if (port == 0) + throw new MsgAcceptedException(PROG_UNAVAIL); + } + + /* + * Check the connection cache first to see + * if there's a connection already set up + * for this port, server and protocol. This is + * particularly important for TCP with its + * high connection overhead. + * + * The code is synchronized to prevent concurrent + * threads from missing the cache and setting + * up multiple connections. + */ + synchronized (Connection.connections) { + conn = Connection.getCache(server, port, proto); + + if (conn == null) { + if (proto.equals("tcp")) + conn = new ConnectSocket(server, port, maxReply); + else + conn = new ConnectDatagram(server, port, maxReply); + + Connection.putCache(conn); + } + } + + return conn; + } + + /** + * Set the RPC credential + * + * @param c - cred to be used + */ + public void setCred(Cred c) throws RpcException { + + cred = c; + cred.init(conn, prog, vers); + } + + /** + * Delete the RPC credential data and destroy its security + * context with the server. + */ + public void delCred() throws RpcException { + + cred.destroy(this); + } + + /** + * Return the RPC credential + * + * @return The credential + */ + public Cred getCred() { + return cred; + } + + /** + * + */ + public void setRpcHandler(RpcHandler r) { + rhandler = r == null ? new RpcHandler() : r; + } + + /** + * Construct an RPC header in the XDR buffer + * + * @param call The XDR buffer for the header + * @param proc The service procedure to be called + */ + public void rpc_header(Xdr call, int proc) throws RpcException { + + call.xid = next_xid(); + + /* + * Initialize XDR buffer + * If using TCP then reserve space for record mark + */ + call.xdr_offset(conn instanceof ConnectSocket ? 4 : 0); + + call.xdr_int(call.xid); + call.xdr_int(0); // direction=CALL + call.xdr_int(2); // RPC version + call.xdr_int(prog); + call.xdr_int(vers); + call.xdr_int(proc); + cred.putCred(call); + } + + /* + * A rare static method! We need to + * make sure that the xid is unique + * for all instances of an RPC connection + * on this client. + */ + static synchronized int next_xid() { + return xid++; + } + + /* + * Message type + */ + static final int CALL = 0; + static final int REPLY = 1; + + /* + * Reply Status + */ + static final int MSG_ACCEPTED = 0; + static final int MSG_DENIED = 1; + + /* + * Accept Status + */ + static final int SUCCESS = 0; + static final int PROG_UNAVAIL = 1; + static final int PROG_MISMATCH = 2; + static final int PROC_UNAVAIL = 3; + static final int GARBAGE_ARGS = 4; + static final int SYSTEM_ERR = 5; + + /* + * Reject Status + */ + static final int RPC_MISMATCH = 0; + static final int AUTH_ERROR = 1; + + /* + * Re-construct the call xdr buffer when retranmitting an + * RPCSEC_GSS request. + * (i.e. for a retransmitted RPCSEC_GSS requests, it uses a + * different sequence number and it needs to use its un-encrypted + * argument to do wrap() again. + */ + private Xdr call_reconstruct(Xdr call, byte[] arg) + throws IOException, RpcException { + + Xdr recall = new Xdr(call.xdr_size()); + recall.xid = call.xid; + + // the rpc_header + recall.xdr_raw(call.xdr_raw(0, + conn instanceof ConnectSocket ? 28 : 24)); + cred.putCred(recall); + + // the not-yet-encrypted rpc argument + if (arg != null) { + if (recall.xdr_offset() == recall.xdr_wrap_offset()) { + recall.xdr_raw(arg); + } else { + recall.xdr_raw(arg, 4, arg.length - 4); + } + } + + return recall; + } + + /** + * Transmit the XDR call buffer containing an RPC header + * followed by a protocol header and receive the + * reply. + * + * @param call XDR buffer containing RPC call to transmit + * @param arg (seq_num + RPC argument) if wrap + * @param timeout after this number of milliseconds + * @return Xdr the XDR buffer for the reply + * @throws RpcException + */ + public Xdr rpc_call_one(Xdr call, byte[] arg, int timeout) + throws IOException, RpcException { + + int status, astat, rstat; + int why; + byte[] verifier; + + // encrypt the rpc argument if it's needed + if (arg != null) + cred.wrap(call, arg); + + Xdr reply = conn.send(call, timeout); + + // XID already xdr'ed by the connection listener + + if (reply.xdr_int() != REPLY) // direction + throw new RpcException("Unknown RPC header"); + + status = reply.xdr_int(); + switch (status) { + case MSG_ACCEPTED: + reply.xdr_skip(4); // verifier flavor + verifier = reply.xdr_bytes(); // get the verifier + astat = reply.xdr_int(); + + switch (astat) { + case SUCCESS: + int seq_num_in = cred.unwrap(reply); + + // decrypt the result if it's needed + if (seq_num_in > 0) { + cred.validate(verifier, seq_num_in); + } + break; + + case PROG_UNAVAIL: + case PROG_MISMATCH: + case PROC_UNAVAIL: + throw new MsgAcceptedException(astat, + reply.xdr_int(), reply.xdr_int()); + + case GARBAGE_ARGS: + case SYSTEM_ERR: + default: + throw new MsgAcceptedException(astat); + } + break; + + case MSG_DENIED: + rstat = reply.xdr_int(); + switch (rstat) { + case RPC_MISMATCH: + throw new MsgRejectedException(rstat, + reply.xdr_int(), reply.xdr_int()); + case AUTH_ERROR: + why = reply.xdr_int(); + throw new MsgRejectedException(rstat, why); + + default: + throw new MsgRejectedException(rstat); + } + } + + return reply; + } + + /** + * Make an RPC call but retry if necessary + * + * Retries use exponential backoff up to MAX_TIMEOUT ms. + * + * Note that we handle TCP connections differently: there is + * no timeout, and retransmission is used only when reconnecting. + * + * @param call XDR buffer containing RPC call to transmit + * @param timeout for the initial call + * @param retries the number of times to retry the call. + * A value of zero implies forever. + * @return Xdr the XDR buffer for the reply + * @throws IOException + */ + public Xdr rpc_call(Xdr call, int timeout, int retries) + throws IOException { + + boolean timedout = false; + Xdr reply = null; + long startTime = System.currentTimeMillis(); + + if (retries == 0) + retries = Integer.MAX_VALUE; // retry forever + + /* + * If it's a TCP connection, do retries only + * to re-establish connection. + */ + if (conn instanceof ConnectSocket) + timeout = MAX_TIMEOUT; + + // refresh twice if needed + int num_refresh = 2; + for (int c = 0; c < retries; c++) { + + byte[] arg = null; + + /* + * Currently, only CredNone, CredUnix, CredGss is supported. + * For CredGss: save the (seq_num + rpc argument) before + * it's encrypted. This arg will be needed during retransmit. + * + * CredGss not checked to avoid loading un-used CredGss class. + */ + if (!(cred instanceof CredUnix) && !(cred instanceof CredNone) && + (call.xdr_offset() > call.xdr_wrap_offset())) { + arg = call.xdr_raw(call.xdr_wrap_offset(), + call.xdr_offset() - call.xdr_wrap_offset()); + } + + try { + + reply = rpc_call_one(call, arg, timeout); + break; // reply received OK + + } catch (MsgRejectedException e) { + + /* + * Refresh the cred and try again + */ + if (num_refresh > 0 && + (e.why == MsgRejectedException.RPCSEC_GSS_NOCRED || + e.why == MsgRejectedException.RPCSEC_GSS_FAILED) && + cred.refresh(conn, prog, vers)) { + + // re-construct the "call" Xdr buffer. + call = call_reconstruct(call, arg); + num_refresh--; + c--; // to do refresh + + } else { + throw e; + } + + } catch (RpcException e) { + + /* + * An error that cannot be recovered by + * retrying - just give up. + */ + throw e; + + } catch (IOException e) { + + /* + * If it's a timeout then tell the RPC handler. + * It may request an abort by returning true. + */ + if (rhandler.timeout(conn.server, c, + (int) (System.currentTimeMillis() - startTime))) + throw new InterruptedIOException(); + + /* + * Probably a timeout. + * Double the timeout and retry + */ + timedout = true; + timeout *= 2; // double the timeout + if (timeout > MAX_TIMEOUT) + timeout = MAX_TIMEOUT; + + /* + * For CredGss: reconstruct the clear-text-argument + * and use a new sequence number. + * Currently, only CredNone, CredUnix, CredGss is supported. + * + * CredGss not checked to avoid loading un-used CredGss class. + */ + if (!(cred instanceof CredUnix) && + !(cred instanceof CredNone)) { + call = call_reconstruct(call, arg); + } + } + } + + if (reply == null) // reached retry limit + throw new InterruptedIOException(); + + /* + * If recovered after a timeout then tell + * the RPC Handler so it can display a + * "server OK" message. + */ + if (timedout && reply != null) + rhandler.ok(conn.server); + + return reply; + } + + /** + * Since this returns the address of the server it may + * seem redundant - but if you receive a reply to a + * broadcast RPC you need to know who is replying. + * @return address of the Peer + */ + public InetAddress getPeer() { + return conn.getPeer(); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/RpcException.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/RpcException.java new file mode 100644 index 0000000000..2de45b997c --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/RpcException.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +/** + * + * Handle the RPC exceptions. Most of the work is done + * by the two subclasses that handle the Accepted and Denied + * classes of RPC errors. + * + * @see MsgDeniedException + * @see MsgAcceptedConnection + * @author Brent Callaghan + */ +public class RpcException extends java.io.IOException { + + public int error; + public int why; + public int lo, hi; + + /* + * Construct a new RPC exception with the given error + * @param string The error message + */ + public RpcException(String msg) { + super("RPC error: " + msg); + } + + /* + * Construct a new RPC exception with the given error + * @param error The RPC error + */ + public RpcException(int error) { + super("RPC error: " + error); + this.error = error; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/RpcHandler.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/RpcHandler.java new file mode 100644 index 0000000000..ca9a628021 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/RpcHandler.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +import java.io.*; + +/** + * This handler is implemented by the RPC application + * if it wishes to be notifed of retransmissions. + * A good example is an NFS client that displays + * "NFS Server not responding" and "NFS server OK" + */ + +public class RpcHandler { + + /** + * Called when the RPC times out. + * + * @param server The name of the server + * @param retries Number of retries (initially 0) + * @param waittime Total time waiting for response + * @return bool True to abort, false to continue retrying + */ + public boolean timeout(String server, int retries, int waittime) { + return false; + } + + /** + * Called when the server responds after a timeout + * + * @param server The name of the server + */ + public void ok(String server) { + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Xdr.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Xdr.java new file mode 100644 index 0000000000..05e4ef5bc8 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/Xdr.java @@ -0,0 +1,441 @@ +/* + * Copyright (c) 1997-1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.rpc; + +import java.io.*; + +/** + * This class handles the marshalling/unmarshalling of + * primitive data types into and out of a buffer. + * + * The XDR buffer is a field within this class and its + * size is determined when the class is instantiated. + * Other than this buffer, there are just two pointers: + * "off" is the current XDR offset into the buffer and + * moves up the buffer by an integral number of XDRUNITs + * as data are encoded/decoded. The other pointer is + * "size" which is the number of valid data bytes in + * the buffer and is set only for received buffers. + * + * XXX we should perhaps check that off <= size + * whenever an item is decoded so that we can raise + * an exception if the received data is underlength. + * + * @see Rpc + * @author Brent Callaghan + */ +public class Xdr { + private static int XDRUNIT = 4; + private byte[] buf; + private int size, off, wrap_offset; + int xid; + + /** + * Build a new Xdr object with a buffer of given size + * + * @param size of the buffer in bytes + */ + public Xdr(int size) { + this.buf = new byte[size]; + this.size = size; + this.off = 0; + } + + /** + * Skip a number of bytes. + *
Note that the count is + * rounded up to the next XDRUNIT. + * + * @param count of the buffer in bytes + */ + public void xdr_skip(int count) { + int r = (off += count) % XDRUNIT; + + if (r > 0) + off += XDRUNIT - r; + } + + /** + * Return the entire Xdr buffer + * + * @return Xdr buffer + */ + public byte[] xdr_buf() { + return buf; + } + + /** + * Return the current offset + * + * @return offset + */ + public int xdr_offset() { + return off; + } + + /** + * Set the current offset + * + * @param off offset into XDR buffer + */ + public void xdr_offset(int off) { + this.off = off; + } + + /** + * Return the starting point of the bytes that will + * be encrypted. + * + * @return offset for bytes to be encrypted + */ + public int xdr_wrap_offset() { + return wrap_offset; + } + + /** + * Set the starting point of the bytes that will + * be encrypted. + * + * @return offset for bytes to be encrypted + */ + public void xdr_wrap_offset(int off) { + wrap_offset = off; + } + + /** + * Return the current size of the XDR buffer + * + * @return size + */ + public int xdr_size() { + return size; + } + + /** + * Set the current size of the XDR buffer + * + * @param size of buffer + */ + public void xdr_size(int size) { + this.size = size; + } + + /** + * Get an integer from the buffer + * + * @return integer + */ + public int xdr_int() { + return ((buf[off++] & 0xff) << 24 | + (buf[off++] & 0xff) << 16 | + (buf[off++] & 0xff) << 8 | + (buf[off++] & 0xff)); + } + + /** + * Put an integer into the buffer + * + * @param i Integer to store in XDR buffer. + */ + public void xdr_int(int i) { + buf[off++] = (byte)(i >>> 24); + buf[off++] = (byte)(i >> 16); + buf[off++] = (byte)(i >> 8); + buf[off++] = (byte)i; + } + + /** + * Get an unsigned integer from the buffer + * + *
Note that Java has no unsigned integer + * type so we must return it as a long. + * + * @return long + */ + public long xdr_u_int() { + return ((buf[off++] & 0xff) << 24 | + (buf[off++] & 0xff) << 16 | + (buf[off++] & 0xff) << 8 | + (buf[off++] & 0xff)); + } + + /** + * Put an unsigned integer into the buffer + * + * Note that Java has no unsigned integer + * type so we must submit it as a long. + * + * @param i unsigned integer to store in XDR buffer. + */ + public void xdr_u_int(long i) { + buf[off++] = (byte)(i >>> 24 & 0xff); + buf[off++] = (byte)(i >> 16); + buf[off++] = (byte)(i >> 8); + buf[off++] = (byte)i; + } + + /** + * Get a long from the buffer + * + * @return long + */ + public long xdr_hyper() { + return ((long)(buf[off++] & 0xff) << 56 | + (long)(buf[off++] & 0xff) << 48 | + (long)(buf[off++] & 0xff) << 40 | + (long)(buf[off++] & 0xff) << 32 | + (long)(buf[off++] & 0xff) << 24 | + (long)(buf[off++] & 0xff) << 16 | + (long)(buf[off++] & 0xff) << 8 | + (long)(buf[off++] & 0xff)); + } + + /** + * Put a long into the buffer + * + * @param i long to store in XDR buffer + */ + public void xdr_hyper(long i) { + buf[off++] = (byte)(i >>> 56) ; + buf[off++] = (byte)((i >> 48) & 0xff); + buf[off++] = (byte)((i >> 40) & 0xff); + buf[off++] = (byte)((i >> 32) & 0xff); + buf[off++] = (byte)((i >> 24) & 0xff); + buf[off++] = (byte)((i >> 16) & 0xff); + buf[off++] = (byte)((i >> 8) & 0xff); + buf[off++] = (byte)(i & 0xff); + } + + /* + * Note: we have no XDR routines for encoding/decoding + * unsigned longs. They exist in XDR but not in Java + * hence we can't represent them. + * Best just to use xdr_hyper() and hope the sign bit + * isn't used. + */ + + /** + * Get a boolean from the buffer + * + * @return boolean + */ + public boolean xdr_bool() { + return (xdr_int() != 0); + } + + /** + * Put a boolean into the buffer + * + * @param b boolean + */ + public void xdr_bool(boolean b) { + xdr_int(b ? 1 : 0); + } + + /** + * Get a floating point number from the buffer + * + * @return float + */ + public float xdr_float() { + return (Float.intBitsToFloat(xdr_int())); + } + + /** + * Put a floating point number into the buffer + * + * @param f float + */ + public void xdr_float(float f) { + xdr_int(Float.floatToIntBits(f)); + } + + /** + * Get a string from the buffer + * + * @return string + */ + public String xdr_string() { + int len = xdr_int(); + + String s = new String(buf, off, len); + xdr_skip(len); + return s; + } + + /** + * Put a string into the buffer + * + * @param s string + */ + public void xdr_string(String s) { + xdr_bytes(s.getBytes()); + } + + /** + * Get a counted array of bytes from the buffer + * + * @return bytes + */ + public byte[] xdr_bytes() { + return (xdr_raw(xdr_int())); + } + + /** + * Put a counted array of bytes into the buffer. + * Note that the entire byte array is encoded. + * + * @param b byte array + */ + public void xdr_bytes(byte[] b) { + xdr_bytes(b, 0, b.length); + } + + /** + * Put a counted array of bytes into the buffer + * + * @param b byte array + * @param len number of bytes to encode + */ + public void xdr_bytes(byte[] b, int len) { + xdr_bytes(b, 0, len); + } + + /** + * Put a counted array of bytes into the buffer + * + * @param b byte array + * @param boff offset into byte array + * @param len number of bytes to encode + */ + public void xdr_bytes(byte[] b, int boff, int len) { + xdr_int(len); + System.arraycopy(b, boff, buf, off, len); + xdr_skip(len); + } + + /** + * Put an Xdr buffer into the buffer + * + *
This is used to encode the RPC credentials + * + * @param x XDR buffer + */ + public void xdr_bytes(Xdr x) { + xdr_bytes(x.xdr_buf(), x.xdr_offset()); + } + + /** + * Get a fixed number of bytes from the buffer + * + * e.g. an NFS v2 filehandle + * + * @param len Number of bytes to get + * @return byte array + */ + public byte[] xdr_raw(int len) { + if (len == 0) + return null; + + byte[] b = new byte[len]; + + System.arraycopy(buf, off, b, 0, len); + xdr_skip(len); + return b; + } + + /** + * Get a fixed number (len) of bytes from the buffer + * at offset off. Do not change any buffer indicators. + * + * @param off Offset of bytes to get from + * @param len Number of bytes to copy + * @return byte array + */ + public byte[] xdr_raw(int off, int len) { + if (len == 0) + return null; + + byte[] b = new byte[len]; + + System.arraycopy(buf, off, b, 0, len); + return b; + } + + /** + * Put a fixed number of bytes into the buffer + * The length is not encoded. + * + * e.g. an NFS v2 filehandle + * + * @param b byte array + */ + public void xdr_raw(byte[] b) { + int len = b.length; + + System.arraycopy(b, 0, buf, off, len); + xdr_skip(len); + } + + /** + * Put a fixed number of bytes into the buffer + * at offset off. The length is not encoded. + * + * @param b byte array + * @param off where to put the byte array + */ + public void xdr_raw(byte[] b, int off) { + int len = b.length; + + System.arraycopy(b, 0, buf, off, len); + xdr_skip(len); + } + + /** + * Put a counted array of bytes into the buffer. + * The length is not encoded. + * + * @param b byte array + * @param boff offset into byte array + * @param len number of bytes to encode + */ + public void xdr_raw(byte[] b, int boff, int len) { + System.arraycopy(b, boff, buf, off, len); + xdr_skip(len); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/samples/README b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/samples/README new file mode 100644 index 0000000000..937afbf3eb --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/samples/README @@ -0,0 +1,88 @@ + +#pragma ident "@(#)README 1.3 98/11/12 SMI" + + +System +------ + Solaris + Install the dummy mechanism package on the server. + + +Server Setup +------------ + +Before running the client java test program, the C server program +has to be invoked first: + +/home/lling/test/rpcsec_gss/C/list_svc [-l] -n -m + +Check README in /home/lling/test/rpcsec_gss/C for server program usage. + + Example: % ./list_svc -n nfs -m 2& + + + +Client Setup +------------ + +o Set CLASSPATH as follows: + + client% setenv CLASSPATH /usr/java/lib/classes.zip:/home/lling/test/rpcsec_gss/java/classes.jar:. + + + +How to run +---------- + +client% cd /home/lling/test/rpcsec_gss/java + +client% java RPCGSSClient host service -m mech# + + -m 1 is for kerberos_v5 + -m 2 is for dummy + default is dummy + + Example: % java RPCGSSClient jaywing nfs -m 2 + + +How to test +----------- + +commands are: + set + get + del + service (integrity | privacy | none) + create-context + destroy-context + loop n + quit +enter cmd -> + + +*NOTE: context must be created before performing set/get/del commands + + create-context + to create a secure context + + service (integrity | privacy | none) + to change the service level + (Only works without -l option on server) + + set + to add an value to the server's list + e.g. enter cmd -> set foo 80 + + get + to fetch an value from the server's list: + e.g. enter cmd -> get foo + + del + to delete an value from the server's list + e.g. enter cmd -> del foo + + destroy-context + to destroy a secure context: + + loop n + Create/destroy context n times. diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/rpc/samples/RPCGSSClient.java b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/samples/RPCGSSClient.java new file mode 100644 index 0000000000..75228d4111 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/rpc/samples/RPCGSSClient.java @@ -0,0 +1,377 @@ +package com.sun.rpc.samples; +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +/* + * Sample rpcgss-client application. + * This program will inter-operate with the "C" rpcsec_gss server sample + * test program. + * + * This java client sample program is invoked as follows: + * + * % java RPCGSSClient host service -m + * + * The -m indicates the mechanism used. + * '-m 1' is for kerberos mechanism + * '-m 2' is for dummy mechanism + * The dummy is used as the default mechanism. + */ + +import java.io.*; +import com.sun.rpc.*; + +class RPCGSSClient { + + private static final int ADDRLISTPROG = 620756992; + private static final int ADDRLISTVERS = 1; + private static final int ADDR_SET = 1; + private static final int ADDR_GET = 2; + private static final int ADDR_DEL = 3; + private static final int SVC_SET = 4; + private static final int CREATE = 5; + private static final int DESTROY = 6; + private static final int LOOP = 8; + private static final int QUIT = 7; + + private static final String mech1 = "1.2.840.113554.1.2.2"; //krb5 + private static final String mech2 = "1.3.6.1.4.1.42.2.26.1.2"; //dummy + + private static String serverHost, serviceName, mech, svcString; + private static int op = 0, serviceType = CredGss.SVC_PRIVACY, loop_times; + private static String name = null, addr = null; + + + /** + * Main method for the RPCGSSClient sample application. + */ + public static void main(String args[]) { + + Rpc rpc = null; + CredGss cred = null; + Xdr callmsg = new Xdr(1024), replymsg; + boolean status; + + if ((args.length < 2) || (args.length > 4)) { + usage(); + exit(1); + } + + //set the required command line args + serverHost = args[0]; + serviceName = args[1]; + + // parse -m option; use dummy mech if -m is not specified + if (args.length > 2) { + if (args[2].equals("-m")) { + if (args[3].equals("1")) { + mech = mech1; + print("Kerberos mechanism " + mech); + } else if (args[3].equals("2")) { + mech = mech2; + print("Dummy mechanism " + mech); + } else { + usage(); + exit(1); + } + } else { + usage(); + exit(1); + } + } else { + mech = mech2; + print("Dummy mechanism " + mech); + } + + try { + rpc = new Rpc(serverHost, 0, ADDRLISTPROG, ADDRLISTVERS, + "tcp", 512); + } catch (IOException e) { + print("\n***RPC ERROR:\t" + e.toString()); + e.printStackTrace(); + exit(-1); + } + + while (true) { + try { + parseargs(); + + switch (op) { + case CREATE: + cred = new CredGss(serviceName, mech, + serviceType, 0); + rpc.setCred(cred); + break; + + case SVC_SET: + if (svcString.equals("none")) { + serviceType = CredGss.SVC_NONE; + } else if (svcString.equals("integrity")) { + serviceType = CredGss.SVC_INTEGRITY; + } else if (svcString.equals("privacy")) { + serviceType = CredGss.SVC_PRIVACY; + } + if (cred != null) { + cred.serviceType = serviceType; + } + break; + + case ADDR_SET: + rpc.rpc_header(callmsg, ADDR_SET); + callmsg.xdr_string(name); + callmsg.xdr_string(addr); + replymsg = rpc.rpc_call(callmsg, 3 * 1000, 3); + status = replymsg.xdr_bool(); + if (status) { + print("set ok \n"); + } else { + print("set failed\n"); + } + break; + + case ADDR_GET: + rpc.rpc_header(callmsg, ADDR_GET); + callmsg.xdr_string(name); + replymsg = rpc.rpc_call(callmsg, 3 * 1000, 3); + name = replymsg.xdr_string(); + addr = replymsg.xdr_string(); + if (addr.getBytes().length != 0) { + print(name + " = " + addr); + } else { + print("no value"); + } + break; + + case ADDR_DEL: + rpc.rpc_header(callmsg, ADDR_DEL); + callmsg.xdr_string(name); + replymsg = rpc.rpc_call(callmsg, 3 * 1000, 3); + status = replymsg.xdr_bool(); + if (status) { + print("delete ok"); + } else { + print("delete failed"); + } + break; + + case DESTROY: + if (cred != null) { + rpc.delCred(); + print("Context destroyed"); + cred = null; + } else { + print("No Context to be destroyed"); + } + break; + + case LOOP: + if (cred != null) { + rpc.delCred(); + cred = null; + } + int i = 0; + while (loop_times-- > 0) { + i++; + print("\n***LOOP " + i + "***"); + // create-context + cred = new CredGss(serviceName, mech, + serviceType, 0); + rpc.setCred(cred); + + // destroy-context + rpc.delCred(); + cred = null; + print("Context destroyed"); + } + break; + + case QUIT: + exit(0); + + } // switch + + } catch (IOException e) { + + print("\n**IO ERRORS**:\t" + e.toString()); + e.printStackTrace(); + } + } // while (true) + } // main() + + /** + * Parse command line input + */ + private static void parseargs() { + + InputStream in = System.in; + byte[] argbuf = new byte[128]; + String[] args = new String[4]; + int len, offset, n, i; + + usage1(); + System.out.print("enter cmd -> "); + + try { + len = in.read(argbuf); + offset = 0; n = 0; i = 0; + + while (i < (len - 1)) { + while (Character.isSpace((char) argbuf[i])) { + i++; + } + offset = i; + while ((char) argbuf[i] != '\n' && + (char) argbuf[i] != ' ') { + //!Character.isSpace((char) argbuf[i])) + i++; + } + args[n++] = new String(argbuf, 0, offset, i-offset); + } + args[n] = null; + + } catch (IOException e) { + print(e.toString()); + parseargs(); + } + + if (args[0] == null) + parseargs(); + + if (args[0].equals("set")) { + op = ADDR_SET; + name = args[1]; + addr = args[2]; + if (name == null || addr == null) { + print("syntax error"); + parseargs(); + } + + } else if (args[0].equals("get")) { + op = ADDR_GET; + name = args[1]; + if (name == null) { + print("syntax error"); + parseargs(); + } + + } else if (args[0].equals("del")) { + op = ADDR_DEL; + if (args[1] == null) { + print("syntax error"); + parseargs(); + } + name = args[1]; + + } else if (args[0].equals("service")) { + op = SVC_SET; + if (args[1] == null) { + print("syntax error"); + parseargs(); + } + svcString = args[1]; + + } else if (args[0].equals("create-context")) { + op = CREATE; + + } else if (args[0].equals("destroy-context")) { + op = DESTROY; + + } else if (args[0].equals("loop")) { + op = LOOP; + if (args[1] != null) { + loop_times = Integer.parseInt(args[1]); + } else { + loop_times = 5; + } + + } else if (args[0].equals("quit") || args[0].equals("exit")) { + op = QUIT; + + } else { + print("syntax error"); + parseargs(); + } + } + + + private static void usage1() { + print("\ncommands are:"); + print("\tset "); + print("\tget "); + print("\tdel "); + print("\tservice (integrity | privacy | none)"); + print("\tcreate-context"); + print("\tdestroy-context"); + print("\tloop n"); + print("\tquit"); + } + + /** + * Utility method to display application usage string. + */ + private static void usage() { + print("\nUsage: "); + print("\tjava RPCGSSClient serverHost serviceName -m mech#\n"); + print("\t-m 1 is for kerberos_v5"); + print("\t-m 2 is for dummy"); + print("\tdefault mech is dummy if -m is not specified\n"); + } + + + /** + * Utility method to display information to the screen. + */ + private static void print(String msg) { + + System.out.println(msg); + } + +/* + private static void print(int x) { + + System.out.println(x); + } +*/ + + /** + * Utility method to gracefully shut down the connection and + * terminate the application. + */ + private static void exit(int status) { + System.exit(status); + } + +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFile.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFile.java new file mode 100644 index 0000000000..2808b83fd5 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFile.java @@ -0,0 +1,987 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +import java.io.*; +import java.util.Vector; +import java.lang.reflect.Constructor; +import java.util.Hashtable; +import java.util.StringTokenizer; + +/** + * + * Instances of this class represent the name of a file or directory. + * Since only the name of the file is represented, the file itself + * need not exist. + *

+ * The XFile object is functionally equivalent to the java.io.File + * object with the ability to handle not only native pathnames + * but also URL-style pathnames. URL pathnames have some advantages + * over native pathnames: + *

+ *

    + *
  • The name is platform-independent.
    + * You can use the same name to reference a file + * independent of the pathname syntax supported + * by the underlying operating system. The + * component separator in a URL pathname is always + * a forward slash. + *

    + *

  • The name can be global in scope.
    + * For instance, a URL name can refer to a file + * anywhere on the Internet, e.g. + *

    + * nfs://santa.northpole.org/toys/catalog + *

    + *

  • The name can refer explicitly to an access scheme.
    + * For example: + *
      + *
    • file:///C|/java/bin (a local directory) + *
    • nfs://myserver/home/ed + * (directory on NFS server) + *
    • ftp://ftpsrv/pub/pkg.zip + * (file on FTP server) + *
    + * This property makes possible the dynamic loading + * of new filesystem accessors. + *

    + *

  • Consistent rules for composition of relative names.
    + * URLs support a well defined set of rules for the use + * of names relative to a "base" URL described in + * RFC 1808. + *
    For instance: + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    BaseRelativeComposition
    file:///a/b/cxfile:///a/b/c/x
    nfs://server/a/b/c/ynfs://server/y
    nfs://server/a/b/c../znfs://server/a/b/z
    file:///a/b/cd/.nfs://server/a/b/c/d
    file:///a/b/cnfs://srv/xnfs://srv/x
    + *
    + *

    + *

  • Will support Universal Resource Names.
    + * Although URLs are necessarily location dependent, + * location indepent Universal Resource Names (URN) + * names can be used within the same structure (see + * + * RFC 2141. + *

    + *

+ *

+ * + * Pathnames that are not represented as URL names will be + * assumed to represent "native" names and XFile will present + * the same semantics as the java.io.File class. + */ +public class XFile { + + /** + * File Accessor that implements the underlying filesystem + */ + private XFileAccessor xfa; + + /** + * The url of the file. + */ + private XFurl url; + private String urlStr; + private File nativeFile; + private boolean bound; + + /** + * Creates a XFile instance that represents the file + * whose pathname is the given url argument. + * + * If the the name argument contains the string "://" then it + * is assumed to be a URL name. The characters prior to the + * colon are assumed to be the filesystem scheme name, e.g. + * "file", "nfs", etc. The rest of the URL name is assumed + * to be structured according to the Common Internet Scheme + * syntax described in + * RFC 1738; + * an optional location part followed by a hierarchical set + * of slash separated directories. + *

+ * <scheme>://<location>/<path> + * + * @param name the file url + * @exception java.lang.NullPointerException if the file url + * is equal to null. + */ + public XFile(String name) { + + urlStr = name; + if (name == null) + throw new NullPointerException(); + + try { + url = new XFurl(name); + xfa = loadAccessor(url); + } catch (Exception e) { + if (name.startsWith(".:")) + name = name.substring(2); // lop off ".:" + + nativeFile = new File(name); + xfa = makeNative(nativeFile); + } + } + + + /** + * Creates a XFile instance that represents the file + * with the specified name in the specified directory. + * + * If the dir XFile is null, or if the + * name string is a full URL, then the single-arg + * constructor is used on the name. + *

+ * If the dir XFile represents a native file + * and the name string isAbsolute + * then the single-arg constructor is used on the name. + * If the name is not absolute then the resulting + * path is the simple concatenation of the dir + * path with the file separator and the name as + * for the two-arg constructor of the File class. + *

+ * If the dir XFile represents a URL name then + * the dir is assumed to be a base URL + * and the name string is evaluated as a + * relative URL according to the rules described in + * RFC 1808. + * + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
DirNameComposition
file:///a/b/cxfile:///a/b/c/x
nfs://server/a/b/c/ynfs://server/y
nfs://server/a/b/c../znfs://server/a/b/z
file:///a/b/cd/.nfs://server/a/b/c/d
file:///a/b/cnfs://srv/xnfs://srv/x
C:\Data\Programsmyprog.exeC:\Data\Programs\myprog.exe
+ *
+ * + * @param dir the directory. + * @param name absolute or relative file name or URL + */ + public XFile(XFile dir, String name) { + + if (name == null) + throw new NullPointerException(); + + try { + url = new XFurl(name); + xfa = loadAccessor(url); + } catch (Exception e) { + + /* + * If the name starts with ".:" then its + * a "native" URL - not relative. + */ + if (name.startsWith(".:")) { + name = name.substring(2); // lop off ".:" + dir = null; + } + + /* + * The name is not a URL + * If dir is not a URL then + * make a native file. + */ + if (dir == null) { + nativeFile = new File(name); + xfa = makeNative(nativeFile); + + /* + * Departure from strict java.io semantics here: + * If name is absolute then ignore the dir. + */ + } else if (dir.nativeFile != null) { + if (new File(name).isAbsolute()) + nativeFile = new File(name); + else + nativeFile = new File(dir.nativeFile, name); + xfa = makeNative(nativeFile); + + /* + * If the dir is a URL then evaluate + * name as a relative URL (see RFC 1808) + */ + } else { + try { + url = new XFurl(dir.getURL(), name); + xfa = loadAccessor(url); + } catch (Exception ee) { + System.out.println("Error: " + dir.getURL() + + " " + name); + } + } + } + urlStr = url.toString(); + } + + + /* + * Extract the protocol scheme from the url and + * load a class for an XFileAccessor or XFileExtensionAccessor + * + * The accessor is located by constructing a package + * name that contains the scheme string which is then + * located relative to the CLASSPATH. + * + * The package name is constructed from three components: + * + * . . + * + * The default package prefix is "com.sun" however this may + * changed by setting of the System property "java.protocol.xfile" + * to the value of one or more alternative prefixes delimited + * by vertical bars. The list is searched until the XFileAccessor + * is found. This method of locating accessors is similar to that + * of java.net.URL protocol handlers. The suffix is either + * "XFileAccessor" or "XFileExtensionAccessor". + * + * The hash table is used as a cache for previously loaded classes. + */ + private Class loadClass(String proto, String suffix, Hashtable ht) + throws ClassNotFoundException, IllegalAccessException { + + /* + * Check if there's a cached class for this protocol + */ + Class cl = (Class)ht.get(proto); + if (cl != null) + return cl; + + String prefixList = null; + + try { // applets will get a security exception here + prefixList = System.getProperty("java.protocol.xfile"); + } catch (SecurityException e) {}; + + if (prefixList == null) + prefixList = ""; + else + prefixList += "|"; + prefixList += "com.sun"; // always the default + + StringTokenizer pkgs = new StringTokenizer(prefixList, "|"); + + while (cl == null && pkgs.hasMoreTokens()) { + String prefix = pkgs.nextToken().trim(); + String clname = prefix + "." + proto + "." + suffix; + try { + cl = Class.forName(clname); + } catch (Exception e) {}; + } + + if (cl == null) + throw new ClassNotFoundException(); + + ht.put(proto, cl); + + return (cl); + } + + + /* + * A table of cached XFileAccessors + */ + static Hashtable cachedAccessors = new Hashtable(); + + /* + * Load an XFileAccessor + */ + private XFileAccessor loadAccessor(XFurl url) + throws ClassNotFoundException, IllegalAccessException, + InstantiationException { + + Class cl = loadClass(url.getProtocol(), "XFileAccessor", + cachedAccessors); + if (cl == null) + return null; + + return (XFileAccessor)cl.newInstance(); + } + + + /* + * Return a file accessor that corresponds + * to a native file. + */ + private XFileAccessor makeNative(File f) { + char sep = f.separatorChar; + try { + url = new XFurl("file:///" + f.getPath().replace(sep, '/')); + return loadAccessor(url); + } catch (Exception e) { + System.out.println("Error: makenative:" + f.getPath()); + return null; + } + } + + + /* + * Check that the file is open. + * The open() method must be called before + * any other methods in the Accessor. + * This makes it easier for Accessors to + * centralize initialization code in one place. + */ + private boolean bind() { + if (bound) + return true; + + bound = xfa.open(this, false, false); + + return bound; + } + + + /* + * Return the bound status + */ + private boolean getBound() { + return bound; + } + + + /* + * Get the native file + */ + private File getNative() { + return nativeFile; + } + + /* + * Get a new XFileAccessor for this object + */ + protected XFileAccessor newAccessor() { + try { + return loadAccessor(url); + } catch (Exception e) { + return makeNative(nativeFile); + } + } + + /* + * Get the XFileAccessor for this Object + * + * @return XFileAccessor + */ + private XFileAccessor getAccessor() { + return xfa; + } + + + /* + * A table of cached XFileExtensionAccessors + */ + static Hashtable cachedExtensionAccessors = new Hashtable(); + + /** + * Get the XFileExtensionAccessor + * + * @return instance of XFileExtensionAccessor or null + * if there is no XFileExtensionAccessor. + */ + public XFileExtensionAccessor getExtensionAccessor() { + try { + + /* + * XXX The following ugly code avoids a ClassCastException + * for old apps using the deprecated + * nfsXFileExtensionAccessor class. + */ + String suffix; + + if (url.getProtocol().equals("nfs")) + suffix = "nfsXFileExtensionAccessor"; + else + suffix = "XFileExtensionAccessor"; + + Class cl = loadClass(url.getProtocol(), suffix, + cachedExtensionAccessors); + + Constructor con = cl.getConstructor(new Class[]{this.getClass()}); + return (XFileExtensionAccessor)con.newInstance(new Object[]{this}); + + } catch (Exception e) { + return null; + } + } + + + /* + * Get the XFile URL + */ + private XFurl getURL() { + return url; + } + + + /** + * Returns the name of the filesystem, the string before + * the colon of the URL. + * + * If this XFile represents a native path then the + * "file" filesystem will be returned. + * + * @return the name of the filesystem. + */ + public String getFileSystemName() { + return url.getProtocol(); + } + + + /** + * Returns the name of the file represented by this object. + * + * The name is the last component of the pathname. + * For a URL this is the last, non-terminating slash. + * For a native file it is the portion of the pathname after + * the last occurrence of the separator character. + * + * @return the name of the file (without any directory components) + * represented by this XFile object. + */ + public String getName() { + if (nativeFile != null) + return nativeFile.getName(); + + return url.getName(); + } + + + /** + * Returns the pathname of the file represented by this object. + * + * @return the pathname represented by this XFile + * object. + *

+ * If the object is a URL type, the path is the part + * of the URL following the location, e.g. + *

+ * new XFile("nfs://location/a/b/c").getPath() + * == "a/b/c" + *

+ * new XFile("file:///a/b/c").getPath() + * == "a/b/c" + *

+ * new XFile("nfs://server/").getPath() + * == "" + */ + public String getPath() { + if (nativeFile != null) + return nativeFile.getPath(); + + return url.getPath(); + } + + + /** + * Returns the absolute pathname of the file represented by this + * object. + * + * If this object is represented by a native pathname and is an + * absolute pathname, then return the pathname. Otherwise, return + * a pathname that is a concatenation of the current user + * directory, the separator character, and the pathname of this + * file object. + * The system property user.dir contains the current + * user directory. + *

+ * If the object is represented by a URL then return the entire URL + * string. + * + * @return a system-dependent absolute pathname for this + * XFile. + */ + public String getAbsolutePath() { + if (nativeFile != null) + return nativeFile.getAbsolutePath(); + + return urlStr; + } + + + /** + * Returns the canonical form of this XFile object's + * pathname. + * + * If the object is represented by a URL name then the full + * URL is always returned. URL names are always canonical. + *

+ * For native paths the precise definition of canonical form + * is system-dependent, but it usually specifies an absolute + * pathname in which all relative references and references + * to the current user directory have been completely + * resolved. The canonical form of a pathname of a nonexistent + * file may not be defined. + * + * @return the canonical path of the object + * @exception java.io.IOException If an I/O error occurs, which + * is possible because the construction of the + * canonical path may require filesystem queries. + */ + public String getCanonicalPath() throws IOException { + if (nativeFile != null) + return nativeFile.getCanonicalPath(); + + return urlStr; + } + + + /** + * Returns the parent part of the pathname of this + * XFile object, or null if the name + * has no parent part. + * + * If the name is a URL then the parent part is the URL with + * the last component of the pathname removed. If the URL + * has no pathname part, then the URL is returned unchanged. + *

+ * For native paths the parent part is generally everything + * leading up to the last occurrence of the separator character, + * although the precise definition is system dependent. + * On UNIX, for example, the parent part of "/usr/lib" + * is "/usr" whose parent part is "/", + * which in turn has no parent. + * On Windows platforms, the parent part of "c:\java" + * is "c:\", which in turn has no parent. + * + * @return the name of the parent directory + */ + public String getParent() { + if (nativeFile != null) + return nativeFile.getParent(); + + return url.getParent(); + } + + + /** + * Tests if the file represented by this XFile + * object is an absolute pathname. + * + * If the object is represented by a URL then true + * is always returned.
+ * If the XFile represents a native name then + * the definition of an absolute pathname is system + * dependent. For example, on UNIX, a pathname is absolute if its + * first character is the separator character. + * On Windows platforms, + * a pathname is absolute if its first character is an ASCII + * '\' or '/', or if it begins with a letter followed by + * a colon. + * + * @return true if the pathname indicated by the + * XFile object is an absolute pathname; + * false otherwise. + */ + public boolean isAbsolute() { + if (nativeFile != null) + return nativeFile.isAbsolute(); + + return true; + } + + + /** + * Tests if this XFile exists. + * + * @return true if the file specified by this object + * exists; false otherwise. + */ + public boolean exists() { + if (!bind()) + return false; + + return xfa.exists(); + } + + + /** + * Tests if the application can write to this file. + * + * @return true if the application is allowed to + * write to a file whose name is specified by this object; + * false otherwise. + */ + public boolean canWrite() { + if (!bind()) + return false; + + return xfa.canWrite(); + } + + + /** + * Tests if the application can read from the specified file. + * + * @return true if the file specified by this + * object exists and the application can read the file; + * false otherwise. + */ + public boolean canRead() { + if (!bind()) + return false; + + return xfa.canRead(); + } + + + /** + * Tests if the file represented by this XFile + * object is a "normal" file. + * + * A file is "normal" if it is not a directory and, in + * addition, satisfies other system-dependent criteria. Any + * non-directory file created by a Java application is guaranteed + * to be a normal file. + * + * @return true if the file specified by this object + * exists and is a "normal" file; false + * otherwise. + */ + public boolean isFile() { + if (!bind()) + return false; + + return xfa.isFile(); + } + + + /** + * Tests if the file represented by this XFile + * object is a directory. + * + * @return true if this XFile exists + * and is a directory; false otherwise. + */ + public boolean isDirectory() { + if (!bind()) + return false; + + return xfa.isDirectory(); + } + + + + /** + * Returns the time that the file represented by this + * XFile object was last modified. + *

+ * The return value is system dependent and should only be used to + * compare with other values returned by last modified. It should + * not be interpreted as an absolute time. + * + * @return the time the file specified by this object was last + * modified, or 0L if the specified file + * does not exist. + */ + public long lastModified() { + if (!bind()) + return 0L;; + + return xfa.lastModified(); + } + + + /** + * Returns the length of the file represented by this + * XFile object. + * + * @return the length, in bytes, of the file specified by this + * object, or 0L if the specified file does + * not exist. The length constitutes the number of bytes + * readable via an InputStream. The length value for + * a directory is undefined. + */ + public long length() { + if (!bind()) + return 0L; + + return xfa.exists() ? xfa.length() : 0L; + } + + + /** + * Renames the file specified by this XFile object to + * have the pathname given by the XFile argument. + * + * This object and dest must represent filesystems + * of the same type. For instance: both native or both of + * the same URL scheme. + * + * After a successful renameTo, this object continues to + * be a valid reference to the file. Only the name + * is different. + * + * If the destination filename already exists, it will be replaced. + * The application must have permission to modify the source and + * destination directory. + * + * @param dest the new filename. + * @return true if the renaming succeeds; + * false otherwise. + */ + public boolean renameTo(XFile dest) { + if (dest == null) + throw new NullPointerException(); + + if (! xfa.getClass().isInstance(dest.getAccessor())) + return false; + + if (!bind()) + return false; + + boolean ok = xfa.renameTo(dest); + + /* + * Only the name of the file is changed. + * Its data and state are unaffected. + * Hence we make this XFile object a clone + * of the dest XFile. + */ + if (ok) { + url = dest.getURL(); + urlStr = dest.getAbsolutePath(); + nativeFile = dest.getNative(); + xfa = dest.getAccessor(); + bound = dest.getBound(); + } + + return ok; + } + + + /** + * Creates a directory whose pathname is specified by this + * XFile object. + * + * If any parent directories in the pathname do not + * exist, the method will return false. + * + * @return true if the directory could be created; + * false otherwise. + */ + public boolean mkdir() { + bind(); + + return xfa.mkdir(); + } + + + /** + * Creates a directory whose pathname is specified by this + * XFile object, including any necessary parent + * directories. + * + * @return true if the directory (or directories) + * could be created; false otherwise. + */ + public boolean mkdirs() { + bind(); + + if (exists()) { + return false; + } + if (mkdir()) { + return true; + } + + String parent = getParent(); + return (parent != null) && (new XFile(parent).mkdirs() && mkdir()); + } + + + /** + * Returns a list of the files in the directory specified by this + * XFile object. + * + * @return an array of file names in the specified directory. + * This list does not include the current directory or the + * parent directory ("." and ".." + * on Unix systems). + */ + public String[] list() { + if (!bind()) + return null;; + + return xfa.list(); + } + + + /** + * Returns a list of the files in the directory specified by this + * XFile that satisfy the specified filter. + * + * @param filter a filename filter. + * @return an array of file names in the specified directory. + * This list does not include the current directory or the + * parent directory ("." and ".." + * on Unix systems). + * @see com.sun.xfilenameFilter + */ + public String[] list(XFilenameFilter filter) { + if (!bind()) + return null;; + + String names[] = list(); + + if (names == null) { + return null; + } + + // Fill in the Vector + Vector v = new Vector(); + for (int i = 0 ; i < names.length ; i++) { + if ((filter == null) || filter.accept(this, names[i])) { + v.addElement(names[i]); + } + } + + // Create the array + String files[] = new String[v.size()]; + v.copyInto(files); + + return files; + } + + + /** + * Deletes the file specified by this object. + * If the target file to be deleted is a directory, it must be + * empty for deletion to succeed. + * + * @return true if the file is successfully deleted; + * false otherwise. + */ + public boolean delete() { + if (!bind()) + return false;; + + boolean ok = xfa.delete(); + + bound = !ok; + + return ok; + } + + + /** + * Computes a hashcode for the file. + * + * @return a hash code value for this XFile object. + */ + public int hashCode() { + return urlStr.hashCode() ^ 1234321; + } + + + /** + * Compares this object against the specified object. + * + * Returns true if and only if the argument is + * not null and is a XFile object whose + * pathname is equal to the pathname of this object. + * + * @param obj the object to compare with. + * @return true if the objects are the same; + * false otherwise. + */ + public boolean equals(Object obj) { + if ((obj == null) || (! (obj instanceof XFile))) + return false; + + return url.toString().equals(((XFile)obj).getURL().toString()); + } + + + /** + * Returns a string representation of this object. + * + * @return a string giving the pathname of this object. + */ + public String toString() { + if (nativeFile != null) + return (nativeFile.toString()); + + return urlStr; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileAccessor.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileAccessor.java new file mode 100644 index 0000000000..b6d379c134 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileAccessor.java @@ -0,0 +1,328 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +import java.io.IOException; + +/** + * The XFileAccessor interface is implemented by filesystems that + * need to be accessed via the XFile API. + * + * Classes that implement this interface must be associated + * with a URL scheme that is structured according to the + * Common Internet Scheme syntax described in + * RFC 1738; + * an optional location part followed by a hierarchical set + * of slash separated directories. + *

+ * A class file that implements this interface must be named + * "XFileAccessor" and be installed in a directory named after + * the URL scheme that it implements, for instance, an XFileAccessor + * that provides file access through the HTTP protocol would be + * associated with the "http" URL and its class file would be + * called: + *

+ * http.XFileAccessor + *

+ * A class prefix is added to this name. The default prefix is + * com.sun and this composite name is located by the + * classLoader via the CLASSPATH. + * For instance, Sun's "nfs" XFileAccessor is installed as: + *

+ * com.sun.nfs.XFileAccessor + *

+ * The default class prefix com.sun can be changed by + * setting the System property java.protocol.xfile + * to any desired prefix or a list of prefixes separated by + * vertical bars. Each prefix in the list will be used to + * construct a package name and the classLoader will attempt + * to load that package via the CLASSPATH. This process will + * continue until the XFileAccessor is successfully loaded. + *

+ * For instance, if you want to use the "ftp" + * XFileAccessor from Acme, Inc and the "nfs" XFileAccessor + * from "ABC Inc." then you can set the system property as + * follows: + *

+ * java.protocol.xfile=com.acme|com.abc + *
+ * When an "ftp" URL is used, the following package names will + * be constructed: + *
+ *    com.acme.ftp.XFileAccessor
+ *    com.abc.ftp.XFileAccessor
+ *    com.sun.ftp.XFileAccessor
+ * 
+ * (the default "com.sun" prefix is automatically added to + * the end of the property list) + *

+ * The class loader attempts to load each of the constructed + * package names in turn relative to the CLASSPATH until it is + * successful. + *

+ * A subsequent reference to an "nfs" URL will result in + * the following list of candidate package names: + *

+ *    com.acme.nfs.XFileAccessor
+ *    com.abc.nfs.XFileAccessor
+ *    com.sun.nfs.XFileAccessor
+ * 
+ * In this case the "nfs" XFileAccessor from ABC, Inc. will + * be loaded in preference to Sun's NFS. + * + * + * @author Brent Callaghan + * @version 1.0, 04/08/98 + * @see com.sun.xfile.XFile + */ +public interface XFileAccessor { + + + /** + * Open a file in this filesystem. + * + * This method is called before any other method. + * It may be used to open the real file. + * + * @param xf The XFile for the file to be accessed + * The URL will be of the form + *

+ * <proto>://<location>/<path> + *

+ * where <proto> is the name of the filesystem, + * e.g. "nfs" and <location> is the location of + * the filesystem. For nfs this is the network name of + * a server. The <path> is a pathname that locates + * the file within <location>. As required by + * RFC 1738, the component delimiters in the pathname + * are as for URL syntax: forward slashes only. + * @param serial true if serial access; false if random access + * @param readOnly true if read only; false if read/write + */ + boolean open(XFile xf, boolean serial, boolean readOnly); + + /** + * Return the XFile for this Accessor + */ + XFile getXFile(); + + + /** + * Tests if this XFile object exists. + * + * @return true if the file specified by this object + * exists; false otherwise. + */ + boolean exists(); + + + /** + * Tests if the application can write to this file. + * + * @return true if the application is allowed to + * write to a file whose name is specified by this + * object; false otherwise. + */ + boolean canWrite(); + + + /** + * Tests if the application can read from the specified file. + * + * @return true if the file specified by this + * object exists and the application can read the file; + * false otherwise. + */ + boolean canRead(); + + /** + * Tests if the file represented by this + * object is a "normal" file. + *

+ * A file is "normal" if it is not a directory and, in + * addition, satisfies other system-dependent criteria. Any + * non-directory file created by a Java application is + * guaranteed to be a normal file. + * + * @return true if the file specified by this + * object exists and is a "normal" + * file; false otherwise. + */ + boolean isFile(); + + + /** + * Tests if the file represented by this XFileAccessor + * object is a directory. + * + * @return true if this XFileAccessor object + * exists and is a directory; false + * otherwise. + */ + boolean isDirectory(); + + + /** + * Returns the time that the file represented by this + * XFile object was last modified. + * It is measured as the time in milliseconds since + * midnight, January 1, 1970 UTC. + *

+ * @return the time the file specified by this object was last + * modified, or 0L if the specified file + * does not exist. + */ + long lastModified(); + + + /** + * Returns the length of the file represented by this + * XFileAccessor object. + * + * @return the length, in bytes, of the file specified by + * this object, or 0L if the specified + * file does not exist. + */ + long length(); + + + /** + * Creates an empty file whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the file was created; + * false otherwise. + */ + boolean mkfile(); + + + /** + * Creates a directory whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the directory could be created; + * false otherwise. + */ + boolean mkdir(); + + + /** + * Renames the file specified by this XFileAccessor object to + * have the pathname given by the XFileAccessor object argument. + * + * The destination XFile object will be of the same URL + * scheme as this object. The change of name must not + * affect the existence or accessibility of this object. + * + * @param dest the new filename. + * @return true if the renaming succeeds; + * false otherwise. + */ + boolean renameTo(XFile dest); + + + /** + * Deletes the file specified by this object. If the target + * file to be deleted is a directory, it must be empty for deletion + * to succeed. + * + * @return true if the file is successfully deleted; + * false otherwise. + */ + boolean delete(); + + + /** + * Returns a list of the files in the directory specified by + * this XFileAccessor object. + * + * @return an array of file names in the specified directory. + * This list does not include the current directory or + * the parent directory ("." and + * ".." on Unix systems). + */ + String[] list(); + + + /** + * Reads a subarray as a sequence of bytes. + * + * @param b the buffer into which the data is read + * @param off the start offset in the data buffer + * @param len the maximum number of bytes to be read + * @param foff the offset into the file + * @return number of bytes read - zero if none. + * @exception java.io.IOException If an I/O error has occurred. + */ + int read(byte b[], int off, int len, long foff) throws IOException; + + + /** + * Writes a sub array as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data in the buffer + * @param len the number of bytes that are written + * @param foff the offset into the file + * @exception java.io.IOException If an I/O error has occurred. + */ + void write(byte b[], int off, int len, long foff) throws IOException; + + + /** + * Forces any buffered output bytes to be written out. + *

+ * + * @exception java.io.IOException if an I/O error occurs. + */ + void flush() throws IOException; + + + /** + * Close the file. + * + * Closes this file and releases any system resources + * associated with the file. + * + * After the file is closed further I/O operations may + * throw IOException. + * + * @exception java.io.IOException If an I/O error has occurred. + */ + void close() throws IOException; +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileExtensionAccessor.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileExtensionAccessor.java new file mode 100644 index 0000000000..0425845d76 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileExtensionAccessor.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +/** + * This is an abstract class to intended to be extended with + * filesystem-specific methods. + *

+ * An XFileExtensionAccessor class must be associated with an + * XFileAccessor. An XFileExtensionAccessor can be used to + * provide access to filesystem-specific methods that are not + * defined within the XFileAccessor interface. + * A subclass of XFileExtensionAccessor must be declared as: + *


+ *     import com.sun.xfile.*;
+ *     

+ * public class XFileExtensionAccessor extends com.sun.xfile.XFileExtensionAccessor { + * : + * + *

+ *

+ * An XFileExtensionAccessor class is loaded when the + * XFile.getExtensionAccessor() method is invoked. The + * class loading process is identical to that of an + * XFileAccessor except for the final component of the package + * name: "XFileExtensionAccessor" instead of "XFileAccessor". + *

+ * An application that needs to use the methods within the + * XFileExtensionAccessor must cast the result of XFile.getExtensionAccessor. + *


+ *    import com.sun.xfile.*;
+ *    

+ * XFile xf = new XFile("ftp://server/path"); + * com.acme.ftp.XFileExtensionAccessor xftp = + * (com.acme.ftp.XFileExtensionAccessor) xf.getExtensionAccessor(); + * xftp.login(); + * : + *

+ * + * + * @author Brent Callaghan + * @see com.sun.xfile.XFile#getExtensionAccessor() + * @see com.sun.xfile.XFileAccessor + */ +public abstract class XFileExtensionAccessor { + + private XFile xf; + + /* + * Constructor for the XFileExtensionAccessor. + * + * Invoked by the XFile class when its getExtensionAccessor + * method is called. The XFile argument of + * the constructor provides context for the methods + * within the class. + */ + public XFileExtensionAccessor(XFile xf) { + this.xf = xf; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileInputStream.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileInputStream.java new file mode 100644 index 0000000000..c11c8b68c9 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileInputStream.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +import java.io.*; + +/** + * An XFile input stream is an input stream for reading data from an + * XFile. + */ +public class XFileInputStream extends InputStream { + + private long fp; /* File Pointer */ + + /** + * File Accessor that implements the underlying filesystem + */ + private XFileAccessor xfa; + + + /** + * Creates an input file stream to read from the specified + * XFile object. + * + * @param xfile the file to be opened for reading. + * @exception java.io.FileNotFoundException if the file is + * not found. + */ + public XFileInputStream(XFile xfile) throws IOException { + xfa = xfile.newAccessor(); + if (! xfa.open(xfile, true, true)) // serial, read-only + throw new FileNotFoundException("no file"); + + if (!xfa.canRead()) + throw new IOException("no read permission"); + } + + + /** + * Creates an input file stream to read from a file with the + * specified name. + * + * @param name the system-dependent file name. + * @exception java.io.FileNotFoundException if the file is + * not found. + */ + public XFileInputStream(String name) throws IOException { + this(new XFile(name)); + } + + + /* + * Reads a subarray as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @exception java.io.IOException If an I/O error has occurred. + */ + synchronized private int XFAread(byte b[], int off, int len) + throws IOException { + + if (b == null) + throw new NullPointerException(); + + if (len == 0) + return 0; + + if (off < 0 || len < 0 || off >= b.length || (off + len) > b.length) + throw new IllegalArgumentException("Invalid argument"); + + int c = xfa.read(b, off, len, fp); + + if (c <= 0) + return (-1); + + fp += c; + + return (c); + } + + /** + * Reads a byte of data from this XFile. + * + * @return the next byte of data, or -1 + * if the end of the file is reached. + * @exception java.io.IOException if an I/O error occurs. + */ + public int read() throws IOException { + byte[] b = new byte[1]; + + if (XFAread(b, 0, 1) != 1) + return (-1); + + return b[0] & 0xff; + } + + /** + * Reads up to b.length bytes of data from this file + * into an array of bytes. + * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because + * the end of the file has been reached. + * @exception java.io.IOException if an I/O error occurs. + */ + public int read(byte b[]) throws IOException { + return XFAread(b, 0, b.length); + } + + + /** + * Reads up to len bytes of data from this file + * into an array of bytes. + * + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because + * the end of the file has been reached. + * @exception java.io.IOException if an I/O error occurs. + */ + public int read(byte b[], int off, int len) throws IOException { + return XFAread(b, off, len); + } + + + /** + * Returns the number of bytes yet to be read from this file. + * + * @return the number of bytes yet to be read from this file + * without blocking. + * @exception java.io.IOException if an I/O error occurs. + */ + public int available() throws IOException { + return (int)(xfa.length() - fp); + } + + + /** + * Skips over and discards n bytes of data from the + * file. + * + * The skip method may, for a variety of + * reasons, end up skipping over some smaller number of bytes, + * possibly 0. + * The actual number of bytes skipped is returned. + * + * @param n the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @exception java.io.IOException if an I/O error occurs. + */ + public long skip(long n) throws IOException { + if (n < 0) + throw new IllegalArgumentException("illegal skip: " + n); + + fp += n; + + return n; + } + + + /** + * Closes this file input stream and releases any system resources + * associated with the stream. + * + * After the file is closed further I/O operations may + * throw IOException. + * + * @exception java.io.IOException if an I/O error occurs. + */ + public void close() throws IOException { + xfa.close(); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileOutputStream.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileOutputStream.java new file mode 100644 index 0000000000..ad83d23623 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileOutputStream.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +import java.io.*; + +/** + * An XFile output stream is an output stream for writing data to an + * XFile. + */ +public class XFileOutputStream extends OutputStream { + + private long fp; /* File Pointer */ + + /* + * File Accessor that implements the underlying filesystem + */ + private XFileAccessor xfa; + + + /** + * Creates an XFile output stream to write to the specified + * XFile object. + * + * @param file the XFile to be opened for writing. + * @exception java.io.IOException if the XFile could not + * be opened for writing. + */ + public XFileOutputStream(XFile xfile) throws IOException { + + xfa = xfile.newAccessor(); + + if (xfa.open(xfile, true, false)) { // serial, not readonly + if (!xfa.isFile()) + throw new IOException("not a file"); + + if (!xfa.canWrite()) + throw new IOException("no write permission"); + } + + if (!xfa.mkfile()) + throw new IOException("no write permission"); + } + + /** + * Creates an output XFile stream to write to the file with the + * specified name. + * + * @param name the system-dependent filename. + * @exception java.io.IOException if the file could + * not be opened for writing. + */ + public XFileOutputStream(String name) throws IOException { + this(new XFile(name)); + } + + + /** + * Creates an output file for the specified XFile object. + * + * @param xfile the XFile to be opened for writing. + * @param append true if writes begin at the end of the file + * @exception java.io.IOException If the file is not found. + */ + public XFileOutputStream(XFile xfile, boolean append) + throws IOException { + + boolean isExist; + + xfa = xfile.newAccessor(); + + if ((isExist = xfa.open(xfile, true, false))) { // serial, not readonly + if (!xfa.isFile()) + throw new IOException("not a file"); + + if (!xfa.canWrite()) + throw new IOException("no write permission"); + } + + /* + * If file doesn't exist or append is False create the file + */ + if (!isExist || !append) { + if (!xfa.mkfile()) + throw new IOException("no write permission"); + } + + if (append) + fp = xfa.length(); + } + + + /** + * Creates an output file with the specified name or URL. + * + * @param name the native name or URL + * @param append true if writes begin at the end of the file + * @exception java.io.IOException If the file is not found. + */ + public XFileOutputStream(String name, boolean append) + throws IOException { + + this(new XFile(name), append); + + } + + + /* + * All writes to the Accessor go through here. + */ + synchronized private void XFAwrite(byte b[], int off, int len) + throws IOException { + + if (b == null) + throw new NullPointerException(); + + if (len == 0) + return; + + if (off < 0 || len < 0 || off >= b.length || (off + len) > b.length) + throw new IllegalArgumentException("Invalid argument"); + + xfa.write(b, off, len, fp); + fp += len; + } + + + /** + * Writes the specified byte to this file output stream. + * + * @param b the byte to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public void write(int b) throws IOException { + XFAwrite(new byte[] {(byte)b}, 0, 1); + } + + + /** + * Writes b.length bytes from the specified byte array + * to this file output stream. + * + * @param b the data. + * @exception java.io.IOException if an I/O error occurs. + */ + public void write(byte b[]) throws IOException { + XFAwrite(b, 0, b.length); + } + + + /** + * Writes len bytes from the specified byte array + * starting at offset off to this XFile output stream. + * + * @param b the data. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @exception java.io.IOException if an I/O error occurs. + */ + public void write(byte b[], int off, int len) throws IOException { + XFAwrite(b, off, len); + } + + + /** + * Flushes this output stream and forces any buffered output bytes + * to be written out. + *

+ * + * @exception java.io.IOException if an I/O error occurs. + */ + public void flush() throws IOException { + xfa.flush(); + } + + + /** + * Closes this file output stream, flushes any buffered, + * unwritten data, and releases any system resources + * associated with this stream. + * + * After the file is closed further I/O operations may + * throw IOException. + * + * @exception java.io.IOException if an I/O error occurs. + */ + public void close() throws IOException { + xfa.close(); + } + + + /** + * Ensures that the close method of this XFile + * output stream is called when there are no more references + * to this stream. + * + * @exception java.io.IOException if an I/O error occurs. + * @see com.sun.xfile.XFileInputStream#close() + */ + protected void finalize() throws IOException { + close(); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileReader.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileReader.java new file mode 100644 index 0000000000..4068cea979 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileReader.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +import java.io.*; + +/** + * Convenience class for reading character files. + * + * The constructors of this class assume that the default character + * encoding and the default byte-buffer size are appropriate. + * To specify these values yourself, construct an + * InputStreamReader on a FileInputStream. + * + * @see InputStreamReader + * @see XFileInputStream + * + */ +public class XFileReader extends InputStreamReader { + + public XFileReader(String fileName) throws IOException { + super(new XFileInputStream(fileName)); + } + + public XFileReader(XFile file) throws IOException { + super(new XFileInputStream(file)); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileWriter.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileWriter.java new file mode 100644 index 0000000000..28f32db0e9 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFileWriter.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +import java.io.*; + +/** + * Convenience class for writing character files. + * + * The constructors of this class assume that the default character + * encoding and the default byte-buffer size are acceptable. + * To specify these values yourself, construct an + * OutputStreamWriter on a FileOutputStream. + * + * @see OutputStreamWriter + * @see XFileOutputStream + */ +public class XFileWriter extends OutputStreamWriter { + + public XFileWriter(String fileName) throws IOException { + super(new XFileOutputStream(fileName)); + } + + public XFileWriter(String fileName, boolean append) throws IOException { + super(new XFileOutputStream(fileName, append)); + } + + public XFileWriter(XFile file) throws IOException { + super(new XFileOutputStream(file)); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFilenameFilter.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFilenameFilter.java new file mode 100644 index 0000000000..34e41ac3af --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFilenameFilter.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +/** + * Instances of classes that implement this interface are used to + * filter filenames. These instances are used to filter directory + * listings in the list method of class + * XFile. + * + * @see com.sun.xfile.XFile#list(com.sun.xfile.XFilenameFilter) + */ +public interface XFilenameFilter { + + /** + * Tests if a specified file should be included in a file list. + * + * @param dir the directory in which the file was found. + * @param name the name of the file. + * @return true if the name should be included in + * the file list; false otherwise. + */ + boolean accept(XFile dir, String name); +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFurl.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFurl.java new file mode 100644 index 0000000000..e6a9b107a4 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XFurl.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 1999, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +import java.net.MalformedURLException; + +/** + * This is just a dumb URL parser class. + * I wrote it because I got fed up with the + * JDK URL class calling NFS URL's "invalid" + * simply because the Handler wasn't installed. + * + * @author Brent Callaghan + */ +class XFurl { + + private String url; + private String protocol; + private String location; + private String path; + + XFurl(String url) throws MalformedURLException { + int p, q, r; + + url = url.trim(); // remove leading & trailing spaces + this.url = url; + int end = url.length(); + + p = url.indexOf(':'); + if (p < 0) + throw new MalformedURLException("colon expected"); + protocol = url.substring(0, p); + q = p; + p++; // skip colon + if (url.regionMatches(p, "//", 0, 2)) { // have hostname + p += 2; + q = url.indexOf('/', p); + if (q < 0) + q = end; + location = url.substring(p, q); + } + + path = q < end ? url.substring(q + 1, end) : ""; + + // Remove trailing slashes from path + + while (path.endsWith("/")) + path = path.substring(0, path.length()-1); + } + + XFurl(XFurl base, String rpath) throws MalformedURLException { + + protocol = base.getProtocol(); + location = base.getLocation(); + path = base.getPath(); + + rpath = rpath.trim(); + + if (rpath.indexOf("://") > 0) { // URL - ignore base + url = rpath; + XFurl u = new XFurl(rpath); + protocol = u.getProtocol(); + location = u.getLocation(); + path = u.getPath(); + + } else if (rpath.startsWith("/")) { // absolute path + path = rpath.substring(1); + + } else { + + /* + * Escape any "%" characters in the name + * e.g. "%markup" -> "%25markup" + */ + String npath = ""; + int len = rpath.length(); + int p1 = 0, p2; + + while (true) { + p2 = rpath.indexOf('%', p1); // look for % + if (p2 < 0) + p2 = len; + + npath += rpath.substring(p1, p2); + if (p2 >= len) + break; + + npath += "%25"; // replace % with %25 + p1 = p2 + 1; + } + rpath = npath; + len = rpath.length(); + + /* + * Combine base path with relative path + * according to rules in RFCs 1808 & 2054 + * + * e.g. /a/b/c + x = /a/b/c/x + * /a/b/c + /y = /y + * /a/b/c + ../z = /a/b/z + * /a/b/c + d/. = /a/b/c/d + */ + String bpath = base.getPath(); + p1 = 0; + + while (p1 <= len) { + p2 = rpath.indexOf("/", p1); + if (p2 < 0) + p2 = len; + String component = rpath.substring(p1, p2); + + if (component.equals(".") || component.equals("")) { + // ignore + } else if (component.equals("..")) { + int q = bpath.lastIndexOf("/"); + bpath = q < 0 ? "" : bpath.substring(0, q); + } else { + if (bpath.equals("")) + bpath = component; + else + bpath += "/" + component; + } + p1 = p2 + 1; + } + path = bpath; + } + } + + String getProtocol() { + return (protocol); + } + + String getLocation() { + return (location); + } + + String getPath() { + return (path); + } + + String getParent() { + + if (path.equals("")) + return null; // no parent + + String s = protocol + ":"; + + if (location != null) + s += "//" + location; + + int index = path.lastIndexOf('/'); + if (index >= 0) + s += "/" + path.substring(0, index); + + return s; + } + + String getName() { + int index = path.lastIndexOf('/'); + return index < 0 ? path : path.substring(index + 1); + } + + public String toString() { + String s = protocol + ":"; + + if (location != null) + s += "//" + location; + + if (path != null) + s += "/" + path; + + return (s); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XRandomAccessFile.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XRandomAccessFile.java new file mode 100644 index 0000000000..2aeda3ecd6 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfile/XRandomAccessFile.java @@ -0,0 +1,912 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfile; + +import java.io.*; + +/** + * Instances of this class support both reading and writing to a + * random access file. An application can modify the position in the + * file at which the next read or write occurs. + * This class provides a sense of security + * by offering methods that allow specified mode accesses of + * read-only or read-write to files. + * + */ +public class XRandomAccessFile implements DataOutput, DataInput { + + private long fp; /* File Pointer */ + + private boolean readOnly; + + /* + * File Accessor that implements the underlying filesystem + */ + private XFileAccessor xfa; + + + /** + * Creates a random access file stream to read from, and optionally + * to write to, the file specified by the XFile + * argument. + * + * The mode argument must either be equal to "r" or to + * "rw", indicating either to open the file for input, + * or for both input and output, respectively. + * + * @param xf the XFile object. + * @param mode the access mode. + * @exception java.lang.IllegalArgumentException if the mode + * argument is not equal to "r" or + * to "rw". + * @exception java.io.IOException if an I/O error occurs. + */ + public XRandomAccessFile(XFile xf, String mode) throws IOException { + + + if (! (mode.equals("r") || mode.equals("rw"))) + throw new IllegalArgumentException("mode must be r or rw"); + readOnly = mode.equals("r"); + xfa = xf.newAccessor(); + xfa.open(xf, false, readOnly); + + if (xfa.exists()) { + if (readOnly && ! xfa.canRead()) + throw new IOException("no read permission"); + if (! readOnly && ! xfa.canWrite()) + throw new IOException("no write permission"); + } else { + if (readOnly) + throw new IOException("no such file or directory"); + + if (! xfa.mkfile()) + throw new IOException("no write permission"); + } + } + + /** + * Creates a random access file to read from, and optionally + * to write to, a file with the specified name. + *

+ * The mode argument must either be equal to "r" or + * "rw", indicating either to open the file for input + * or for both input and output. + * + * @param name the native or URL file name. + * @param mode the access mode. + * @exception java.lang.IllegalArgumentException if the mode + * argument is not equal to "r" or to + * "rw". + * @exception java.io.IOException if an I/O error occurs. + */ + public XRandomAccessFile(String name, String mode) throws IOException { + this(new XFile(name), mode); + } + + + // 'Read' primitives + + private int XFAread(byte b[], int off, int len) throws IOException { + + if (b == null) + throw new NullPointerException(); + + if (len == 0) + return 0; + + if (off < 0 || len < 0 || off >= b.length || (off + len) > b.length) + throw new IllegalArgumentException("Invalid argument"); + + int c = xfa.read(b, off, len, fp); + + if (c >= 0) + fp += c; + + return c; + } + + + /** + * Reads a byte of data from this file. + * + * @return the next byte of data, or -1 if the + * end of the file is reached. + * @exception java.io.IOException if an I/O error occurs. + */ + public int read() throws IOException { + byte[] b = new byte[1]; + + if (XFAread(b, 0, 1) != 1) + return (-1); + + return b[0] & 0xff; + } + + + /** + * Reads up to len bytes of data from this file into + * an array of bytes. + * + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because + * the end of the file has been reached. + * @exception java.io.IOException if an I/O error occurs. + */ + public int read(byte b[], int off, int len) throws IOException { + return XFAread(b, off, len); + } + + + /** + * Reads up to b.length bytes of data from this file + * into an array of bytes. + * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because + * the end of this file has been reached. + * @exception java.io.IOException if an I/O error occurs. + */ + public int read(byte b[]) throws IOException { + return XFAread(b, 0, b.length); + } + + + /** + * Reads b.length bytes from this file into the byte + * array. + * + * @param b the buffer into which the data is read. + * @exception java.io.EOFException if this file reaches + * the end before reading all the bytes. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void readFully(byte b[]) throws IOException { + readFully(b, 0, b.length); + } + + + /** + * Reads exactly len bytes from this file into + * the byte array. + * + * @param b the buffer into which the data is read. + * @param off the start offset of the data. + * @param len the number of bytes to read. + * @exception java.io.EOFException if this file reaches the + * end before reading all the bytes. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void readFully(byte b[], int off, int len) + throws IOException { + + if (XFAread(b, off, len) < len) + throw new EOFException(); + } + + + /** + * Skips exactly n bytes of input. + *

+ * + * @param n the number of bytes to be skipped. + * @return the number of bytes skipped, which is always + * n. + * @exception java.io.EOFException if this file reaches the end + * before skipping all the bytes. + * @exception java.io.IOException if an I/O error occurs. + */ + public int skipBytes(int n) throws IOException { + + if (fp + n > xfa.length()) + throw new EOFException(); + + seek(fp + n); + + return n; + } + + + // 'Write' primitives + + private void XFAwrite(byte b[], int off, int len) + throws IOException { + + if (b == null) + throw new NullPointerException(); + + if (readOnly) + throw new IOException("Read only file"); + + if (off < 0 || len < 0) + throw new IllegalArgumentException("Invalid argument"); + + xfa.write(b, off, len, fp); + fp += len; + } + + + /** + * Writes the specified byte to this file. + * + * @param b the byte to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public void write(int b) throws IOException { + XFAwrite(new byte[]{(byte)b}, 0, 1); + } + + + /** + * Writes a sub array as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @exception java.io.IOException If an I/O error has occurred. + */ + private void writeBytes(byte b[], int off, int len) + throws IOException { + + XFAwrite(b, off, len); + } + + + /** + * Writes b.length bytes from the specified byte array + * starting at offset off to this file. + * + * @param b the data. + * @exception java.io.IOException if an I/O error occurs. + */ + public void write(byte b[]) throws IOException { + writeBytes(b, 0, b.length); + } + + + /** + * Writes len bytes from the specified byte array + * starting at offset off to this file. + * + * @param b the data. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @exception java.io.IOException if an I/O error occurs. + */ + public void write(byte b[], int off, int len) throws IOException { + writeBytes(b, off, len); + } + + + // 'Random access' stuff + + /** + * Returns the current offset in this file. + * + * @return the offset from the beginning of the file, in bytes, + * at which the next read or write occurs. + * @exception java.io.IOException if an I/O error occurs. + */ + public long getFilePointer() throws IOException { + return fp; + } + + + /** + * Sets the offset from the beginning of this file at which + * the next read or write occurs. + * + * @param pos the absolute position. + * @exception java.io.IOException if an I/O error occurs. + */ + public void seek(long pos) throws IOException { + + if ( pos < 0 || (readOnly && pos >= xfa.length())) + throw new IOException("illegal seek" + pos); + + fp = pos; + } + + + /** + * Returns the length of this file. + * + * @return the length of this file. + * @exception java.io.IOException if an I/O error occurs. + */ + public long length() throws IOException { + return xfa.length(); + } + + + /** + * Forces any buffered output bytes to be written out. + * + * @exception java.io.IOException if an I/O error occurs. + */ + public void flush() throws IOException { + + if (readOnly) + throw new IOException("Read only file"); + + xfa.flush(); + } + + + /** + * Closes this random access file and flushes any + * unwritten data to the file. + * + * After the file is closed further I/O operations may + * throw IOException. + * + * @exception java.io.IOException if an I/O error occurs. + */ + public void close() throws IOException { + xfa.close(); + } + + + // + // Some "reading/writing Java data types" methods stolen from + // DataInputStream and DataOutputStream. + // + + /** + * Reads a boolean from this file. This method reads a + * single byte from the file. A value of 0 represents + * false. Any other value represents true. + * This method blocks until the byte is read, the end of the stream + * is detected, or an exception is thrown. + * + * @return the boolean value read. + * @exception java.io.EOFException if this file has reached the end. + * @exception java.io.IOException if an I/O error occurs. + */ + public final boolean readBoolean() throws IOException { + int ch = this.read(); + if (ch < 0) + throw new EOFException(); + return (ch != 0); + } + + + /** + * Reads a signed 8-bit value from this file. This method reads a + * byte from the file. If the byte read is b, where + * 0 <= b <= 255, + * then the result is: + *

    + * (byte)(b) + *
+ *

+ * This method blocks until the byte is read, the end of the stream + * is detected, or an exception is thrown. + * + * @return the next byte of this file as a signed 8-bit + * byte. + * @exception java.io.EOFException if this file has reached the end. + * @exception java.io.IOException if an I/O error occurs. + */ + public final byte readByte() throws IOException { + int ch = this.read(); + if (ch < 0) + throw new EOFException(); + return (byte)(ch); + } + + + /** + * Reads an unsigned 8-bit number from this file. This method reads + * a byte from this file and returns that byte. + *

+ * This method blocks until the byte is read, the end of the stream + * is detected, or an exception is thrown. + * + * @return the next byte of this file, interpreted as an unsigned + * 8-bit number. + * @exception java.io.EOFException if this file has reached the end. + * @exception java.io.IOException if an I/O error occurs. + */ + public final int readUnsignedByte() throws IOException { + int ch = this.read(); + if (ch < 0) + throw new EOFException(); + return ch; + } + + + /** + * Reads a signed 16-bit number from this file. The method reads 2 + * bytes from this file. If the two bytes read, in order, are + * b1 and b2, where each of the two values is + * between 0 and 255, inclusive, then the + * result is equal to: + *

    + * (short)((b1 << 8) | b2) + *
+ *

+ * This method blocks until the two bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next two bytes of this file, interpreted as a signed + * 16-bit number. + * @exception java.io.EOFException if this file reaches the end before reading + * two bytes. + * @exception java.io.IOException if an I/O error occurs. + */ + public final short readShort() throws IOException { + int ch1 = this.read(); + int ch2 = this.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (short)((ch1 << 8) + (ch2 << 0)); + } + + + /** + * Reads an unsigned 16-bit number from this file. This method reads + * two bytes from the file. If the bytes read, in order, are + * b1 and b2, where + * 0 <= b1, b2 <= 255, + * then the result is equal to: + *

    + * (b1 << 8) | b2 + *
+ *

+ * This method blocks until the two bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next two bytes of this file, interpreted as an unsigned + * 16-bit integer. + * @exception java.io.EOFException if this file reaches the end before reading + * two bytes. + * @exception java.io.IOException if an I/O error occurs. + */ + public final int readUnsignedShort() throws IOException { + int ch1 = this.read(); + int ch2 = this.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (ch1 << 8) + (ch2 << 0); + } + + + /** + * Reads a Unicode character from this file. This method reads two + * bytes from the file. If the bytes read, in order, are + * b1 and b2, where + * 0 <= b1, b2 <= 255, + * then the result is equal to: + *

    + * (char)((b1 << 8) | b2) + *
+ *

+ * This method blocks until the two bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next two bytes of this file as a Unicode character. + * @exception java.io.EOFException if this file reaches the end before reading + * two bytes. + * @exception java.io.IOException if an I/O error occurs. + */ + public final char readChar() throws IOException { + int ch1 = this.read(); + int ch2 = this.read(); + if ((ch1 | ch2) < 0) + throw new EOFException(); + return (char)((ch1 << 8) + (ch2 << 0)); + } + + + /** + * Reads a signed 32-bit integer from this file. This method reads 4 + * bytes from the file. If the bytes read, in order, are b1, + * b2, b3, and b4, where + * 0 <= b1, b2, b3, b4 <= 255, + * then the result is equal to: + *

    + * (b1 << 24) | (b2 << 16) + (b3 << 8) + b4 + *
+ *

+ * This method blocks until the four bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next four bytes of this file, interpreted as an + * int. + * @exception java.io.EOFException if this file reaches the end before reading + * four bytes. + * @exception java.io.IOException if an I/O error occurs. + */ + public final int readInt() throws IOException { + int ch1 = this.read(); + int ch2 = this.read(); + int ch3 = this.read(); + int ch4 = this.read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EOFException(); + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); + } + + + /** + * Reads a signed 64-bit integer from this file. This method reads eight + * bytes from the file. If the bytes read, in order, are + * b1, b2, b3, + * b4, b5, b6, + * b7, and b8, where: + *

    + * 0 <= b1, b2, b3, b4, b5, b6, b7, b8 <=255, + *
+ *

+ * then the result is equal to: + *

+     *     ((long)b1 << 56) + ((long)b2 << 48)
+     *     + ((long)b3 << 40) + ((long)b4 << 32)
+     *     + ((long)b5 << 24) + ((long)b6 << 16)
+     *     + ((long)b7 << 8) + b8
+     * 
+ *

+ * This method blocks until the eight bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next eight bytes of this file, interpreted as a + * long. + * @exception java.io.EOFException if this file reaches the end before reading + * eight bytes. + * @exception java.io.IOException if an I/O error occurs. + */ + public final long readLong() throws IOException { + return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL); + } + + + /** + * Reads a float from this file. This method reads an + * int value as if by the readInt method + * and then converts that int to a float + * using the intBitsToFloat method in class + * Float. + *

+ * This method blocks until the four bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next four bytes of this file, interpreted as a + * float. + * @exception java.io.EOFException if this file reaches the end before reading + * four bytes. + * @exception java.io.IOException if an I/O error occurs. + * @see com.sun.xfile.XRandomAccessFile#readInt() + * @see java.lang.Float#intBitsToFloat(int) + */ + public final float readFloat() throws IOException { + return Float.intBitsToFloat(readInt()); + } + + + /** + * Reads a double from this file. This method reads a + * long value as if by the readLong method + * and then converts that long to a double + * using the longBitsToDouble method in + * class Double. + *

+ * This method blocks until the eight bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return the next eight bytes of this file, interpreted as a + * double. + * @exception java.io.EOFException if this file reaches the end before reading + * eight bytes. + * @exception java.io.IOException if an I/O error occurs. + * @see com.sun.xfile.XRandomAccessFile#readLong() + * @see java.lang.Double#longBitsToDouble(long) + */ + public final double readDouble() throws IOException { + return Double.longBitsToDouble(readLong()); + } + + + /** + * Reads the next line of text from this file. This method + * successively reads bytes from the file until it reaches the end of + * a line of text. + *

+ * A line of text is terminated by a carriage-return character + * ('\r'), a newline character ('\n'), a + * carriage-return character immediately followed by a newline + * character, or the end of the input stream. The line-terminating + * character(s), if any, are included as part of the string returned. + *

+ * This method blocks until a newline character is read, a carriage + * return and the byte following it are read (to see if it is a + * newline), the end of the stream is detected, or an exception is thrown. + * + * @return the next line of text from this file. + * @exception java.io.IOException if an I/O error occurs. + */ + public final String readLine() throws IOException { + StringBuffer input = new StringBuffer(); + int c; + + while (((c = read()) != -1) && (c != '\n')) { + input.append((char)c); + } + if ((c == -1) && (input.length() == 0)) { + return null; + } + return input.toString(); + } + + + /** + * Reads in a string from this file. The string has been encoded + * using a modified UTF-8 format. + *

+ * The first two bytes are read as if by + * readUnsignedShort. This value gives the number of + * following bytes that are in the encoded string, not + * the length of the resulting string. The following bytes are then + * interpreted as bytes encoding characters in the UTF-8 format + * and are converted into characters. + *

+ * This method blocks until all the bytes are read, the end of the + * stream is detected, or an exception is thrown. + * + * @return a Unicode string. + * @exception java.io.EOFException if this file reaches the end before + * reading all the bytes. + * @exception java.io.IOException if an I/O error occurs. + * @exception java.io.UTFDataFormatException if the bytes do not represent + * valid UTF-8 encoding of a Unicode string. + * @see com.sun.xfile.XRandomAccessFile#readUnsignedShort() + */ + public final String readUTF() throws IOException { + return DataInputStream.readUTF(this); + } + + + /** + * Writes a boolean to the file as a 1-byte value. The + * value true is written out as the value + * (byte)1; the value false is written out + * as the value (byte)0. + * + * @param v a boolean value to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void writeBoolean(boolean v) throws IOException { + write(v ? 1 : 0); + //written++; + } + + + /** + * Writes a byte to the file as a 1-byte value. + * + * @param v a byte value to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void writeByte(int v) throws IOException { + write(v); + //written++; + } + + + /** + * Writes a short to the file as two bytes, high byte first. + * + * @param v a short to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void writeShort(int v) throws IOException { + write((v >>> 8) & 0xFF); + write((v >>> 0) & 0xFF); + //written += 2; + } + + + /** + * Writes a char to the file as a 2-byte value, high + * byte first. + * + * @param v a char value to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void writeChar(int v) throws IOException { + write((v >>> 8) & 0xFF); + write((v >>> 0) & 0xFF); + //written += 2; + } + + + /** + * Writes an int to the file as four bytes, high byte first. + * + * @param v an int to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void writeInt(int v) throws IOException { + write((v >>> 24) & 0xFF); + write((v >>> 16) & 0xFF); + write((v >>> 8) & 0xFF); + write((v >>> 0) & 0xFF); + //written += 4; + } + + + /** + * Writes a long to the file as eight bytes, high byte first. + * + * @param v a long to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void writeLong(long v) throws IOException { + write((int)(v >>> 56) & 0xFF); + write((int)(v >>> 48) & 0xFF); + write((int)(v >>> 40) & 0xFF); + write((int)(v >>> 32) & 0xFF); + write((int)(v >>> 24) & 0xFF); + write((int)(v >>> 16) & 0xFF); + write((int)(v >>> 8) & 0xFF); + write((int)(v >>> 0) & 0xFF); + //written += 8; + } + + + /** + * Converts the float argument to an int using the + * floatToIntBits method in class Float, + * and then writes that int value to the file as a + * 4-byte quantity, high byte first. + * + * @param v a float value to be written. + * @exception java.io.IOException if an I/O error occurs. + * @see java.lang.Float#floatToIntBits(float) + */ + public final void writeFloat(float v) throws IOException { + writeInt(Float.floatToIntBits(v)); + } + + + /** + * Converts the double argument to a long using the + * doubleToLongBits method in class Double, + * and then writes that long value to the file as an + * 8-byte quantity, high byte first. + * + * @param v a double value to be written. + * @exception java.io.IOException if an I/O error occurs. + * @see java.lang.Double#doubleToLongBits(double) + */ + public final void writeDouble(double v) throws IOException { + writeLong(Double.doubleToLongBits(v)); + } + + /** + * Writes the string to the file as a sequence of bytes. Each + * character in the string is written out, in sequence, by discarding + * its high eight bits. + * + * @param s a string of bytes to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void writeBytes(String s) throws IOException { + int len = s.length(); + for (int i = 0 ; i < len ; i++) { + write((byte)s.charAt(i)); + } + //written += len; + } + + + /** + * Writes a string to the file as a sequence of characters. Each + * character is written to the data output stream as if by the + * writeChar method. + * + * @param s a String value to be written. + * @exception java.io.IOException if an I/O error occurs. + * @see com.sun.xfile.XRandomAccessFile#writeChar(int) + */ + public final void writeChars(String s) throws IOException { + int len = s.length(); + for (int i = 0 ; i < len ; i++) { + int v = s.charAt(i); + write((v >>> 8) & 0xFF); + write((v >>> 0) & 0xFF); + } + //written += len * 2; + } + + + /** + * Writes a string to the file using UTF-8 encoding in a + * machine-independent manner. + *

+ * First, two bytes are written to the file as if by the + * writeShort method giving the number of bytes to + * follow. This value is the number of bytes actually written out, + * not the length of the string. Following the length, each character + * of the string is output, in sequence, using the UTF-8 encoding + * for each character. + * + * @param str a string to be written. + * @exception java.io.IOException if an I/O error occurs. + */ + public final void writeUTF(String str) throws IOException { + int strlen = str.length(); + int utflen = 0; + + for (int i = 0 ; i < strlen ; i++) { + int c = str.charAt(i); + if ((c >= 0x0001) && (c <= 0x007F)) { + utflen++; + } else if (c > 0x07FF) { + utflen += 3; + } else { + utflen += 2; + } + } + + if (utflen > 65535) + throw new UTFDataFormatException(); + + write((utflen >>> 8) & 0xFF); + write((utflen >>> 0) & 0xFF); + for (int i = 0 ; i < strlen ; i++) { + int c = str.charAt(i); + if ((c >= 0x0001) && (c <= 0x007F)) { + write(c); + } else if (c > 0x07FF) { + write(0xE0 | ((c >> 12) & 0x0F)); + write(0x80 | ((c >> 6) & 0x3F)); + write(0x80 | ((c >> 0) & 0x3F)); + //written += 2; + } else { + write(0xC0 | ((c >> 6) & 0x1F)); + write(0x80 | ((c >> 0) & 0x3F)); + //written += 1; + } + } + //written += strlen + 2; + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfilechooser/BeanXFile.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfilechooser/BeanXFile.java new file mode 100644 index 0000000000..3370cd0284 --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfilechooser/BeanXFile.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfilechooser; + +import java.io.File; +import com.sun.xfile.*; +import java.io.IOException; + +/** + * The BeanXFile class is the interface that makes an XFile object + * look like a File object. This class is needed to support the + * UI of the JFileChooser which accesses file objects. + * Thus all the methods would call the corresponding XFile methods. + * + * @see #XFile + */ +public class BeanXFile extends File { + + private XFile beanXF; + + /* + * BeanXFile constructors which mirror the File I/O constructors. + */ + public BeanXFile(String path) { + super(path); + beanXF = new XFile(path); + } + + public BeanXFile(File dir, String name) { + super(dir, name); + + XFile parentXF = new XFile(dir.getAbsolutePath()); + beanXF = new XFile(parentXF, name); + } + + /* + * XFile Methods that can be accessed. + */ + public String getPath() { + String path = beanXF.getPath(); + + // For nfs URLs, if the url is nfs://, path is "" + if (path == "") + path = beanXF.getAbsolutePath(); + + return path; + } + + public String getAbsolutePath() { + return beanXF.getAbsolutePath(); + } + + public String getCanonicalPath() { + try { + String path = beanXF.getCanonicalPath(); + return path; + } catch (IOException e) { + String path = beanXF.getAbsolutePath(); + return path; + } + + } + + public String getName() { + String fname = beanXF.getName(); + if (fname == null) + return(beanXF.getAbsolutePath()); + else + return(fname); + } + + public boolean renameTo(File dest) { + XFile tmpFile = new XFile(dest.getAbsolutePath()); + return (beanXF.renameTo(tmpFile)); + } + + public String getParent() { + return beanXF.getParent(); + } + + public boolean exists() { + return beanXF.exists(); + } + + public boolean canWrite(){ + return beanXF.canWrite(); + } + + public boolean canRead() { + return beanXF.canRead(); + } + + public boolean isFile() { + return beanXF.isFile(); + } + + public boolean isDirectory() { + return beanXF.isDirectory(); + } + + public boolean isAbsolute() { + // For nfs urls: isAbsolute is always true + return beanXF.isAbsolute(); + } + + public boolean equals(Object obj) { + /* + * Need to pass the XFile object to *.equals because + * it checks for instance of XFile + */ + XFile xf = new XFile(((File)obj).getAbsolutePath()); + return beanXF.equals(xf); + } + + public long lastModified() { + return beanXF.lastModified(); + } + + public long length() { + return beanXF.length(); + } + + public boolean mkdir() { + return beanXF.mkdir(); + } + + public boolean mkdirs() { + return beanXF.mkdirs(); + } + + public String[] list() { + return beanXF.list(); + } + + public String toString() { + return beanXF.toString(); + } + + public boolean delete() { + return beanXF.delete(); + } + +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/xfilechooser/DialogEditor.java b/mucommander-protocol-nfs/src/main/java/com/sun/xfilechooser/DialogEditor.java new file mode 100644 index 0000000000..5fadd0ab1f --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/xfilechooser/DialogEditor.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1998, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.xfilechooser; + +import java.beans.*; +import javax.swing.*; +import javax.swing.filechooser.*; +import java.util.*; +import com.sun.xfilechooser.*; + +/** + * An editor to set the Dialog Type of XFileChooser. Used during + * customization via a bean editor. + * @see #XFileChooserBeanInfo + */ +public class DialogEditor extends PropertyEditorSupport { + + /* For I18N */ + private static ResourceBundle rb = + ResourceBundle.getBundle("com.sun.xfilechooser.EditorResource"/*NOI18N*/); + int[] dialogValues = {JFileChooser.OPEN_DIALOG, JFileChooser.SAVE_DIALOG, + JFileChooser.CUSTOM_DIALOG}; + + String[] dialogNames = {rb.getString("Open"), rb.getString("Save"), + rb.getString("Custom")}; + + /** + * Provides the valid dialog type: Open, Save, or Custom + * @return String name of the valid dialog type + */ + public String[] getTags() { + return dialogNames; + } + + /** + * Gets the integer value of current selected dialog type and returns the + * corresponding string of dialog type. + * @return String name of type of dialog + */ + public String getAsText() { + int s = ((Integer)getValue()).intValue(); + for (int i=0; i

\n/

\n
\n"); + } else { + buf.append("

\n" + path + "

\n
\n"); + } + + // Display a URL link to the parent directory if this is + // not the root directory + if (!root_directory) { + String parentURL = url.toString(); + int limit = parentURL.length() - 1; + if (url.getFile() != null) { + if (parentURL.endsWith("/")) { + limit--; + } + + parentURL = parentURL.substring(0, + parentURL.lastIndexOf('/', limit)); + buf.append(""); + buf.append("

Go To Parent Directory

\n
\n"); + } + } + + // Display the list of files in the directory + dirList = nfsFile.list(); + if (dirList != null) { + + // Sort the entries in the directory list + StringCompare strComp = new StringCompare(); + //Sort.quicksort(dirList, strComp); + Arrays.sort(dirList, strComp); + + boolean hideDotFiles = Boolean.getBoolean("file.hidedotfiles"); + + for (int i = 0 ; i < dirList.length ; i++) { + XFile dirEntry; + + // Don't display the ".." or "." directory entries + if (dirList[i].equals("..") || dirList[i].equals(".")) { + continue; + } + + // Skip files beginning with '.' if the file.hidedotfiles + // property is set + if (hideDotFiles) { + if (dirList[i].charAt(0) == '.') { + continue; + } + } + + // Display an image file for each directory entry + buf.append("\n"); + } else if (dirEntry.isFile()) { + String imageFileName = MimeEntry_defaultImagePath + "/file.gif"; + + // Find the file image to use using the file's .suffix + entry = mt.findByFileName(dirList[i]); + if (entry != null) { + String realImageName = entry.getImageFileName(); + if (realImageName != null) { + imageFileName = realImageName; + } + } + + buf.append(imageFileName); + buf.append("\" WIDTH=" + iconWidth + " HEIGHT=" + iconHeight + + ">\n"); + } else { + // Entry is a symbolic link. Use the default file image for now. + buf.append(MimeEntry_defaultImagePath + + "/file.gif\" WIDTH=" + iconWidth + + " HEIGHT=" + iconHeight + ">\n"); + } + + //dirEntry.close(); + + // Display the directory entry's name + buf.append(""); + buf.append(dirList[i] + "\n
"); + + } + } + + // Finish the HTML document + buf.append("\n\n"); + + // Hand the input stream off to HotJava + is = new ByteArrayInputStream(buf.toString().getBytes()); + + } else { + // Mark the input stream we return as containing a certain file type + // by looking up the file name in the mimetable + entry = mt.findByFileName(path); + if (entry != null) { + props.add("content-type", entry.getType()); + } + setProperties(props); + + if (!nfsFile.exists()) { + throw new IOException("Cannot Access File " + nfsFile.getPath() + "!"); + } + + // Hand the input stream off to HotJava + is = new XFileInputStream(nfsFile); + if (is == null) { + throw new IOException("Unable to Open InputStream for " + url.getFile()); + } + } + + return is; + + } + +} + + +/** + * StringCompare implements the Compare interface. + * Enables the comparison of two String objects. + */ +class StringCompare implements Comparator { + + /** + * compare + * @param str1 - an Object that is presumes is a String Object. + * @param str1 - an Object that is presumes is a String Object. + * @return -1 if str1 < str2, 0 if str1 == str2, 1 if str1 > str2 + */ + public int compare(String str1, String str2) { + String s1, s2; + + s1 = str1.toLowerCase(); + s2 = str2.toLowerCase(); + return s1.compareTo(s2); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/zip/XFileAccessor.java b/mucommander-protocol-nfs/src/main/java/com/sun/zip/XFileAccessor.java new file mode 100644 index 0000000000..f32f77a03c --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/zip/XFileAccessor.java @@ -0,0 +1,398 @@ +/* + * Copyright (c) 1997, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ + +package com.sun.zip; + +import com.sun.xfile.*; +import java.io.*; +import java.util.*; +import java.util.zip.*; + +/** + * The XFileAccessor interface is implemented by filesystems that + * need to be accessed via the XFile API. + * + * @author Brent Callaghan + * @version 1.0, 04/08/98 + * @see com.sun.xfile.XFile + */ +public class XFileAccessor implements com.sun.xfile.XFileAccessor { + + private XFile xf; + private InputStream iStream; + private long fp; // file pointer + private ZipFile zf; + private ZipEntry ze; + private String path; + private ZipURL zu; + private Enumeration zipList; + + + /** + * Open this file object + * + * @param xf the XFile for this file + * @param serial true if serial access + * @param readOnly true if read only + */ + public boolean open(XFile xf, boolean serial, boolean readOnly) { + this.xf = xf; + + try { + zu = new ZipURL(xf.getAbsolutePath()); + zf = new ZipFile(zu.getLocation()); + zipList = zf.entries(); + path = zu.getPath(); + + if (path != null && !path.equals("")) { + ze = zf.getEntry(path); + if (ze == null) { + path += "/"; + ze = zf.getEntry(path); + } + } + + return true; + + } catch (IOException e) { + return false; + } + } + + + /** + * Get the XFile for this Accessor + * + * @return XFile for this object + */ + public XFile getXFile() { + return xf; + } + + /** + * Tests if this XFileAccessor object exists. + * + * @return true if the file specified by this object + * exists; false otherwise. + */ + public boolean exists() { + return ze != null; + } + + + /** + * Tests if the application can write to this file. + * + * @return true if the application is allowed to + * write to a file whose name is specified by this + * object; false otherwise. + */ + public boolean canWrite() { + return false; + } + + + /** + * Tests if the application can read from the specified file. + * + * @return true if the file specified by this + * object exists and the application can read the file; + * false otherwise. + */ + public boolean canRead() { + return true; + } + + /** + * Tests if the file represented by this XFileAccessor + * object is a directory. + * + * @return true if this XFileAccessor object + * exists and is a directory; false + * otherwise. + */ + public boolean isDirectory() { + + if (ze != null) + return ze.isDirectory(); + + /* + * The Zip file may not have an explicit directory + * entry so we may need to infer its presence by + * checking the pathnames of the Zip entries. + */ + String dirPath = path.endsWith("/") ? path : path + "/"; + + while (zipList.hasMoreElements()) { + ZipEntry z = (ZipEntry)zipList.nextElement(); + + if (z.getName().startsWith(dirPath)) + return true; + } + + return false; + } + + + /** + * Tests if the file represented by this + * object is a "normal" file. + *

+ * A file is "normal" if it is not a directory and, in + * addition, satisfies other system-dependent criteria. Any + * non-directory file created by a Java application is + * guaranteed to be a normal file. + * + * @return true if the file specified by this + * XFile object exists and is a "normal" + * file; false otherwise. + */ + public boolean isFile() { + if (ze != null) + return ! ze.isDirectory(); + + return ! isDirectory(); + } + + + /** + * Returns the time that the file represented by this + * XFile object was last modified. + *

+ * The return value is system dependent and should only be + * used to compare with other values returned by last modified. + * It should not be interpreted as an absolute time. + * + * @return the time the file specified by this object was last + * modified, or 0L if the specified file + * does not exist. + */ + public long lastModified() { + return ze.getTime(); + } + + + /** + * Returns the length of the file represented by this + * XFileAccessor object. + * + * @return the length, in bytes, of the file specified by + * this object, or 0L if the specified + * file does not exist. + */ + public long length() { + return ze.getSize(); + } + + + /** + * Creates a file whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the file could be created; + * false otherwise. + */ + public boolean mkfile() { + return false; + } + + + /** + * Creates a directory whose pathname is specified by this + * XFileAccessor object. + * + * @return true if the directory could be created; + * false otherwise. + */ + public boolean mkdir() { + return false; + } + + + /** + * Renames the file specified by this XFileAccessor object to + * have the pathname given by the XFileAccessor object argument. + * + * @param dest the new filename. + * @return true if the renaming succeeds; + * false otherwise. + */ + public boolean renameTo(XFile dest) { + return false; + } + + + /** + * Returns a list of the files in the directory specified by + * this XFileAccessor object. + * + * @return an array of file names in the specified directory. + * This list does not include the current directory or + * the parent directory ("." and + * ".." on Unix systems). + */ + public String[] list() { + + String dirPath = path.endsWith("/") ? path : path + "/"; + int plen = dirPath.length(); + String[] s = new String[8]; + int i = 0; + + while (zipList.hasMoreElements()) { + ZipEntry z = (ZipEntry)zipList.nextElement(); + String zname = z.getName(); + + if (zname.startsWith(dirPath)) { + int slash = zname.indexOf('/', plen); + if (slash < 0) + slash = zname.length(); + s[i++] = zname.substring(plen, slash); + + if (i >= s.length) { // last elem in array ? + String[] tmp = s; + + s = new String[i*2]; // double its size + System.arraycopy(tmp, 0, s, 0, i); + } + } + } + + /* + * Trim array to exact size + */ + if (i < s.length) { + String[] tmp = s; + + s = new String[i]; + System.arraycopy(tmp, 0, s, 0, i); + } + + return s; + } + + + /** + * Deletes the file specified by this object. If the target + * file to be deleted is a directory, it must be empty for + * deletion to succeed. + * + * @return true if the file is successfully deleted; + * false otherwise. + */ + public boolean delete() { + return false; + } + + + /** + * Reads a subarray as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param foff the offset into the file + * @return number of bytes read; -1 if EOF + * @exception IOException If an I/O error has occurred. + */ + public int read(byte b[], int off, int len, long foff) + throws IOException { + + if (iStream == null) + iStream = zf.getInputStream(ze); + + if (foff > fp) { + iStream.skip(foff - fp); + fp = foff; + } + + int c = iStream.read(b, off, len); + if (c > 0) + fp += c; + + return (c); + } + + + /** + * Writes a sub array as a sequence of bytes. + * + * @param b the data to be written + * @param off the start offset in the data + * @param len the number of bytes that are written + * @param foff the offset into the file + * @exception IOException If an I/O error has occurred. + */ + public void write(byte b[], int off, int len, long foff) + throws IOException { + + throw new IOException("write not supported"); + } + + + /** + * Forces any buffered output bytes to be written out. + *

+ * Since RandomAccessFile has no corresponding method + * this does nothing. + * + * @exception IOException if an I/O error occurs. + */ + public void flush() throws IOException { + } + + + /** + * Close the file + * + * @exception IOException If an I/O error has occurred. + */ + public void close() throws IOException { + + if (iStream != null) + iStream.close(); + } + + + /** + * Returns a string representation of this object. + * + * @return a string giving the pathname of this object. + */ + public String toString() { + return zu.toString(); + } +} diff --git a/mucommander-protocol-nfs/src/main/java/com/sun/zip/ZipURL.java b/mucommander-protocol-nfs/src/main/java/com/sun/zip/ZipURL.java new file mode 100644 index 0000000000..329d29729d --- /dev/null +++ b/mucommander-protocol-nfs/src/main/java/com/sun/zip/ZipURL.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1997, 2007 Sun Microsystems, Inc. + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * -Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * -Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING + * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS + * SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE + * AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE + * SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE + * LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, + * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED + * AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR + * INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed,licensed or intended + * for use in the design, construction, operation or maintenance of any + * nuclear facility. + */ +package com.sun.zip; + +import java.net.MalformedURLException; + +/** + * @author Brent Callaghan + */ + +public class ZipURL { + + private String url; + private String protocol; + private String location; + private String path; + + /* + * Undocumented testing options + */ + private int version; + private String proto; + private boolean pub = true; + + public ZipURL(String url) throws MalformedURLException { + int p, q, r; + int end = url.length(); + + url = url.trim(); // remove leading & trailing spaces + this.url = url; + + p = url.indexOf(':'); + if (p < 0) + throw new MalformedURLException("colon expected"); + protocol = url.substring(0, p); + p++; // skip colon + if (url.regionMatches(p, "//", 0, 2)) { // have location + p += 2; + q = url.indexOf('/', p); + if (q < 0) + q = end; + location = url.substring(0, q); + r = q; // no port + if (p < r) + location = url.substring(p, r); + } else { + q = p; + } + + if (q < end) + path = url.substring(q + 1, end); + + } + + public String getProtocol() { + return (protocol); + } + + public String getLocation() { + return (location); + } + + public String getPath() { + return (path); + } + + public String toString() { + String s = getProtocol() + ":"; + + if (location != null) + s += "//" + location; + + if (path != null) + s += "/" + path; + + return (s); + } +} diff --git a/mucommander-protocol-nfs/src/main/resources/com/sun/nfs/nfssec.properties b/mucommander-protocol-nfs/src/main/resources/com/sun/nfs/nfssec.properties index 827fb96129..30f30c31ce 100644 --- a/mucommander-protocol-nfs/src/main/resources/com/sun/nfs/nfssec.properties +++ b/mucommander-protocol-nfs/src/main/resources/com/sun/nfs/nfssec.properties @@ -1,8 +1,38 @@ # -# @(#)nfssec.properties 1.3 99/02/23 -# -# Copyright (c) 1999 Sun Microsystems, Inc. +# Copyright (c) 1999, 2007 Sun Microsystems, Inc. # All Rights Reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# -Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# -Redistribution in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# Neither the name of Sun Microsystems, Inc. or the names of contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# This software is provided "AS IS," without a warranty of any kind. ALL +# EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING +# ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS +# SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE +# AS A RESULT OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE +# SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE +# LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, +# SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED +# AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR +# INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGES. +# +# You acknowledge that this software is not designed,licensed or intended +# for use in the design, construction, operation or maintenance of any +# nuclear facility. # # The WebNFS security services properties file. # diff --git a/mucommander-protocol-ovirt/build.gradle b/mucommander-protocol-ovirt/build.gradle index a4e8594120..23f3ffac34 100644 --- a/mucommander-protocol-ovirt/build.gradle +++ b/mucommander-protocol-ovirt/build.gradle @@ -26,5 +26,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-registry/build.gradle b/mucommander-protocol-registry/build.gradle index dfa3087155..769161e79e 100644 --- a/mucommander-protocol-registry/build.gradle +++ b/mucommander-protocol-registry/build.gradle @@ -29,5 +29,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-s3/build.gradle b/mucommander-protocol-s3/build.gradle index fa84ecb2a2..4f00a1dd87 100644 --- a/mucommander-protocol-s3/build.gradle +++ b/mucommander-protocol-s3/build.gradle @@ -35,5 +35,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-sftp/build.gradle b/mucommander-protocol-sftp/build.gradle index 58d9f2c0b9..b3230e5767 100644 --- a/mucommander-protocol-sftp/build.gradle +++ b/mucommander-protocol-sftp/build.gradle @@ -26,5 +26,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-smb/build.gradle b/mucommander-protocol-smb/build.gradle index 49870dd26d..d08a423bd9 100644 --- a/mucommander-protocol-smb/build.gradle +++ b/mucommander-protocol-smb/build.gradle @@ -28,5 +28,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-protocol-vsphere/build.gradle b/mucommander-protocol-vsphere/build.gradle index cb78a252ef..a7ba6d4cba 100644 --- a/mucommander-protocol-vsphere/build.gradle +++ b/mucommander-protocol-vsphere/build.gradle @@ -30,5 +30,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-translator/build.gradle b/mucommander-translator/build.gradle index 6ff9513c1f..3648bcc30e 100644 --- a/mucommander-translator/build.gradle +++ b/mucommander-translator/build.gradle @@ -21,7 +21,7 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } test { diff --git a/mucommander-translator/src/main/java/com/mucommander/text/Translator.java b/mucommander-translator/src/main/java/com/mucommander/text/Translator.java index 09d3945928..e459ed5e2c 100644 --- a/mucommander-translator/src/main/java/com/mucommander/text/Translator.java +++ b/mucommander-translator/src/main/java/com/mucommander/text/Translator.java @@ -97,9 +97,9 @@ public static boolean hasValue(String key, boolean useDefaultLanguage) { * @param paramValues array of parameters which will be used as values for variables. * @return the localized text String for the given key expressed in the current language */ - public static String get(String key, String... paramValues) { + public static String get(String key, Object... paramValues) { if (dictionaryBundle.containsKey(key)) - return MessageFormat.format(dictionaryBundle.getString(key), (Object[]) paramValues); + return MessageFormat.format(dictionaryBundle.getString(key), paramValues); if (languagesBundle.containsKey(key)) return languagesBundle.getString(key); diff --git a/mucommander-translator/src/main/resources/dictionary.properties b/mucommander-translator/src/main/resources/dictionary.properties index 63cd79d27a..7442fad1e6 100644 --- a/mucommander-translator/src/main/resources/dictionary.properties +++ b/mucommander-translator/src/main/resources/dictionary.properties @@ -42,6 +42,8 @@ customize = Customize choose_folder = Choose a folder login = Login password = Password +maybe_password_protected = Password-protected file? +maybe_password_protected_failure = If it is a password-protected file, you can specify its password below user = User encoding = Encoding preferred_encodings = Preferred encodings @@ -72,6 +74,7 @@ details = Details title = Title warning = Warning error = Error +view = View find = Find generic_error = An error has occurred while performing the requested operation. folder_does_not_exist = This folder doesn''t exist or is not available. @@ -130,7 +133,7 @@ CompareFolders.label = Compare folders ConnectToServer.label = Connect to server ConnectToServer.tooltip = Connect to a remote server Find.label = $[find] -View.label = View +View.label = $[view] InternalView.label = View (internal) View.tooltip = View selected file Edit.label = $[edit] @@ -206,6 +209,8 @@ NewWindow.label = New window NewWindow.tooltip = Open a new window Open.label = Open Open.tooltip = Enter folder / Enter archive / Execute +OpenCommandPrompt.label = Open command prompt +OpenCommandPrompt.tooltip = Open command prompt and change to the current folder OpenNatively.label = Open natively OpenNatively.tooltip = Execute selected file with system''s file associations OpenInNewTab.label = Open in new tab @@ -321,6 +326,7 @@ status_bar.volume_capacity = Capacity: {0} shortcuts_panel.title = Shortcuts shortcuts_panel.restore_defaults = Restore defaults shortcuts_panel.show = Show +shortcuts_panel.filter=Filter shortcuts_panel.default_message = Press Enter or double-click the shortcut you wish to edit shortcuts_table.action_description = Action description shortcuts_table.shortcut = Shortcut @@ -564,19 +570,50 @@ file_viewer.viewer_menu = Viewer file_viewer.close = Close file_viewer.large_file_warning = This file may be too large for this operation. file_viewer.open_anyway = Open anyway +file_viewer.fullscreen = Full screen text_viewer.edit = Edit text_viewer.copy = Copy -text_viewer.select_all = Select All +text_viewer.select_all = Select all text_viewer.find = $[find] text_viewer.find_next = Find next text_viewer.find_previous = Find previous text_viewer.view = View -text_viewer.line_wrap = Line wrap -text_viewer.line_numbers = Line numbers +text_viewer.animate_bracket_matching = Animated bracket matching +text_viewer.anti_aliasing = Anti-aliasing +text_viewer.auto_indent = Auto-indent text_viewer.binary_file_warning = This appears to be a binary file +text_viewer.bracket_matching = Bracket matching +text_viewer.clear_whitespace_lines = Clear whitespace lines +text_viewer.code_folding = Code folding +text_viewer.close_curly_braces = Close curly braces +text_viewer.close_markup_tags = Close markup tags +text_viewer.drag_n_drop = Drag and drop +text_viewer.eol_markers = End Of Line markers +text_viewer.fade_current_line = Fade current line highlighting +text_viewer.highlight_current_line = Highlight current line +text_viewer.line_numbers = Line numbers +text_viewer.line_wrap = Line wrap +text_viewer.mark_occurrences = Mark occurrences +text_viewer.rounded_selection = Rounded selection +text_viewer.show_matched_bracket_popup = Show matched bracket popup +text_viewer.syntax_style = Syntax +text_viewer.tabs_emulated = Tabs emulated with spaces +text_viewer.tab_lines = Tab lines +text_viewer.tab_size = Tab size +text_viewer.whitespace_visible = Whitespace visible +image_viewer.view_menu = $[text_viewer.view] image_viewer.controls_menu = Controls +image_viewer.view_status_bar = Status bar +image_viewer.initial_zoom_menu = Initial zoom +image_viewer.initial_zoom_as_native = Native size +image_viewer.initial_zoom_fit_to_view = Fit to view +image_viewer.initial_zoom_resize_window = Resize window +image_viewer.zoom_to_actual_size = Zoom to actual size +image_viewer.zoom_to_fit = Zoom to fit image_viewer.zoom_in = Zoom in image_viewer.zoom_out = Zoom out +image_viewer.status.imageSizeLabel.toolTipText = Image resolution (width x height) +image_viewer.status.zoomLabel.toolTipText = Current zoom level file_editor.edit_error_title = Edit error file_editor.edit_error = Unable to edit file. file_editor.save = Save @@ -587,6 +624,7 @@ file_editor.editor_menu = Editor file_editor.file_menu = $[file_viewer.file_menu] file_editor.close = $[file_viewer.close] file_editor.open_anyway = $[file_viewer.open_anyway] +file_editor.fullscreen = $[file_viewer.fullscreen] text_editor.cut = Cut text_editor.paste = Paste text_editor.edit = $[text_viewer.edit] @@ -596,8 +634,12 @@ text_editor.view = $[text_viewer.view] text_editor.find = $[text_viewer.find] text_editor.find_next = $[text_viewer.find_next] text_editor.find_previous = $[text_viewer.find_previous] -text_editor.line_wrap = $[text_viewer.line_wrap] -text_editor.line_numbers = $[text_viewer.line_numbers] +text_editor.spaces_to_tabs = Replace spaces with tabs +text_editor.syntax_style = $[text_viewer.syntax_style] +text_editor.tabs_to_spaces = Replace tabs with spaces +text_editor.tab_size = $[text_viewer.tab_size] +text_editor.undo = Undo +text_editor.redo = Redo binary_viewer.name = Binary binary_viewer.copy = $[text_viewer.copy] binary_viewer.select_all = $[text_viewer.select_all] @@ -700,6 +742,7 @@ theme_editor.colors = Colors theme_editor.plain_file = Plain file theme_editor.marked_file = Marked file theme_editor.hidden_file = Hidden file +theme_editor.read_only_file = Read-only file theme_editor.folder = Folder theme_editor.archive_file = Archive theme_editor.symbolic_link = Symbolic link @@ -776,6 +819,8 @@ prefs_dialog.enable_bonjour_discovery = Enable Bonjour services discovery prefs_dialog.enable_system_notifications = Enable system notifications prefs_dialog.open_with_viewer_on_error = Open the file with the viewer in case of opening error prefs_dialog.set_drop_action_to_copy = Set default file drag and drop action to 'COPY' +prefs_dialog.no_quick_search_timeout = None +prefs_dialog.quick_search_timeout_sec = Quick search timeout (seconds) debug_console_dialog.level = Level unit.byte = byte unit.bytes = bytes diff --git a/mucommander-translator/src/main/resources/dictionary_ar.properties b/mucommander-translator/src/main/resources/dictionary_ar.properties index 5da48fefd5..827983be7b 100644 --- a/mucommander-translator/src/main/resources/dictionary_ar.properties +++ b/mucommander-translator/src/main/resources/dictionary_ar.properties @@ -70,6 +70,7 @@ remove = حذ٠details = ØªÙØ§ØµÙŠÙ„ warning = تحذير error = خطأ +view = عرض generic_error = حدث خطأ أثناء إنجاز العملية المطلوبة folder_does_not_exist = هذا المجلد غير موجود أو أنه غير متاح. this_folder_does_not_exist = المجلد التالي غير موجود أو أنه غير متاح: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = التحقق من التحديثات CompareFolders.label = مقارنة المجلدات ConnectToServer.label = الاتصال بالخادم ConnectToServer.tooltip = الاتصال بخادم بعيد -View.label = عرض InternalView.label = عرض (محلي) View.tooltip = عرض المل٠المحدد InternalEdit.label = تحرير (محلي) diff --git a/mucommander-translator/src/main/resources/dictionary_be.properties b/mucommander-translator/src/main/resources/dictionary_be.properties index 46fc38a113..dca9dcaa52 100644 --- a/mucommander-translator/src/main/resources/dictionary_be.properties +++ b/mucommander-translator/src/main/resources/dictionary_be.properties @@ -70,6 +70,7 @@ remove = Выдаліць details = ПадрабÑзьней warning = ПапÑÑ€Ñджаньне error = Памылка +view = ПраглÑдзець generic_error = Пры выкананьні апÑрацыі ўзьнікла памылка folder_does_not_exist = ТÑчка з такім імём не Ñ–Ñнуе альбо недаÑÑÐ³Ð°Ð»ÑŒÐ½Ð°Ñ this_folder_does_not_exist = ТÑчка {0} не Ñ–Ñнуе альбо недаÑÑÐ³Ð°Ð»ÑŒÐ½Ð°Ñ @@ -118,7 +119,6 @@ CheckForUpdates.label = Праверыць абнаўленьні CompareFolders.label = Параўнаць Ñ‚Ñчкі ConnectToServer.label = Злучыцца з ÑÑрвÑрам ConnectToServer.tooltip = Злучыцца з дыÑтанцыÑнаваным ÑÑрвÑрам -View.label = ПраглÑдзець InternalView.label = ПраглÑд (убудаваным) View.tooltip = ПраглÑд абранага файлу InternalEdit.label = РÑдагаваць (убудаваным) diff --git a/mucommander-translator/src/main/resources/dictionary_ca.properties b/mucommander-translator/src/main/resources/dictionary_ca.properties index f27ed11e56..483f1bbd1e 100644 --- a/mucommander-translator/src/main/resources/dictionary_ca.properties +++ b/mucommander-translator/src/main/resources/dictionary_ca.properties @@ -70,6 +70,7 @@ remove = Esborrar details = Detalls warning = Atenció error = Error +view = Visualitza generic_error = S''ha produit un error mentre es realitzava l''operació sol·licitada folder_does_not_exist = El directori no existeix o no està disponible this_folder_does_not_exist = Aquest directori no existeix o no està disponible @@ -118,7 +119,6 @@ CheckForUpdates.label = Comprova les actualitzacions CompareFolders.label = Compara directoris ConnectToServer.label = Connecta''t a un servidor ConnectToServer.tooltip = Connecta''t a un servidor remot -View.label = Visualitza InternalView.label = Visualitza (intern) View.tooltip = Visualitza el fitxer seleccionat InternalEdit.label = Edita (intern) diff --git a/mucommander-translator/src/main/resources/dictionary_cs.properties b/mucommander-translator/src/main/resources/dictionary_cs.properties index 4194e7dad8..f48fa04fd3 100644 --- a/mucommander-translator/src/main/resources/dictionary_cs.properties +++ b/mucommander-translator/src/main/resources/dictionary_cs.properties @@ -70,6 +70,7 @@ remove = Odstranit details = Podrobnosti warning = UpozornÄ›ní error = Chyba +view = Zobrazit generic_error = PÅ™i provádÄ›ní požadované operace se vyskytla chyba. folder_does_not_exist = Tato složka neexistuje nebo není dostupná. this_folder_does_not_exist = Tato složka neexistuje nebo není dostupná: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Zkontrolovat aktualizace CompareFolders.label = Porovnat složky ConnectToServer.label = PÅ™ipojit se k serveru ConnectToServer.tooltip = PÅ™ipojit se k vzdálenému serveru -View.label = Zobrazit InternalView.label = Zobrazit (internÄ›) View.tooltip = Zobrazit vybraný soubor InternalEdit.label = Upravit (internÄ›) diff --git a/mucommander-translator/src/main/resources/dictionary_da.properties b/mucommander-translator/src/main/resources/dictionary_da.properties index 2e17f9935c..5dae93cf13 100644 --- a/mucommander-translator/src/main/resources/dictionary_da.properties +++ b/mucommander-translator/src/main/resources/dictionary_da.properties @@ -70,6 +70,7 @@ remove = Fjern details = Detaljer warning = Advarsel error = Fejl +view = Vis generic_error = En fejl opstod under den ønskede handling folder_does_not_exist = Mappen findes ikke eller er ikke tilgængelig this_folder_does_not_exist = Mappen findes ikke eller er ikke tilgængelig: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Søg efter opdateringer CompareFolders.label = Sammenlign mapper ConnectToServer.label = Forbind til server ConnectToServer.tooltip = Forbind til en fjernserver -View.label = Vis InternalView.label = Vis (indbygget) View.tooltip = Vis markerede fil InternalEdit.label = Rediger (indbygget) diff --git a/mucommander-translator/src/main/resources/dictionary_de.properties b/mucommander-translator/src/main/resources/dictionary_de.properties index 37655090d6..8b4d5d51d2 100644 --- a/mucommander-translator/src/main/resources/dictionary_de.properties +++ b/mucommander-translator/src/main/resources/dictionary_de.properties @@ -71,6 +71,7 @@ remove = Entfernen details = Details warning = Warnung error = Fehler +view = Anzeigen generic_error = Während der angeforderten Operation ist ein Fehler aufgetreten folder_does_not_exist = Dieser Ordner existiert nicht oder ist nicht verfügbar. this_folder_does_not_exist = Dieser Ordner existiert nicht oder ist nicht verfügbar: {0} @@ -119,7 +120,6 @@ CheckForUpdates.label = Nach Updates suchen CompareFolders.label = Ordner vergleichen ConnectToServer.label = Verbinde mit Server ConnectToServer.tooltip = Mit einem Remote Server verbinden -View.label = Anzeigen InternalView.label = Anzeigen (eingebaut) View.tooltip = Markierte Datei betrachten InternalEdit.label = Editor (eingebaut) diff --git a/mucommander-translator/src/main/resources/dictionary_en.properties b/mucommander-translator/src/main/resources/dictionary_en.properties index 3cb0acbe64..3258c6a46c 100644 --- a/mucommander-translator/src/main/resources/dictionary_en.properties +++ b/mucommander-translator/src/main/resources/dictionary_en.properties @@ -72,6 +72,7 @@ details = Details title = Title warning = Warning error = Error +view = View find = Find generic_error = An error has occurred while performing the requested operation. folder_does_not_exist = This folder doesn''t exist or is not available. @@ -129,8 +130,6 @@ CheckForUpdates.label = Check for updates CompareFolders.label = Compare folders ConnectToServer.label = Connect to server ConnectToServer.tooltip = Connect to a remote server -Find.label = $[find] -View.label = View InternalView.label = View (internal) View.tooltip = View selected file Edit.label = $[edit] @@ -206,8 +205,6 @@ NewWindow.label = New window NewWindow.tooltip = Open a new window Open.label = Open Open.tooltip = Enter folder / Enter archive / Execute -OpenCommandPrompt.label = Open command prompt -OpenCommandPrompt.tooltip = Open command prompt and change to the current folder OpenNatively.label = Open natively OpenNatively.tooltip = Execute selected file with system''s file associations OpenInNewTab.label = Open in new tab @@ -320,11 +317,6 @@ status_bar.selected_files = {0} of {1} selected status_bar.connecting_to_folder = Connecting to folder, press ESCAPE to cancel. status_bar.volume_free = Free: {0} status_bar.volume_capacity = Capacity: {0} -shortcuts_panel.title = Shortcuts -shortcuts_panel.restore_defaults = Restore defaults -shortcuts_panel.show = Show -shortcuts_panel.filter=Filter -shortcuts_panel.default_message = Press Enter or double-click the shortcut you wish to edit shortcuts_table.action_description = Action description shortcuts_table.shortcut = Shortcut shortcuts_table.alternate_shortcut = Alternate Shortcut @@ -552,9 +544,11 @@ edit_bookmarks_dialog.new = New file_viewer.view_error_title = View error file_viewer.view_error = Unable to view file. file_viewer.file_menu = File +file_viewer.viewer_menu = Viewer file_viewer.close = Close file_viewer.large_file_warning = This file may be too large for this operation. file_viewer.open_anyway = Open anyway +file_viewer.fullscreen = Full screen text_viewer.edit = Edit text_viewer.copy = Copy text_viewer.select_all = Select All @@ -562,10 +556,33 @@ text_viewer.find = $[find] text_viewer.find_next = Find next text_viewer.find_previous = Find previous text_viewer.view = View -text_viewer.line_wrap = Line wrap -text_viewer.line_numbers = Line numbers +text_viewer.animate_bracket_matching = Animated bracket matching +text_viewer.anti_aliasing = Anti-aliasing +text_viewer.auto_indent = Auto-indent text_viewer.binary_file_warning = This appears to be a binary file +text_viewer.bracket_matching = Bracket matching +text_viewer.clear_whitespace_lines = Clear whitespace lines +text_viewer.code_folding = Code folding +text_viewer.close_curly_braces = Close curly braces +text_viewer.close_markup_tags = Close markup tags +text_viewer.drag_n_drop = Drag and drop +text_viewer.eol_markers = End Of Line markers +text_viewer.fade_current_line = Fade current line highlighting +text_viewer.highlight_current_line = Highlight current line +text_viewer.line_numbers = Line numbers +text_viewer.line_wrap = Line wrap +text_viewer.mark_occurrences = Mark occurrences +text_viewer.rounded_selection = Rounded selection +text_viewer.show_matched_bracket_popup = Show matched bracket popup +text_viewer.syntax_style = Syntax +text_viewer.tabs_emulated = Tabs emulated with spaces +text_viewer.tab_lines = Tab lines +text_viewer.tab_size = Tab size +text_viewer.whitespace_visible = Whitespace visible +image_viewer.view_menu = $[text_viewer.view] image_viewer.controls_menu = Controls +image_viewer.zoom_to_actual_size = Zoom to actual size +image_viewer.zoom_to_fit = Zoom to fit image_viewer.zoom_in = Zoom in image_viewer.zoom_out = Zoom out file_editor.edit_error_title = Edit error @@ -574,24 +591,26 @@ file_editor.save = Save file_editor.save_as = Save as... file_editor.save_warning = Save changes made to this file before closing ? file_editor.cannot_write = Unable to write file. +file_editor.editor_menu = Editor file_editor.file_menu = $[file_viewer.file_menu] file_editor.close = $[file_viewer.close] file_editor.open_anyway = $[file_viewer.open_anyway] +file_editor.fullscreen = $[file_viewer.fullscreen] text_editor.cut = Cut text_editor.paste = Paste text_editor.edit = $[text_viewer.edit] text_editor.copy = $[text_viewer.copy] text_editor.select_all = $[text_viewer.select_all] -text_editor.view = $[text_viewer.view] text_editor.find = $[text_viewer.find] text_editor.find_next = $[text_viewer.find_next] text_editor.find_previous = $[text_viewer.find_previous] -text_editor.line_wrap = $[text_viewer.line_wrap] -text_editor.line_numbers = $[text_viewer.line_numbers] +text_editor.spaces_to_tabs = Replace spaces with tabs +text_editor.syntax_style = $[text_viewer.syntax_style] +text_editor.tabs_to_spaces = Replace tabs with spaces +text_editor.tab_size = $[text_viewer.tab_size] binary_viewer.name = Binary binary_viewer.copy = $[text_viewer.copy] binary_viewer.select_all = $[text_viewer.select_all] -binary_viewer.view = $[text_viewer.view] binary_viewer.edit = $[text_viewer.edit] binary_viewer.code_type = Code Type binary_viewer.code_type.binary = Binary @@ -766,6 +785,8 @@ prefs_dialog.enable_bonjour_discovery = Enable Bonjour services discovery prefs_dialog.enable_system_notifications = Enable system notifications prefs_dialog.open_with_viewer_on_error = Open the file with the viewer in case of opening error prefs_dialog.set_drop_action_to_copy = Set default file drag and drop action to 'COPY' +prefs_dialog.no_quick_search_timeout = None +prefs_dialog.quick_search_timeout_sec = Quick search timeout (seconds) debug_console_dialog.level = Level unit.byte = byte unit.bytes = bytes @@ -781,7 +802,7 @@ duration.hours = {0}h duration.days = {0}d duration.months = {0}mo duration.years = {0}y -duration.infinite = ∞ +duration.infinite = \u221e theme.custom_theme = Custom theme theme.custom = Customized theme.built_in = Built-in diff --git a/mucommander-translator/src/main/resources/dictionary_es.properties b/mucommander-translator/src/main/resources/dictionary_es.properties index 91497b861c..7e37fe2c2b 100644 --- a/mucommander-translator/src/main/resources/dictionary_es.properties +++ b/mucommander-translator/src/main/resources/dictionary_es.properties @@ -71,6 +71,7 @@ remove = Eliminar details = Detalles warning = Aviso error = Error +view = Ver generic_error = Ha ocurrido un error mientras se realizaba la operación folder_does_not_exist = El directoio no existe o no está disponible. this_folder_does_not_exist = El directoio no existe o no está disponible: {0} @@ -119,7 +120,6 @@ CheckForUpdates.label = Comprobar actualizaciones CompareFolders.label = Comparar directorios ConnectToServer.label = Conectar a un servidor ConnectToServer.tooltip = Conectar a un servidor remoto -View.label = Ver InternalView.label = Visualizar (interno) View.tooltip = Ver el fichero seleccionado InternalEdit.label = Editar (interno) diff --git a/mucommander-translator/src/main/resources/dictionary_fr.properties b/mucommander-translator/src/main/resources/dictionary_fr.properties index 346ebf4ec0..cf1d4ddca4 100644 --- a/mucommander-translator/src/main/resources/dictionary_fr.properties +++ b/mucommander-translator/src/main/resources/dictionary_fr.properties @@ -71,6 +71,7 @@ details = Détails title = Titre warning = Avertissement error = Erreur +view = Voir generic_error = Une erreur est survenue pendant l''exécution de la tache demandée. folder_does_not_exist = Ce dossier n''existe pas ou n''est pas disponible. failed_to_read_folder = Echec à la lecture de ce dossier. @@ -122,7 +123,6 @@ CheckForUpdates.label = Mises à jour CompareFolders.label = Comparer dossiers ConnectToServer.label = Connexion à un serveur ConnectToServer.tooltip = Se connecter à un serveur distant -View.label = Voir InternalView.label = Voir (interne) View.tooltip = Voir le fichier sélectionné InternalEdit.label = Editer (interne) diff --git a/mucommander-translator/src/main/resources/dictionary_hu.properties b/mucommander-translator/src/main/resources/dictionary_hu.properties index 4f1cc8893f..a2dfaeb77f 100644 --- a/mucommander-translator/src/main/resources/dictionary_hu.properties +++ b/mucommander-translator/src/main/resources/dictionary_hu.properties @@ -70,6 +70,7 @@ remove = Mozgat details = Részletek warning = Figyelem error = Hiba +view = Megnéz generic_error = Hiba történt a művelet elvégzése alatt. folder_does_not_exist = A könyvtár nem létezik vagy nem található. this_folder_does_not_exist = A könyvtár nem létezik vagy nem elérhetÅ‘: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Frissítések keresése CompareFolders.label = Könyvtárak összehasonlítása ConnectToServer.label = Csatlakozás a szerverhez ConnectToServer.tooltip = Kapcsolodás a távoli szerverhez -View.label = Megnéz InternalView.label = MegnézÅ‘ (beépített) View.tooltip = A kijelölt fájl megtekintése InternalEdit.label = SzerkesztÅ‘ (beépített) diff --git a/mucommander-translator/src/main/resources/dictionary_it.properties b/mucommander-translator/src/main/resources/dictionary_it.properties index f2a05865e6..b9d311ea6a 100644 --- a/mucommander-translator/src/main/resources/dictionary_it.properties +++ b/mucommander-translator/src/main/resources/dictionary_it.properties @@ -64,6 +64,7 @@ this_operation_cannot_be_undone = Questa operazione non puo'' essere annullata. remove = Elimina warning = Attenzione error = Errore +view = Vedi generic_error = Errore durante l''esecuzione dell''operazione richiesta. folder_does_not_exist = Directory inesistente o non disponibile. this_folder_does_not_exist = Directory inesistente o non disponibile: {0} @@ -110,7 +111,6 @@ CheckForUpdates.label = Controlla aggiornamenti CompareFolders.label = Confronta directory ConnectToServer.label = Connetti al server ConnectToServer.tooltip = Connetti ad un server remoto -View.label = Vedi View.tooltip = Visualizza file selezionati Edit.tooltip = Modifica file selezionato Copy.tooltip = Copia file selezionati diff --git a/mucommander-translator/src/main/resources/dictionary_ja.properties b/mucommander-translator/src/main/resources/dictionary_ja.properties index 3fa77f5028..e98fcdd1d3 100644 --- a/mucommander-translator/src/main/resources/dictionary_ja.properties +++ b/mucommander-translator/src/main/resources/dictionary_ja.properties @@ -64,6 +64,7 @@ this_operation_cannot_be_undone = ã“ã®æ“作ã¯å…ƒã«æˆ»ã›ã¾ã›ã‚“。 remove = 削除 warning = 警告 error = エラー +view = 表示 generic_error = è¦æ±‚ã•ã‚ŒãŸæ“作を行ã£ã¦ã„ã‚‹é–“ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¦ã„ã¾ã™ã€‚ folder_does_not_exist = ã“ã®ãƒ•ォルダーã¯å­˜åœ¨ã—ãªã„ã‹åˆ©ç”¨ã§ãã¾ã›ã‚“。 this_folder_does_not_exist = ã“ã®ãƒ•ォルダーã¯å­˜åœ¨ã—ãªã„ã‹åˆ©ç”¨ã§ãã¾ã›ã‚“: {0} @@ -110,7 +111,6 @@ CheckForUpdates.label = æ›´æ–°ã®ãƒã‚§ãƒƒã‚¯ CompareFolders.label = ãƒ•ã‚©ãƒ«ãƒ€ãƒ¼ã®æ¯”較 ConnectToServer.label = サーãƒãƒ¼ã¸æŽ¥ç¶š ConnectToServer.tooltip = リモート サーãƒãƒ¼ã¸æŽ¥ç¶šã—ã¾ã™ -View.label = 表示 View.tooltip = é¸æŠžã•れãŸãƒ•ァイルを表示ã—ã¾ã™ Edit.tooltip = é¸æŠžã•れãŸãƒ•ァイルを編集ã—ã¾ã™ Copy.tooltip = マークã•れãŸãƒ•ァイルをコピーã—ã¾ã™ diff --git a/mucommander-translator/src/main/resources/dictionary_ko.properties b/mucommander-translator/src/main/resources/dictionary_ko.properties index 24b5258662..1d5f8405a4 100644 --- a/mucommander-translator/src/main/resources/dictionary_ko.properties +++ b/mucommander-translator/src/main/resources/dictionary_ko.properties @@ -19,6 +19,7 @@ retry = ìž¬ì‹œë„ resume = 재개 overwrite = ë®ì–´ì“°ê¸° overwrite_if_older = ì˜¤ëž˜ëœ ê²½ìš° ë®ì–´ì“°ê¸° +overwrite_if_size_differs = í¬ê¸°ê°€ 다를 경우 ë®ì–´ì“°ê¸° duplicate = 중복 apply_to_all = ëª¨ë‘ ì ìš© copy = 복사 @@ -66,11 +67,12 @@ nb_files = {0} íŒŒì¼ nb_folders = {0} í´ë” loading = 불러오는 중... this_operation_cannot_be_undone = ì´ ìž‘ì—…ì€ ì·¨ì†Œí•  수 없습니다. -remove = ì´ë™ +remove = 제거 details = ìžì„¸ížˆ title = 제목 warning = 경고 error = 오류 +view = 보기 find = 찾기 generic_error = 요청한 ìž‘ì—…ì„ ìˆ˜í–‰í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. folder_does_not_exist = ì´ í´ë”는 존재하지 않거나 사용할 수 없습니다. @@ -96,6 +98,7 @@ integrity_check_error = 무결성 검사 실패: ì›ë³¸ì™€ 대ìƒì´ ì¼ì¹˜í•˜ startup_error = 오류로 ì¸í•´ muCommanderê°€ 시작ë˜ì§€ 않았습니다. gdrive = Google 드ë¼ì´ë¸Œ dropbox = Dropbox +portable=휴대용 permissions.read = ì½ê¸° permissions.write = 쓰기 permissions.executable = 실행 가능 @@ -127,8 +130,6 @@ CheckForUpdates.label = ì—…ë°ì´íЏ í™•ì¸ CompareFolders.label = í´ë” ë¹„êµ ConnectToServer.label = ì„œë²„ì— ì—°ê²° ConnectToServer.tooltip = ì›ê²© ì„œë²„ì— ì—°ê²° -Find.label = $[find] -View.label = 보기 InternalView.label = 보기 (내장) View.tooltip = ì„ íƒí•œ íŒŒì¼ ë³´ê¸° Edit.label = $[edit] @@ -201,15 +202,15 @@ SwapFolders.tooltip = 왼쪽 ë° ì˜¤ë¥¸ìª½ í´ë” êµì²´ SetSameFolder.label = ê°™ì€ í´ë”로 설정 SetSameFolder.tooltip = 왼쪽 ë° ì˜¤ë¥¸ìª½ 패ë„ì„ ê°™ì€ ë””ë ‰í† ë¦¬ë¡œ 설정 NewWindow.label = 새 ì°½ -NewWindow.tooltip = 새 창으로 열기 +NewWindow.tooltip = 새 ì°½ 열기 Open.label = 열기 -Open.tooltip = í´ë” 열기 / ì••ì¶•íŒŒì¼ ì—´ê¸° / 실행 +Open.tooltip = í´ë” ìž…ë ¥ / ë³´ê´€ ìž…ë ¥ / 실행 OpenCommandPrompt.label = 명령 프롬프트 열기 OpenCommandPrompt.tooltip = 명령 프롬프트를 ì—´ê³  현재 í´ë”로 변경 -OpenNatively.label = 기본ì ìœ¼ë¡œ 열기 -OpenNatively.tooltip = ì‹œìŠ¤í…œì˜ íŒŒì¼ ì—°ê²°ë¡œ ì„ íƒí•œ íŒŒì¼ ì‹¤í–‰ +OpenNatively.label = 기본으로 열기 +OpenNatively.tooltip = ì„ íƒí•œ 파ì¼ì„ ì‹œìŠ¤í…œì˜ íŒŒì¼ ì—°ê²°ê³¼ 함께 실행 OpenInNewTab.label = 새 탭ì—서 열기 -ShowInEnclosingFolder.label = ë™ë´‰ëœ í´ë”ì— í‘œì‹œ +ShowInEnclosingFolder.label = ë™ë´‰ í´ë”ì— í‘œì‹œ OpenInOtherPanel.label = 다른 패ë„ì—서 열기 OpenInBothPanels.label = ë‘ íŒ¨ë„ì—서 ëª¨ë‘ ì—´ê¸° RevealInDesktop.label = {0}ì—서 표시 @@ -225,7 +226,7 @@ ShowFilePopupMenu.label = íŒì—… 메뉴 ShowFilePopupMenu.tooltip = ì„ íƒí•œ 파ì¼ì— 대한 컨í…스트 íŒì—… 메뉴를 표시 ShowPreferences.label = 환경 설정 ShowPreferences.tooltip = muCommander 구성 -ShowServerConnections.label = 열린 ì—°ê²° 표시 +ShowServerConnections.label = ì—´ë ¤ 있는 ì—°ê²° 표시 Quit.label = ë내기 ReverseSortOrder.label = 역순 ToggleAutoSize.label = ì—´ ìžë™ í¬ê¸° ì¡°ì • @@ -241,6 +242,8 @@ CustomizeCommandBar.label = 명령 ëª¨ìŒ ì‚¬ìš©ìž ì§€ì • ToggleStatusBar.show = ìƒíƒœ 표시줄 표시 ToggleStatusBar.hide = ìƒíƒœ 표시줄 숨기기 ToggleShowFoldersFirst.label = í´ë”를 먼저 표시 +ToggleTerminal.label = í„°ë¯¸ë„ í‘œì‹œ +ToggleTerminal.hide = í„°ë¯¸ë„ ìˆ¨ê¸°ê¸° ToggleTree.label = 트리 보기 표시 PopupLeftDriveButton.label = 왼쪽 í´ë” 변경 PopupRightDriveButton.label = 오른쪽 í´ë” 변경 @@ -276,7 +279,7 @@ GoToWebsite.label = 웹 사ì´íŠ¸ë¡œ ì´ë™ GoToForums.label = í¬ëŸ¼ìœ¼ë¡œ ì´ë™ ReportBug.label = 버그 ë³´ê³  Donate.label = 기부하기 -ShowAbout.label = muCommander ì •ë³´ +ShowAbout.label = muCommander ì •ë³´ - 한국어 번역: 비너스걸 OpenTrash.label = 휴지통 열기 EmptyTrash.label = 휴지통 비우기 CalculateChecksum.label = ì²´í¬ì„¬ 계산 @@ -488,13 +491,15 @@ search_dialog.case_sensitive = $[file_selection_dialog.case_sensitive] search_dialog.matches_regexp = $[file_selection_dialog.matches_regexp] search_dialog.wildcards = (* = 모든 문ìžì—´, ? = 모든 ìºë¦­í„°, \\ = ë¬¸ìž ê·¸ëŒ€ë¡œ: *?) search_dialog.search_text = í…스트 í¬í•¨ +search_dialog.size_error= í¬ê¸°ëŠ” 숫ìžì´ê±°ë‚˜ 비어 있어야 합니다! +search_dialog.size_unit.bytes = ë°”ì´íЏ search_dialog.text_case_sensitive = $[file_selection_dialog.case_sensitive] search_dialog.text_matches_regexp = $[file_selection_dialog.matches_regexp] server_connect_dialog.server_type = ì—°ê²° 유형 server_connect_dialog.server = 서버 server_connect_dialog.share = 공유 server_connect_dialog.domain = ë„ë©”ì¸ -server_connect_dialog.username = 사용ìžëª… +server_connect_dialog.username = ì‚¬ìš©ìž ì´ë¦„ server_connect_dialog.initial_dir = 초기 디렉터리 server_connect_dialog.port = í¬íЏ server_connect_dialog.server_url = 서버 URL @@ -505,6 +510,10 @@ server_connect_dialog.nfs_version = NFS 버전 server_connect_dialog.private_key = ê°œì¸ í‚¤ server_connect_dialog.passphrase = 암호 server_connect_dialog.use_proxy = 프ë¡ì‹œ 사용 +server_connect_dialog.storage_type = 저장소 유형 +server_connect_dialog.buckets_location = 버킷 위치 +server_connect_dialog.dns_buckets = DNS 버킷 +server_connect_dialog.secure_http = 보안 HTTP (HTTPS) server_connect_dialog.account = 계정 server_connect_dialog.account_alias = 계정 별칭 server_connect_dialog.privacy_policy = ê°œì¸ ì •ë³´ 보호 ì •ì±… @@ -532,7 +541,8 @@ vsphere_connections_dialog.guest_user = 게스트 ì‚¬ìš©ìž ì´ë¦„ vsphere_connections_dialog.guest_password = 게스트 암호 bonjour.bonjour_services = Bonjour 서비스 bonjour.no_service_discovered = ê²€ìƒ‰ëœ ì„œë¹„ìŠ¤ ì—†ìŒ -bonjour.bonjour_disabled = Bonjour 사용 안함 +bonjour.bonjour_disabled = Bonjour 사용 안 함 +bonjour.bonjour_initializing = Bonjour 초기화 중 auth_dialog.title = ì¸ì¦ auth_dialog.desc = ë¡œê·¸ì¸ ë° ì•”í˜¸ë¥¼ 입력하세요 auth_dialog.server = 서버 @@ -546,9 +556,11 @@ edit_bookmarks_dialog.new = ì‹ ê·œ file_viewer.view_error_title = 보기 오류 file_viewer.view_error = 파ì¼ì„ ë³¼ 수 없습니다. file_viewer.file_menu = íŒŒì¼ +file_viewer.viewer_menu = ë·°ì–´ file_viewer.close = 닫기 file_viewer.large_file_warning = ì´ íŒŒì¼ì´ 너무 커서 ì´ ìž‘ì—…ì„ ìˆ˜í–‰í•  수 없습니다. file_viewer.open_anyway = 어쨌든 엽니다 +file_viewer.fullscreen = ì „ì²´ 화면 text_viewer.edit = 편집 text_viewer.copy = 복사 text_viewer.select_all = ëª¨ë‘ ì„ íƒ @@ -556,10 +568,33 @@ text_viewer.find = $[find] text_viewer.find_next = ë‹¤ìŒ ì°¾ê¸° text_viewer.find_previous = ì´ì „ 찾기 text_viewer.view = 보기 -text_viewer.line_wrap = 줄 바꿈 +text_viewer.animate_bracket_matching = 애니메ì´ì…˜ 대괄호 ì¼ì¹˜ +text_viewer.anti_aliasing = 엘리어싱 제거 +text_viewer.auto_indent = ìžë™ 들여쓰기 +text_viewer.binary_file_warning = ì´ì§„ 파ì¼ì¸ 것 같습니다 +text_viewer.bracket_matching = 대괄호 ì¼ì¹˜ +text_viewer.clear_whitespace_lines = 공백 줄 지우기 +text_viewer.code_folding = 코드 접기 +text_viewer.close_curly_braces = 중괄호 닫기 +text_viewer.close_markup_tags = 마í¬ì—… 태그 닫기 +text_viewer.drag_n_drop = ëŒì–´ì„œ 놓기 +text_viewer.eol_markers = 줄 ë 마커 +text_viewer.fade_current_line = 현재 ì„  ê°•ì¡° 표시 페ì´ë“œ +text_viewer.highlight_current_line = 현재 ì„  ê°•ì¡° 표시 text_viewer.line_numbers = 줄 번호 -text_viewer.binary_file_warning = ë°”ì´ë„ˆë¦¬ 파ì¼ì¸ 것 같습니다 +text_viewer.line_wrap = 줄 바꿈 +text_viewer.mark_occurrences = ë°œìƒ í‘œì‹œ +text_viewer.rounded_selection = 반올림 ì„ íƒ +text_viewer.show_matched_bracket_popup = ì¼ì¹˜í•˜ëŠ” 대괄호 íŒì—… 표시 +text_viewer.syntax_style = 구문 +text_viewer.tabs_emulated = 공백으로 ì—뮬레ì´íŠ¸ëœ íƒ­ +text_viewer.tab_lines = 탭 줄 +text_viewer.tab_size = 탭 í¬ê¸° +text_viewer.whitespace_visible = 공백 표시 +image_viewer.view_menu = $[text_viewer.view] image_viewer.controls_menu = 제어 +image_viewer.zoom_to_actual_size = 실제 í¬ê¸°ë¡œ 확대/축소 +image_viewer.zoom_to_fit = í¬ê¸°ì— 맞게 확대/축소 image_viewer.zoom_in = 확대 image_viewer.zoom_out = 축소 file_editor.edit_error_title = 편집 오류 @@ -568,25 +603,12 @@ file_editor.save = 저장 file_editor.save_as = 다름 ì´ë¦„으로 저장... file_editor.save_warning = 닫기 ì „ì— ì´ íŒŒì¼ì˜ 변경 ì‚¬í•­ì„ ì €ìž¥í•˜ì‹œê² ìŠµë‹ˆê¹Œ? file_editor.cannot_write = 파ì¼ì„ 쓸 수 없습니다. -file_editor.file_menu = $[file_viewer.file_menu] -file_editor.close = $[file_viewer.close] -file_editor.open_anyway = $[file_viewer.open_anyway] +file_editor.editor_menu = 편집기 text_editor.cut = 잘ë¼ë‚´ê¸° text_editor.paste = 붙여넣기 -text_editor.edit = $[text_viewer.edit] -text_editor.copy = $[text_viewer.copy] -text_editor.select_all = $[text_viewer.select_all] -text_editor.view = $[text_viewer.view] -text_editor.find = $[text_viewer.find] -text_editor.find_next = $[text_viewer.find_next] -text_editor.find_previous = $[text_viewer.find_previous] -text_editor.line_wrap = $[text_viewer.line_wrap] -text_editor.line_numbers = $[text_viewer.line_numbers] +text_editor.spaces_to_tabs = ê³µë°±ì„ íƒ­ìœ¼ë¡œ 바꾸기 +text_editor.tabs_to_spaces = íƒ­ì„ ê³µë°±ìœ¼ë¡œ 바꾸기 binary_viewer.name = ì´ì§„수 -binary_viewer.copy = $[text_viewer.copy] -binary_viewer.select_all = $[text_viewer.select_all] -binary_viewer.view = $[text_viewer.view] -binary_viewer.edit = $[text_viewer.edit] binary_viewer.code_type = 코드 유형 binary_viewer.code_type.binary = ì´ì§„수 binary_viewer.code_type.oct = OCT @@ -724,11 +746,12 @@ prefs_dialog.look_and_feel = 보기 ë° ëŠë‚Œ prefs_dialog.icons_size = ì•„ì´ì½˜ í¬ê¸° prefs_dialog.toolbar_icons = ë„구 ëª¨ìŒ prefs_dialog.command_bar_icons = 명령 표시줄 -prefs_dialog.file_icons = íŒŒì¼ í˜•ì‹ +prefs_dialog.file_icons = íŒŒì¼ ìœ í˜• prefs_dialog.use_system_file_icons = 시스템 íŒŒì¼ ì•„ì´ì½˜ 사용 prefs_dialog.use_system_file_icons.always = í•­ìƒ prefs_dialog.use_system_file_icons.never = 안함 prefs_dialog.use_system_file_icons.applications = ì‘ìš© 프로그램만 +prefs_dialog.use_system_file_icons.folders = í´ë”ë§Œ prefs_dialog.edit_current_theme = 현재 테마 편집... prefs_dialog.themes = 테마 prefs_dialog.import_theme = 테마 불러오기 @@ -755,6 +778,8 @@ prefs_dialog.confirm_on_quit = 종료 시 í™•ì¸ ëŒ€í™” ìƒìž 표시 prefs_dialog.shell = $[RunCommand.label] prefs_dialog.default_shell = 기본 시스템 ì…¸ 사용 prefs_dialog.custom_shell = ì‚¬ìš©ìž ì§€ì • ì…¸ 사용 +prefs_dialog.shell_encoding = ì…¸ ì¸ì½”딩 +prefs_dialog.auto_detect_shell_encoding = ìžë™ ê°ì§€ prefs_dialog.enable_bonjour_discovery = Bonjour 서비스 검색 사용 prefs_dialog.enable_system_notifications = 시스템 알림 사용 prefs_dialog.open_with_viewer_on_error = 열기 오류 ë°œìƒ ì‹œ 뷰어로 íŒŒì¼ ì—´ê¸° diff --git a/mucommander-translator/src/main/resources/dictionary_nb.properties b/mucommander-translator/src/main/resources/dictionary_nb.properties index aceadd2253..34197c8793 100644 --- a/mucommander-translator/src/main/resources/dictionary_nb.properties +++ b/mucommander-translator/src/main/resources/dictionary_nb.properties @@ -69,6 +69,7 @@ remove = Fjern details = Detaljer warning = Advarsel error = Feilmelding +view = Vis generic_error = En feil oppstod under utførelsen av valgte handling. folder_does_not_exist = Mappen finnes ikke eller er utilgjengelig. this_folder_does_not_exist = Mappen finnes ikke eller er utilgjengelig: {0} @@ -117,7 +118,6 @@ CheckForUpdates.label = Søk etter oppdateringer CompareFolders.label = Sammenlign mapper ConnectToServer.label = Koble til tjener ConnectToServer.tooltip = Koble til fjerntjener -View.label = Vis InternalView.label = Vis (intern) View.tooltip = Vis markert fil InternalEdit.label = Rediger (intern) diff --git a/mucommander-translator/src/main/resources/dictionary_nl.properties b/mucommander-translator/src/main/resources/dictionary_nl.properties index d8d77efb85..80be20bf06 100644 --- a/mucommander-translator/src/main/resources/dictionary_nl.properties +++ b/mucommander-translator/src/main/resources/dictionary_nl.properties @@ -70,6 +70,7 @@ remove = Verwijder details = Details warning = Waarschuwing error = Fout +view = Bekijken generic_error = Er heeft zich een fout voorgedaan bij het uitvoeren van de gevraagde taak. folder_does_not_exist = Map bestaat niet of is niet beschikbaar this_folder_does_not_exist = Deze map bestaat niet of is niet beschikbaar: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Zoeken naar updates CompareFolders.label = Vergelijk mappen ConnectToServer.label = Met server verbinden ConnectToServer.tooltip = Met server op afstand verbinden -View.label = Bekijken InternalView.label = Bekijken (intern) View.tooltip = Geselecteerd bestand bekijken InternalEdit.label = Bewerken (intern) diff --git a/mucommander-translator/src/main/resources/dictionary_pl.properties b/mucommander-translator/src/main/resources/dictionary_pl.properties index d88fd584a3..a72eba30e5 100644 --- a/mucommander-translator/src/main/resources/dictionary_pl.properties +++ b/mucommander-translator/src/main/resources/dictionary_pl.properties @@ -70,6 +70,7 @@ remove = UsuÅ„ details = Szczegóły warning = Uwaga error = Błąd +view = PodglÄ…d generic_error = WystÄ…piÅ‚ błąd podczas wykonywania operacji. folder_does_not_exist = Ten katalog nie istnieje lub jest nieosiÄ…galny. this_folder_does_not_exist = Ten katalog nie istnieje lub jest nieosiÄ…galny: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Sprawdź aktualizacje CompareFolders.label = Porównaj katalogi ConnectToServer.label = Połączenie z serwerem ConnectToServer.tooltip = Podłącz do zdalnego serwera -View.label = PodglÄ…d InternalView.label = PodglÄ…d (wewnÄ™trzny) View.tooltip = Zobacz wybrany plik InternalEdit.label = Edycja (wewnÄ™trzny) @@ -444,7 +444,28 @@ text_viewer.select_all = Zaznacz wszystko text_viewer.find = Znajdź text_viewer.find_next = Znajdź nastÄ™pne text_viewer.find_previous = Znajdź poprzednie +text_viewer.animate_bracket_matching = Animowane dopasowane nawiasy +text_viewer.anti_aliasing = Antyaliasing +text_viewer.auto_indent = Autoindentacja text_viewer.binary_file_warning = WyglÄ…da że jest to plik binarny nie tekstowy +text_viewer.bracket_matching = Dopasowywanie nawiasów +text_viewer.clear_whitespace_lines = Czyszczenie linii z biaÅ‚ymi znakami +text_viewer.close_curly_braces = Domykanie nawiasów +text_viewer.close_markup_tags = Domykanie tagów +text_viewer.code_folding = Zwijanie kodu +text_viewer.eol_markers = KoÅ„ce linii +text_viewer.fade_current_line = Rozmywanie podÅ›wietlenia linii +text_viewer.line_numbers = Numery linii +text_viewer.line_wrap = Zawijanie linii +text_viewer.highlight_current_line = PodÅ›wietlona aktualna linia +text_viewer.mark_occurrences = Zaznaczaj wystÄ…pienia +text_viewer.rounded_selection = ZaokrÄ…glaj zaznaczenie +text_viewer.show_matched_bracket_popup = Pokazuj dopasowany nawias +text_viewer.syntax_style = SkÅ‚adnia +text_viewer.tabs_emulated = Taby emulowane spacjami +text_viewer.tab_lines = Linie Tabulacji +text_viewer.tab_size = Wielkosć Tabulacji +text_viewer.whitespace_visible = BiaÅ‚e znaki widoczne image_viewer.controls_menu = Sterowanie image_viewer.zoom_in = PowiÄ™ksz image_viewer.zoom_out = Pomniejsz @@ -454,8 +475,11 @@ file_editor.save = Zapisz file_editor.save_as = Zapisz jako... file_editor.save_warning = Zapisać zmiany przed zamkniÄ™ciem ? file_editor.cannot_write = Nie mogÄ™ zapisać pliku. -text_editor.cut = Wytnij -text_editor.paste = Wklej +text_editor.spaces_to_tabs = ZamieÅ„ spacje na tabulacje +text_editor.syntax_style = $[text_viewer.syntax_style] +text_editor.tabs_to_spaces = ZamieÅ„ tabulacje na spacje +text_editor.undo = Confnij +text_editor.redo = Ponów shortcuts_dialog.quick_search.start_search = Wpisz dowolne znaki aby rozpocząć wyszukiwanie shortcuts_dialog.quick_search.cancel_search = Anuluj szybkie wyszukiwanie shortcuts_dialog.quick_search.remove_last_char = UsuÅ„ ostatni znak z szybkiego wyszukiwania diff --git a/mucommander-translator/src/main/resources/dictionary_pt_BR.properties b/mucommander-translator/src/main/resources/dictionary_pt_BR.properties index 64648feaae..ae218f5fa1 100644 --- a/mucommander-translator/src/main/resources/dictionary_pt_BR.properties +++ b/mucommander-translator/src/main/resources/dictionary_pt_BR.properties @@ -70,6 +70,7 @@ remove = Remover details = Detalhes warning = Alerta error = Erro +view = Ver generic_error = Ocorreu um erro durante a operação folder_does_not_exist = Diretório inexistente ou não disponível this_folder_does_not_exist = Este diretório não existe ou não está disponível: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Checar atualizações CompareFolders.label = Comparar diretórios ConnectToServer.label = Conectar ao servidor ConnectToServer.tooltip = Conectar ao servidor remoto -View.label = Ver InternalView.label = Ver (interno) View.tooltip = Ver arquivo selecionado InternalEdit.label = Editar (interno) diff --git a/mucommander-translator/src/main/resources/dictionary_ro.properties b/mucommander-translator/src/main/resources/dictionary_ro.properties index bd577230db..f6f9bdbf53 100644 --- a/mucommander-translator/src/main/resources/dictionary_ro.properties +++ b/mucommander-translator/src/main/resources/dictionary_ro.properties @@ -70,6 +70,7 @@ remove = Elimină details = Detalii warning = Avertisment error = Eroare +view = Vezi generic_error = O eroare a apărut in timp ce executam operaÈ›iunea cerută folder_does_not_exist = Acest director nu există sau nu este disponibil. this_folder_does_not_exist = Acest director nu exista sau nu este disponibil: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Actualizează programul CompareFolders.label = Compară directoarele ConnectToServer.label = Conectare la un server ConnectToServer.tooltip = Conectare la un server la distanță -View.label = Vezi InternalView.label = Vizualizează (intern) View.tooltip = Vezi fiÈ™ierul selectat InternalEdit.label = Editează (internal) diff --git a/mucommander-translator/src/main/resources/dictionary_ru.properties b/mucommander-translator/src/main/resources/dictionary_ru.properties index 868a5026d8..98ae125f62 100644 --- a/mucommander-translator/src/main/resources/dictionary_ru.properties +++ b/mucommander-translator/src/main/resources/dictionary_ru.properties @@ -70,6 +70,7 @@ remove = Удалить details = Подробнее warning = Предупреждение error = Ошибка +view = ПроÑмотреть generic_error = При выполнении запрошенной операции возникла ошибка folder_does_not_exist = Каталог Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем не ÑущеÑтвует или недоÑтупен this_folder_does_not_exist = Каталог {0} не ÑущеÑтвует или недоÑтупен @@ -118,7 +119,6 @@ CheckForUpdates.label = Проверить Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ CompareFolders.label = Сравнить каталоги ConnectToServer.label = Соединение Ñ Ñервером ConnectToServer.tooltip = СоединитьÑÑ Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð½Ñ‹Ð¼ Ñервером -View.label = ПроÑмотреть InternalView.label = ПроÑмотр (вÑтроенным) View.tooltip = ПроÑмотр выбранного файла InternalEdit.label = Редактировать (вÑтроенным) @@ -775,10 +775,7 @@ text_editor.edit = $[text_viewer.edit] text_editor.find = $[text_viewer.find] text_editor.find_next = $[text_viewer.find_next] text_editor.find_previous = $[text_viewer.find_previous] -text_editor.line_numbers = $[text_viewer.line_numbers] -text_editor.line_wrap = $[text_viewer.line_wrap] text_editor.select_all = $[text_viewer.select_all] -text_editor.view = $[text_viewer.view] theme_editor.quick_search = $[quick_search] ToggleHiddenFiles.label = $[prefs_dialog.show_hidden_files] ToggleSinglePanel.label = Переключить предÑтавление на одну панель diff --git a/mucommander-translator/src/main/resources/dictionary_sk.properties b/mucommander-translator/src/main/resources/dictionary_sk.properties index 82b8235f52..6ca64a8ac2 100644 --- a/mucommander-translator/src/main/resources/dictionary_sk.properties +++ b/mucommander-translator/src/main/resources/dictionary_sk.properties @@ -70,6 +70,7 @@ remove = OdstrániÅ¥ details = Detaily warning = Upozornenie error = Chyba +view = ZobraziÅ¥ generic_error = Pri požadovanej operácii sa vyskytla chyba. folder_does_not_exist = Tento prieÄinok neexistuje, alebo nie je k dispozícii. this_folder_does_not_exist = Tento prieÄinok neexistuje, alebo nie je k dispozícii: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Kontrola aktualizácii CompareFolders.label = PorovnaÅ¥ prieÄinky ConnectToServer.label = PripojiÅ¥ na server ConnectToServer.tooltip = PripojiÅ¥ na vzdialený server -View.label = ZobraziÅ¥ InternalView.label = ZobraziÅ¥ (interne) View.tooltip = ZobraziÅ¥ oznaÄené súbory InternalEdit.label = UpraviÅ¥ (interne) diff --git a/mucommander-translator/src/main/resources/dictionary_sl.properties b/mucommander-translator/src/main/resources/dictionary_sl.properties index 32af5ab46e..b3657f67b1 100644 --- a/mucommander-translator/src/main/resources/dictionary_sl.properties +++ b/mucommander-translator/src/main/resources/dictionary_sl.properties @@ -64,6 +64,7 @@ this_operation_cannot_be_undone = Ta operacija ne more biti razveljavljena. remove = Odstrani warning = Opozorilo error = Napaka +view = Pogled generic_error = Med izvajanjem zahtevane operacije se je zgodila napaka. folder_does_not_exist = Ta mapa ne obstaja oz. ni dostopna. this_folder_does_not_exist = Mapa ne obstaja oz. ni dostopna: {0} @@ -110,7 +111,6 @@ CheckForUpdates.label = Nadgradnja programa CompareFolders.label = Primerjaj mapi ConnectToServer.label = Povezava s strežnikom ConnectToServer.tooltip = Poveži z oddaljenim strežnikom -View.label = Pogled View.tooltip = Poglej izbrano datoteko Edit.tooltip = Uredi izbrano datoteko Copy.tooltip = Kopiraj oznaÄene datoteke diff --git a/mucommander-translator/src/main/resources/dictionary_sv.properties b/mucommander-translator/src/main/resources/dictionary_sv.properties index 9bfa9d81ad..a8d117a1cc 100644 --- a/mucommander-translator/src/main/resources/dictionary_sv.properties +++ b/mucommander-translator/src/main/resources/dictionary_sv.properties @@ -70,6 +70,7 @@ remove = Ta bort details = Detaljer warning = Varning error = Fel +view = Visa generic_error = Ett fel uppstod när handlingen utfördes. folder_does_not_exist = Mappen finns inte eller är inte tillgänglig. this_folder_does_not_exist = Mappen finns inte eller är inte tillgänglig: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Sök uppdateringar CompareFolders.label = Jämför mappar ConnectToServer.label = Anslut till server ConnectToServer.tooltip = Anslut till fjärrserver -View.label = Visa InternalView.label = Visa (intern) View.tooltip = Visa markerad fil InternalEdit.label = Redigera (intern) diff --git a/mucommander-translator/src/main/resources/dictionary_tr.properties b/mucommander-translator/src/main/resources/dictionary_tr.properties index f81ea5f4c3..0a5b4653af 100644 --- a/mucommander-translator/src/main/resources/dictionary_tr.properties +++ b/mucommander-translator/src/main/resources/dictionary_tr.properties @@ -70,6 +70,7 @@ remove = Kaldır details = Ayrıntılar warning = Uyarı error = Hata +view = Görüntüle generic_error = İşlem sırasında bir hata oluÅŸtu. folder_does_not_exist = Dizin mevcut deÄŸil ya da kullanılamıyor. this_folder_does_not_exist = Dizin mevcut deÄŸil ya da kullanılamıyor: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = Güncellemeleri kontrol et CompareFolders.label = Dizinleri karşılaÅŸtır ConnectToServer.label = Sunucuya baÄŸlan ConnectToServer.tooltip = Uzak sunucuya baÄŸlan -View.label = Görüntüle InternalView.label = Görüntüle (dahili) View.tooltip = Seçilen dosyayı görüntüle InternalEdit.label = Düzenle (dahili) diff --git a/mucommander-translator/src/main/resources/dictionary_uk.properties b/mucommander-translator/src/main/resources/dictionary_uk.properties index 96c44f94af..aca670e026 100644 --- a/mucommander-translator/src/main/resources/dictionary_uk.properties +++ b/mucommander-translator/src/main/resources/dictionary_uk.properties @@ -71,6 +71,7 @@ remove = Видалити details = Детальніше warning = ÐŸÐ¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ error = Помилка +view = ПереглÑнути generic_error = При виконанні операції ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° folder_does_not_exist = Папка не Ñ–Ñнує або Ñ” недоÑтупною this_folder_does_not_exist = Папка {0} не Ñ–Ñнує або Ñ” недоÑтупною @@ -119,7 +120,6 @@ CheckForUpdates.label = Перевірити наÑвніÑть оновленн CompareFolders.label = ПорівнÑти папки ConnectToServer.label = З''єднатиÑÑ Ð· Ñервером ConnectToServer.tooltip = З''єднатиÑÑ Ð· віддаленим Ñервером -View.label = ПереглÑнути InternalView.label = ПереглÑд (вбудованим) View.tooltip = ПереглÑнути вибраний файл InternalEdit.label = Редагувати (вбудованим) diff --git a/mucommander-translator/src/main/resources/dictionary_zh_CN.properties b/mucommander-translator/src/main/resources/dictionary_zh_CN.properties index 8289fa0a90..088a35e724 100644 --- a/mucommander-translator/src/main/resources/dictionary_zh_CN.properties +++ b/mucommander-translator/src/main/resources/dictionary_zh_CN.properties @@ -70,6 +70,7 @@ remove = 移除 details = 详细 warning = 警告 error = 错误 +view = 查看 generic_error = å¤„ç†æŒ‡å®šæ“作时, å‘生错误. folder_does_not_exist = 文件夹ä¸å­˜åœ¨æˆ–无法使用. this_folder_does_not_exist = 文件夹ä¸å­˜åœ¨æˆ–无法使用: {0} @@ -118,7 +119,6 @@ CheckForUpdates.label = 检查更新 CompareFolders.label = 比较文件夹 ConnectToServer.label = 连接到æœåС噍 ConnectToServer.tooltip = 连接到远程æœåС噍 -View.label = 查看 InternalView.label = 查看 (内置) View.tooltip = 查看所选文件 InternalEdit.label = 编辑 (内置) diff --git a/mucommander-translator/src/main/resources/dictionary_zh_TW.properties b/mucommander-translator/src/main/resources/dictionary_zh_TW.properties index dfd4b82d61..90fb6da7fb 100644 --- a/mucommander-translator/src/main/resources/dictionary_zh_TW.properties +++ b/mucommander-translator/src/main/resources/dictionary_zh_TW.properties @@ -70,6 +70,7 @@ remove = 移除 details = 細節 warning = 警告 error = 錯誤 +view = 檢視 generic_error = 當進行指定æ“作時, 發生錯誤. folder_does_not_exist = 資料夾ä¸å­˜åœ¨æˆ–無法使用. this_folder_does_not_exist = 資料夾ä¸å­˜åœ¨æˆ–無法使用: {0} @@ -119,7 +120,6 @@ CheckForUpdates.label = 檢查更新版本 CompareFolders.label = 比較資料夾 ConnectToServer.label = 連接至伺æœå™¨ ConnectToServer.tooltip = 連接至é ç«¯ä¼ºæœå™¨ -View.label = 檢視 InternalView.label = 檢視 (內建) View.tooltip = 檢視已é¸å–檔案 InternalEdit.label = 編輯 (內建) diff --git a/mucommander-viewer-api/build.gradle b/mucommander-viewer-api/build.gradle index aaab375987..7630d746a9 100644 --- a/mucommander-viewer-api/build.gradle +++ b/mucommander-viewer-api/build.gradle @@ -4,6 +4,8 @@ dependencies { api project(':mucommander-commons-file') api project(':mucommander-commons-util') + compileOnly 'com.google.code.findbugs:jsr305:1.3.9' + testImplementation 'org.testng:testng:6.11' } @@ -20,5 +22,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/CloseCancelledException.java b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/CloseCancelledException.java index 3e1f721198..74295962d9 100644 --- a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/CloseCancelledException.java +++ b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/CloseCancelledException.java @@ -19,8 +19,6 @@ /** * This exception is thrown when file close is cancelled. - * - * @author Miroslav Hajda */ public class CloseCancelledException extends Exception { } diff --git a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/EditorPresenter.java b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/EditorPresenter.java index cd50042829..ac4e84008c 100644 --- a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/EditorPresenter.java +++ b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/EditorPresenter.java @@ -16,6 +16,8 @@ */ package com.mucommander.viewer; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import javax.swing.JFrame; /** @@ -23,6 +25,7 @@ * * @author Miroslav Hajda */ +@ParametersAreNonnullByDefault public interface EditorPresenter { /** @@ -38,27 +41,9 @@ public interface EditorPresenter { * * @return frame */ + @Nonnull JFrame getWindowFrame(); - /** - * TODO: Remove - * - * Reads fullscreen state - * - * @return full screen state - */ - boolean isFullScreen(); - - /** - * TODO: Remove - * - * Method to set fullscreen. - * - * @param fullScreen - * full screen state - */ - void setFullScreen(boolean fullScreen); - /** * Executes long operation. * diff --git a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileEditor.java b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileEditor.java index 9627942b23..a4f4e3180b 100644 --- a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileEditor.java +++ b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileEditor.java @@ -18,28 +18,32 @@ import com.mucommander.commons.file.AbstractFile; import java.io.IOException; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import javax.swing.JComponent; import javax.swing.JMenuBar; /** * Interface for file editor. - * - * @author Miroslav Hajda */ +@ParametersAreNonnullByDefault public interface FileEditor { /** * Opens a given AbstractFile for display. * - * @param file the file to be presented - * @throws IOException in case of an I/O problem + * @param file + * the file to be presented + * @throws IOException + * in case of an I/O problem */ void open(AbstractFile file) throws IOException; /** * Closes currently opened file. * - * @throws CloseCancelledException when cancelled + * @throws CloseCancelledException + * when cancelled */ void close() throws CloseCancelledException; @@ -48,19 +52,27 @@ public interface FileEditor { * * @return UI component instance */ + @Nonnull JComponent getUI(); /** * Sets presenter API. * - * @param presenter presenter API + * @param presenter + * presenter API */ void setPresenter(EditorPresenter presenter); /** * Extends provided menu with new menu items specific for this viewer. * - * @param menuBar menu bar + * @param menuBar + * menu bar */ void extendMenu(JMenuBar menuBar); + + /** + * Enables to customize focus handling + */ + default void requestFocus() {} } diff --git a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileEditorService.java b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileEditorService.java index 28a9cec939..2c8d411fab 100644 --- a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileEditorService.java +++ b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileEditorService.java @@ -17,12 +17,13 @@ package com.mucommander.viewer; import com.mucommander.commons.file.AbstractFile; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; /** * Interface for file editor service. - * - * @author Miroslav Hajda */ +@ParametersAreNonnullByDefault public interface FileEditorService { /** @@ -30,6 +31,7 @@ public interface FileEditorService { * * @return name title */ + @Nonnull String getName(); /** @@ -44,19 +46,18 @@ public interface FileEditorService { int getOrderPriority(); /** - * Returns true if this factory can create a file editor for - * the specified file. + * Returns true if this factory can create a file editor for the specified file. *

- * The FileEditor may base its decision strictly upon the file's name and - * its extension or may wish to read some of the file and compare it to a - * magic number. + * The FileEditor may base its decision strictly upon the file's name and its extension or may wish to read some of + * the file and compare it to a magic number. *

* - * @param file file for which a editor must be created. - * @return true if this factory can create a file editor for - * the specified file. - * @throws WarnUserException if the specified file can be edited after the - * warning message contained in the exception is displayed to the end user. + * @param file + * file for which a editor must be created. + * @return true if this factory can create a file editor for the specified file. + * @throws WarnUserException + * if the specified file can be edited after the warning message contained in the exception is displayed + * to the end user. */ boolean canEditFile(AbstractFile file) throws WarnUserException; @@ -65,5 +66,6 @@ public interface FileEditorService { * * @return a new instance of {@link FileEditor}. */ + @Nonnull FileEditor createFileEditor(); } diff --git a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileViewer.java b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileViewer.java index 6068a81424..6fb73b63f0 100644 --- a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileViewer.java +++ b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileViewer.java @@ -18,21 +18,24 @@ import com.mucommander.commons.file.AbstractFile; import java.io.IOException; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import javax.swing.JComponent; import javax.swing.JMenuBar; /** * Interface for file viewer. - * - * @author Miroslav Hajda */ +@ParametersAreNonnullByDefault public interface FileViewer { /** * Opens a given AbstractFile for display. * - * @param file the file to be presented - * @throws IOException in case of an I/O problem + * @param file + * the file to be presented + * @throws IOException + * in case of an I/O problem */ void open(AbstractFile file) throws IOException; @@ -46,19 +49,27 @@ public interface FileViewer { * * @return UI component instance */ + @Nonnull JComponent getUI(); /** * Sets presenter API. * - * @param presenter presenter API + * @param presenter + * presenter API */ void setPresenter(ViewerPresenter presenter); /** * Extends provided menu with new menu items specific for this viewer. * - * @param menuBar menu bar + * @param menuBar + * menu bar */ void extendMenu(JMenuBar menuBar); + + /** + * Enables to customize focus handling + */ + default void requestFocus() {} } diff --git a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileViewerService.java b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileViewerService.java index d16b7cea8d..8adec9dd72 100644 --- a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileViewerService.java +++ b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/FileViewerService.java @@ -17,12 +17,13 @@ package com.mucommander.viewer; import com.mucommander.commons.file.AbstractFile; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; /** * Interface for file viewer service. - * - * @author Miroslav Hajda */ +@ParametersAreNonnullByDefault public interface FileViewerService { /** @@ -30,6 +31,7 @@ public interface FileViewerService { * * @return name title */ + @Nonnull String getName(); /** @@ -45,19 +47,18 @@ public interface FileViewerService { int getOrderPriority(); /** - * Returns true if this factory can create a file viewer for - * the specified file. + * Returns true if this factory can create a file viewer for the specified file. *

- * The FileEditor may base its decision strictly upon the file's name and - * its extension or may wish to read some of the file and compare it to a - * magic number. + * The FileEditor may base its decision strictly upon the file's name and its extension or may wish to read some of + * the file and compare it to a magic number. *

* - * @param file file for which a viewer must be created. - * @return true if this factory can create a file viewer for - * the specified file. - * @throws WarnUserException if the specified file can be viewed after the - * warning message contained in the exception is displayed to the end user. + * @param file + * file for which a viewer must be created. + * @return true if this factory can create a file viewer for the specified file. + * @throws WarnUserException + * if the specified file can be viewed after the warning message contained in the exception is displayed + * to the end user. */ boolean canViewFile(AbstractFile file) throws WarnUserException; @@ -66,5 +67,6 @@ public interface FileViewerService { * * @return a new instance of {@link FileViewer}. */ + @Nonnull FileViewer createFileViewer(); } diff --git a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/ViewerPresenter.java b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/ViewerPresenter.java index 4dc7669ee2..c8b352f10b 100644 --- a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/ViewerPresenter.java +++ b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/ViewerPresenter.java @@ -18,14 +18,15 @@ import java.io.IOException; import java.util.function.Function; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; import javax.swing.JFrame; /** * Interface for viewer presenter. - * - * @author Miroslav Hajda */ +@ParametersAreNonnullByDefault public interface ViewerPresenter { /** @@ -41,6 +42,7 @@ public interface ViewerPresenter { * * @return frame */ + @Nonnull JFrame getWindowFrame(); /** @@ -55,25 +57,6 @@ public interface ViewerPresenter { */ void goToFile(Function advance, FileViewerService viewerService) throws IOException; - /** - * TODO: Remove - * - * Reads fullscreen state - * - * @return full screen state - */ - boolean isFullScreen(); - - /** - * TODO: Remove - * - * Method to set fullscreen. - * - * @param fullScreen - * full screen state - */ - void setFullScreen(boolean fullScreen); - /** * Executes long operation. * diff --git a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/WarnUserException.java b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/WarnUserException.java index 68291b34f4..c909ab117d 100644 --- a/mucommander-viewer-api/src/main/java/com/mucommander/viewer/WarnUserException.java +++ b/mucommander-viewer-api/src/main/java/com/mucommander/viewer/WarnUserException.java @@ -16,14 +16,16 @@ */ package com.mucommander.viewer; +import javax.annotation.ParametersAreNonnullByDefault; + /** - * This exception is thrown by {@link com.mucommander.ui.viewer.ViewerFactory} - * and {@link com.mucommander.ui.viewer.EditorFactory} when the user should be - * warned about something before going ahead with viewing/editing a file. - * {@link #getMessage()} contains the message to display to the user. + * This exception is thrown by {@link com.mucommander.ui.viewer.ViewerFactory} and + * {@link com.mucommander.ui.viewer.EditorFactory} when the user should be warned about something before going ahead + * with viewing/editing a file. {@link #getMessage()} contains the message to display to the user. * * @author Maxence Bernard */ +@ParametersAreNonnullByDefault public class WarnUserException extends Exception { public WarnUserException(String localizedMessage) { diff --git a/mucommander-viewer-binary/build.gradle b/mucommander-viewer-binary/build.gradle index 2fa120cf3f..9bd9820515 100644 --- a/mucommander-viewer-binary/build.gradle +++ b/mucommander-viewer-binary/build.gradle @@ -9,7 +9,7 @@ dependencies { api project(':mucommander-commons-file') api project(':mucommander-commons-util') // Version jsr305 3.0.2 conflicts with felix framework - implementation 'com.google.code.findbugs:jsr305:1.3.9' + compileOnly 'com.google.code.findbugs:jsr305:1.3.9' implementation('org.exbin.bined:bined-core:0.2.0') { exclude group: 'org.exbin.auxiliary', module: 'paged_data' @@ -37,5 +37,5 @@ jar { 'Implementation-Vendor': "Miroslav Hajda", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-viewer-image/build.gradle b/mucommander-viewer-image/build.gradle index 44795b6a69..de32797758 100644 --- a/mucommander-viewer-image/build.gradle +++ b/mucommander-viewer-image/build.gradle @@ -6,6 +6,8 @@ dependencies { api project(':mucommander-viewer-api') api project(':mucommander-translator') + compileOnly 'com.google.code.findbugs:jsr305:1.3.9' + testImplementation 'org.testng:testng:6.11' } @@ -23,5 +25,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/Activator.java b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/Activator.java index 9089049eff..4f1f153965 100644 --- a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/Activator.java +++ b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/Activator.java @@ -16,22 +16,25 @@ */ package com.mucommander.viewer.image; +import com.mucommander.snapshot.MuSnapshot; import com.mucommander.viewer.FileViewerService; +import javax.annotation.ParametersAreNonnullByDefault; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; /** * Activator for viewer for image files. - * - * @author Miroslav Hajda */ +@ParametersAreNonnullByDefault public class Activator implements BundleActivator { private ServiceRegistration viewerRegistration; @Override public void start(BundleContext context) throws Exception { + MuSnapshot.registerHandler(new ImageViewerSnapshot()); + viewerRegistration = context.registerService(FileViewerService.class, new ImageFileViewerService(), null); } diff --git a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageFileViewerService.java b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageFileViewerService.java index 89656e234a..999f9ed012 100644 --- a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageFileViewerService.java +++ b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageFileViewerService.java @@ -20,12 +20,15 @@ import com.mucommander.commons.file.filter.ExtensionFilenameFilter; import com.mucommander.viewer.FileViewerService; import com.mucommander.viewer.FileViewer; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; /** * FileViewerService implementation for creating image viewers. * * @author Nicolas Rinaudo */ +@ParametersAreNonnullByDefault public class ImageFileViewerService implements FileViewerService { /** @@ -34,10 +37,10 @@ public class ImageFileViewerService implements FileViewerService { private ExtensionFilenameFilter filter; public ImageFileViewerService() { - filter = new ExtensionFilenameFilter(new String[]{".png", ".gif", ".jpg", ".jpeg"}); - filter.setCaseSensitive(false); + filter = new ExtensionFilenameFilter(new String[]{".png", ".gif", ".jpg", ".jpeg", ".tif", ".tiff", ".bmp", ".wbmp"}, false, false); } + @Nonnull @Override public String getName() { return "Image"; @@ -58,6 +61,7 @@ public boolean canViewFile(AbstractFile file) { return filter.accept(file); } + @Nonnull @Override public FileViewer createFileViewer() { return new ImageViewer(this); diff --git a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewer.java b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewer.java index 881f8a83e4..2bab7d0c60 100644 --- a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewer.java +++ b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewer.java @@ -14,90 +14,282 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package com.mucommander.viewer.image; -import java.awt.Color; +import com.mucommander.commons.file.AbstractFile; +import com.mucommander.commons.io.StreamUtils; +import com.mucommander.commons.util.ui.dialog.DialogToolkit; +import com.mucommander.commons.util.ui.helper.MenuToolkit; +import com.mucommander.commons.util.ui.helper.MnemonicHelper; +import com.mucommander.text.Translator; +import com.mucommander.viewer.FileViewer; +import com.mucommander.viewer.ViewerPresenter; +import com.mucommander.viewer.image.ui.ImageStatusPanel; +import com.mucommander.viewer.image.ui.ImageViewerPanel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.ParametersAreNonnullByDefault; +import javax.swing.AbstractAction; +import javax.swing.ButtonGroup; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JScrollPane; +import javax.swing.JViewport; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.Dimension; -import java.awt.Graphics; import java.awt.Image; import java.awt.MediaTracker; +import java.awt.MouseInfo; +import java.awt.Point; +import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.InputEvent; import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; - -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JSeparator; -import javax.swing.KeyStroke; - -import com.mucommander.commons.file.AbstractFile; -import com.mucommander.commons.util.ui.helper.MenuToolkit; -import com.mucommander.commons.util.ui.helper.MnemonicHelper; -import com.mucommander.text.Translator; -import com.mucommander.ui.main.table.FileTable; -import com.mucommander.ui.theme.ColorChangedEvent; -import com.mucommander.ui.theme.FontChangedEvent; -import com.mucommander.ui.theme.Theme; -import com.mucommander.ui.theme.ThemeListener; -import com.mucommander.ui.theme.ThemeManager; -import com.mucommander.viewer.FileViewer; -import com.mucommander.viewer.ViewerPresenter; import java.util.function.Function; -import javax.swing.JComponent; -import javax.swing.JScrollPane; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** - * A simple image viewer, capable of displaying PNG, GIF and JPEG images. + * A simple image viewer, capable of displaying PNG, GIF and JPEG images. * * @author Maxence Bernard, Arik Hadas */ +@ParametersAreNonnullByDefault class ImageViewer implements FileViewer, ActionListener { + + private static final double ZOOM_RATE = 1.5; + private static final double MAX_ZOOM = Math.pow(ZOOM_RATE, 8); + private static final double MIN_ZOOM = Math.pow(ZOOM_RATE, -8); private static final Logger LOGGER = LoggerFactory.getLogger(ImageViewer.class); private ViewerPresenter presenter; - private JScrollPane ui = new JScrollPane(); - private Image image; - private Image scaledImage; - private double zoomFactor; - + private JPanel ui = new JPanel(new BorderLayout()); + private JScrollPane scrollPane = new JScrollPane(); + private ImageStatusPanel statusPanel = new ImageStatusPanel(); + + private InitialZoom initialZoom = InitialZoom.RESIZE_WINDOW; + private boolean firstZoomPerformed = false; + /** Menu bar */ // Menus // + private JMenu viewMenu; private JMenu controlsMenu; + private JMenu viewInitialZoomMenu; + // Items // private JMenuItem prevImageItem; private JMenuItem nextImageItem; + private JMenuItem zoomToActualSize; + private JMenuItem zoomToFit; private JMenuItem zoomInItem; private JMenuItem zoomOutItem; - - private ImageViewerImpl imageViewerImpl; + private JRadioButtonMenuItem viewAsNativeMenuItem; + private JRadioButtonMenuItem viewAsFitToViewMenuItem; + private JRadioButtonMenuItem viewAsResizeWindowMenuItem; + private AbstractAction viewStatusBarAction; + private JCheckBoxMenuItem viewStatusBarMenuItem; + + private ImageViewerPanel imageViewerPanel; private ImageFileViewerService imageFileViewerService; public ImageViewer(ImageFileViewerService imageFileViewerService) { this.imageFileViewerService = imageFileViewerService; - imageViewerImpl = new ImageViewerImpl(); - - ui.getViewport().setView(imageViewerImpl); - - // Create Go menu - MnemonicHelper menuMnemonicHelper = new MnemonicHelper(); - controlsMenu = MenuToolkit.addMenu(Translator.get("image_viewer.controls_menu"), menuMnemonicHelper, null); - nextImageItem = MenuToolkit.addMenuItem(controlsMenu, Translator.get("image_viewer.next_image"), menuMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), this); - prevImageItem = MenuToolkit.addMenuItem(controlsMenu, Translator.get("image_viewer.previous_image"), menuMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), this); - controlsMenu.add(new JSeparator()); - zoomInItem = MenuToolkit.addMenuItem(controlsMenu, Translator.get("image_viewer.zoom_in"), menuMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), this); - zoomOutItem = MenuToolkit.addMenuItem(controlsMenu, Translator.get("image_viewer.zoom_out"), menuMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), this); + imageViewerPanel = new ImageViewerPanel(); + ui.addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + if (firstZoomPerformed) { + return; + } + + if (ui.getWidth() > 0) { + initialZoom(); + firstZoomPerformed = true; + ui.removeComponentListener(this); + } + } + }); + + init(); + } + + private void init() { + ui.add(scrollPane, BorderLayout.CENTER); + scrollPane.setWheelScrollingEnabled(false); + scrollPane.getViewport().setView(imageViewerPanel); + + MouseAdapter mouseAdapter = new MouseAdapter() { + + private Point origin; + + @Override + public void mouseClicked(MouseEvent e) { + if (e.isControlDown()) { + if (e.getButton() == MouseEvent.BUTTON1) { + double zoomFactor = imageViewerPanel.getZoomFactor(); + zoom(Math.min(zoomFactor * ZOOM_RATE, MAX_ZOOM), e.getPoint()); + } else if (e.getButton() == MouseEvent.BUTTON3) { + double zoomFactor = imageViewerPanel.getZoomFactor(); + zoom(Math.max(zoomFactor / ZOOM_RATE, MIN_ZOOM), e.getPoint()); + } + } + } + + @Override + public void mousePressed(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + origin = new Point(e.getPoint()); + imageViewerPanel.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.getButton() == MouseEvent.BUTTON1) { + origin = null; + imageViewerPanel.setCursor(Cursor.getDefaultCursor()); + } + } + + @Override + public void mouseDragged(MouseEvent e) { + if (origin != null) { + JViewport viewPort = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, + imageViewerPanel); + if (viewPort != null) { + int deltaX = origin.x - e.getX(); + int deltaY = origin.y - e.getY(); + + Rectangle view = viewPort.getViewRect(); + view.x += deltaX; + view.y += deltaY; + + imageViewerPanel.scrollRectToVisible(view); + } + } + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + double rotation = e.getPreciseWheelRotation(); + if (rotation == 0) { + return; + } + + if (rotation > 0) { + double scaleDiff = rotation * ZOOM_RATE; + double zoomFactor = imageViewerPanel.getZoomFactor(); + zoom(Math.max(zoomFactor / scaleDiff, MIN_ZOOM), e.getPoint()); + } else { + double scaleDiff = (-rotation) * ZOOM_RATE; + double zoomFactor = imageViewerPanel.getZoomFactor(); + zoom(Math.min(zoomFactor * scaleDiff, MAX_ZOOM), e.getPoint()); + } + e.consume(); + } + }; + + imageViewerPanel.addMouseListener(mouseAdapter); + imageViewerPanel.addMouseMotionListener(mouseAdapter); + imageViewerPanel.addMouseWheelListener(mouseAdapter); + + MnemonicHelper menuMnemonicHelper = new MnemonicHelper(); + viewInitialZoomMenu = + MenuToolkit.addMenu(Translator.get("image_viewer.initial_zoom_menu"), menuMnemonicHelper, null); + viewAsNativeMenuItem = new JRadioButtonMenuItem(Translator.get("image_viewer.initial_zoom_as_native")); + viewAsNativeMenuItem.addActionListener(e -> switchInitialZoomMode(InitialZoom.NATIVE_SIZE)); + viewAsFitToViewMenuItem = new JRadioButtonMenuItem(Translator.get("image_viewer.initial_zoom_fit_to_view")); + viewAsFitToViewMenuItem.addActionListener(e -> switchInitialZoomMode(InitialZoom.FIT_TO_WINDOW)); + viewAsResizeWindowMenuItem = + new JRadioButtonMenuItem(Translator.get("image_viewer.initial_zoom_resize_window")); + viewAsResizeWindowMenuItem.addActionListener(e -> switchInitialZoomMode(InitialZoom.RESIZE_WINDOW)); + ButtonGroup viewAsButtonGroup = new ButtonGroup(); + viewAsButtonGroup.add(viewAsNativeMenuItem); + viewAsButtonGroup.add(viewAsFitToViewMenuItem); + viewAsButtonGroup.add(viewAsResizeWindowMenuItem); + viewInitialZoomMenu.add(viewAsNativeMenuItem); + viewInitialZoomMenu.add(viewAsFitToViewMenuItem); + viewInitialZoomMenu.add(viewAsResizeWindowMenuItem); + + viewMenu = MenuToolkit.addMenu(Translator.get("image_viewer.view_menu"), menuMnemonicHelper, null); + viewMenu.add(viewInitialZoomMenu); + zoomToActualSize = MenuToolkit.addMenuItem(viewMenu, + Translator.get("image_viewer.zoom_to_actual_size"), + menuMnemonicHelper, + KeyStroke.getKeyStroke(KeyEvent.VK_0, InputEvent.CTRL_DOWN_MASK), + this); + zoomToFit = MenuToolkit.addMenuItem(viewMenu, + Translator.get("image_viewer.zoom_to_fit"), + menuMnemonicHelper, + null, + this); + zoomInItem = MenuToolkit.addMenuItem(viewMenu, + Translator.get("image_viewer.zoom_in"), + menuMnemonicHelper, + KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0), + this); + zoomOutItem = MenuToolkit.addMenuItem(viewMenu, + Translator.get("image_viewer.zoom_out"), + menuMnemonicHelper, + KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0), + this); + viewMenu.addSeparator(); + viewStatusBarAction = new AbstractAction(Translator.get("image_viewer.view_status_bar")) { + @Override + public void actionPerformed(ActionEvent e) { + switchShowStatusBar(viewStatusBarMenuItem.isSelected()); + } + }; + viewStatusBarMenuItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, viewStatusBarAction, menuMnemonicHelper); + + controlsMenu = MenuToolkit.addMenu(Translator.get("image_viewer.controls_menu"), menuMnemonicHelper, null); + nextImageItem = MenuToolkit.addMenuItem(controlsMenu, + Translator.get("image_viewer.next_image"), + menuMnemonicHelper, + KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), + this); + prevImageItem = MenuToolkit.addMenuItem(controlsMenu, + Translator.get("image_viewer.previous_image"), + menuMnemonicHelper, + KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0), + this); + + String initialZoomValue = ImageViewerPreferences.INITIAL_ZOOM.getValue(); + if (InitialZoom.FIT_TO_WINDOW.getKey().equals(initialZoomValue)) { + viewAsFitToViewMenuItem.setSelected(true); + switchInitialZoomMode(InitialZoom.FIT_TO_WINDOW); + } else if (InitialZoom.RESIZE_WINDOW.getKey().equals(initialZoomValue)) { + viewAsResizeWindowMenuItem.setSelected(true); + switchInitialZoomMode(InitialZoom.RESIZE_WINDOW); + } else { + viewAsNativeMenuItem.setSelected(true); + switchInitialZoomMode(InitialZoom.NATIVE_SIZE); + } + boolean showStatusBar = Boolean.parseBoolean(ImageViewerPreferences.SHOW_STATUS_BAR.getValue()); + viewStatusBarMenuItem.setSelected(showStatusBar); + switchShowStatusBar(showStatusBar); } + @Nonnull @Override public JComponent getUI() { return ui; @@ -110,86 +302,129 @@ public void setPresenter(ViewerPresenter presenter) { @Override public void extendMenu(JMenuBar menuBar) { + menuBar.add(viewMenu); menuBar.add(controlsMenu); } private synchronized void loadImage(AbstractFile file) throws IOException { - presenter.getWindowFrame().setCursor(new Cursor(Cursor.WAIT_CURSOR)); - - int read; - byte buffer[] = new byte[1024]; - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - InputStream in = file.getInputStream(); - while ((read=in.read(buffer, 0, buffer.length))!=-1) - bout.write(buffer, 0, read); - - byte imageBytes[] = bout.toByteArray(); - bout.close(); - in.close(); - - this.scaledImage = null; - this.image = imageViewerImpl.getToolkit().createImage(imageBytes); + presenter.getWindowFrame().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + + Image image; + try (ByteArrayOutputStream bout = new ByteArrayOutputStream()) { + try (InputStream in = file.getInputStream()) { + StreamUtils.copyStream(in, bout); + image = imageViewerPanel.getToolkit().createImage(bout.toByteArray()); + } + } waitForImage(image); + imageViewerPanel.setImage(image); + initialZoom(); + } - int width = image.getWidth(null); - int height = image.getHeight(null); - this.zoomFactor = 1.0; - Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); + private void initialZoom() { + int imageWidth = imageViewerPanel.getImageWidth(); + int imageHeight = imageViewerPanel.getImageHeight(); + presenter.getWindowFrame().setCursor(Cursor.getDefaultCursor()); - while(width>d.width || height>d.height) { - width = width/2; - height = height/2; - zoomFactor = zoomFactor/2; + switch (initialZoom) { + case RESIZE_WINDOW: + // Fit to screen size / autozoom and resize window + double zoomFactor = 1; + Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); + while (imageWidth * zoomFactor > d.width || imageHeight * zoomFactor > d.height) { + zoomFactor = zoomFactor / ZOOM_RATE; + if (zoomFactor < MIN_ZOOM) { + zoomFactor = MIN_ZOOM; + break; + } + } + setZoomFactor(zoomFactor); + imageViewerPanel.setSize(imageViewerPanel.getPreferredSize()); + presenter.getWindowFrame().pack(); + DialogToolkit.centerOnScreen(presenter.getWindowFrame()); + break; + case FIT_TO_WINDOW: + zoomToFit(); + break; + default: + setZoomFactor(1.0); } - - if(zoomFactor==1.0) - this.scaledImage = image; - else - zoom(zoomFactor); - - checkZoom(); - presenter.getWindowFrame().setCursor(Cursor.getDefaultCursor()); + + ui.revalidate(); + ui.repaint(); + updateStatus(); } - private void waitForImage(Image image) { - //AppLogger.finest("Waiting for image to load "+image); - MediaTracker tracker = new MediaTracker(imageViewerImpl); + // AppLogger.finest("Waiting for image to load "+image); + MediaTracker tracker = new MediaTracker(imageViewerPanel); tracker.addImage(image, 0); - try { tracker.waitForID(0); } - catch(InterruptedException e) {} + try { + tracker.waitForID(0); + } catch (InterruptedException e) { + } tracker.removeImage(image); - //AppLogger.finest("Image loaded "+image); + // AppLogger.finest("Image loaded "+image); } - - - private synchronized void zoom(double factor) { - presenter.getWindowFrame().setCursor(new Cursor(Cursor.WAIT_CURSOR)); - this.scaledImage = image.getScaledInstance((int)(image.getWidth(null)*factor), (int)(image.getHeight(null)*factor), Image.SCALE_DEFAULT); - waitForImage(scaledImage); + private synchronized void zoom(double factor, @Nullable Point focusPoint) { + double zoomFactor = imageViewerPanel.getZoomFactor(); + if (factor == zoomFactor) { + return; + } - presenter.getWindowFrame().setCursor(Cursor.getDefaultCursor()); - } + JViewport viewPort = (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, imageViewerPanel); + Rectangle view; + Point targetViewportPos = new Point(); + if (viewPort != null) { + view = viewPort.getViewRect(); + if (focusPoint != null) { + int offsetX = focusPoint.x - view.x; + int offsetY = focusPoint.y - view.y; + targetViewportPos.x = (int) Math.round(focusPoint.x / zoomFactor * factor) - offsetX; + targetViewportPos.y = (int) Math.round(focusPoint.y / zoomFactor * factor) - offsetY; + } else { + // Focus center of the viewport instead + int offsetX = (view.width / 2); + int offsetY = (view.height / 2); + targetViewportPos.x = (int) Math.round((view.x + offsetX) / zoomFactor * factor) - offsetX; + targetViewportPos.y = (int) Math.round((view.y + offsetY) / zoomFactor * factor) - offsetY; + } + } - private void updateFrame() { - // Revalidate, pack and repaint should be called in this order - presenter.extendTitle(this.getTitleExt()); - imageViewerImpl.revalidate(); - // TODO Is this necessary? - presenter.getWindowFrame().pack(); - presenter.getWindowFrame().getContentPane().repaint(); + imageViewerPanel.setZoomFactor(factor); + + if (viewPort != null) { + imageViewerPanel.setSize(imageViewerPanel.getPreferredSize()); + scrollPane.getViewport().setViewPosition(targetViewportPos); + } else { + imageViewerPanel.revalidate(); + } + + ui.revalidate(); + ui.repaint(); + + updateStatus(); } - private void checkZoom() { - Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); - - zoomInItem.setEnabled(zoomFactor<1.0 || (2*zoomFactor*image.getWidth(null) < d.width - && 2*zoomFactor*image.getHeight(null) < d.height)); + private synchronized void setZoomFactor(double factor) { + imageViewerPanel.setZoomFactor(factor); + imageViewerPanel.revalidate(); - zoomOutItem.setEnabled(zoomFactor>1.0 || (zoomFactor/2*image.getWidth(null)>160 - && zoomFactor/2*image.getHeight(null)>120)); + ui.revalidate(); + ui.repaint(); + + updateStatus(); + } + + private void updateStatus() { + double zoomFactor = imageViewerPanel.getZoomFactor(); + presenter.extendTitle(this.getTitleExt()); + zoomInItem.setEnabled(zoomFactor < MAX_ZOOM); + zoomOutItem.setEnabled(zoomFactor > MIN_ZOOM); + statusPanel.setZoomFactor(zoomFactor); + statusPanel.setImageSize(imageViewerPanel.getImageWidth(), imageViewerPanel.getImageHeight()); } private void goToImage(Function advance) { @@ -211,90 +446,103 @@ public void open(AbstractFile file) throws IOException { @Override public void close() { + imageViewerPanel.close(); } + @Nonnull public String getTitleExt() { - return " - "+image.getWidth(null)+"x"+image.getHeight(null)+" - "+((int)(zoomFactor*100))+"%"; + double zoomFactor = imageViewerPanel.getZoomFactor(); + int imageWidth = imageViewerPanel.getImageWidth(); + int imageHeight = imageViewerPanel.getImageHeight(); + return " - " + imageWidth + "x" + imageHeight + " - " + ((int) (zoomFactor * 100)) + "%"; } /////////////////////////////////// // ActionListener implementation // /////////////////////////////////// + @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == prevImageItem) { goToImage(i -> i - 1); - } - else if (source == nextImageItem) { + } else if (source == nextImageItem) { goToImage(i -> i + 1); - } - else if (source == zoomInItem && zoomInItem.isEnabled()) { - zoomFactor = zoomFactor * 2; - zoom(zoomFactor); + } else if (source == zoomToActualSize) { + zoom(1, getMousePoint()); + } else if (source == zoomToFit) { + zoomToFit(); + } else if (source == zoomInItem && zoomInItem.isEnabled()) { + double zoomFactor = imageViewerPanel.getZoomFactor(); + zoom(Math.min(zoomFactor * ZOOM_RATE, MAX_ZOOM), getMousePoint()); } else if (source == zoomOutItem && zoomOutItem.isEnabled()) { - zoomFactor = zoomFactor / 2; - zoom(zoomFactor); - } else { - return; + double zoomFactor = imageViewerPanel.getZoomFactor(); + zoom(Math.max(zoomFactor / ZOOM_RATE, MIN_ZOOM), getMousePoint()); + } + } + + @Nullable + private Point getMousePoint() { + Point mousePoint = MouseInfo.getPointerInfo().getLocation(); + JViewport viewport = scrollPane.getViewport(); + SwingUtilities.convertPointFromScreen(mousePoint, viewport); + if (viewport.contains(mousePoint)) { + Point viewPosition = viewport.getViewPosition(); + return new Point(mousePoint.x + viewPosition.x, mousePoint.y + viewPosition.y); } - updateFrame(); - checkZoom(); + + return null; } - - private class ImageViewerImpl extends JPanel implements ThemeListener { - - private Color backgroundColor; - - ImageViewerImpl() { - backgroundColor = ThemeManager.getCurrentColor(Theme.EDITOR_BACKGROUND_COLOR); - ThemeManager.addCurrentThemeListener(this); - } - - //////////////////////// - // Overridden methods // - //////////////////////// - - @Override - public void paint(Graphics g) { - int width = getWidth(); - int height = getHeight(); - - g.setColor(backgroundColor); - g.fillRect(0, 0, width, height); - - if(scaledImage!=null) { - int imageWidth = scaledImage.getWidth(null); - int imageHeight = scaledImage.getHeight(null); - g.drawImage(scaledImage, Math.max(0, (width-imageWidth)/2), Math.max(0, (height-imageHeight)/2), null); + + private void switchInitialZoomMode(InitialZoom mode) { + initialZoom = mode; + ImageViewerPreferences.INITIAL_ZOOM.setValue(mode.key); + } + + private void switchShowStatusBar(boolean showStatusBar) { + if ((statusPanel.getParent() == ui) != showStatusBar) { + ImageViewerPreferences.SHOW_STATUS_BAR.setValue(Boolean.toString(showStatusBar)); + if (showStatusBar) { + ui.add(statusPanel, BorderLayout.SOUTH); + } else { + ui.remove(statusPanel); } + ui.revalidate(); + ui.repaint(); } - - @Override - public synchronized Dimension getPreferredSize() { - return new Dimension(scaledImage.getWidth(null), scaledImage.getHeight(null)); + } + + private void zoomToFit() { + JViewport viewport = scrollPane.getViewport(); + int imageWidth = imageViewerPanel.getImageWidth(); + int imageHeight = imageViewerPanel.getImageHeight(); + double zoomToWidth = (double) viewport.getWidth() / imageWidth; + double zoomToHeight = (double) viewport.getHeight() / imageHeight; + double zoom = Math.min(zoomToWidth, zoomToHeight); + if (zoom < MIN_ZOOM) { + zoom = MIN_ZOOM; } - - ////////////////////////////////// - // ThemeListener implementation // - ////////////////////////////////// - - /** - * Receives theme color changes notifications. - */ - @Override - public void colorChanged(ColorChangedEvent event) { - if(event.getColorId() == Theme.EDITOR_BACKGROUND_COLOR) { - backgroundColor = event.getColor(); - repaint(); - } + if (zoom > MAX_ZOOM) { + zoom = MAX_ZOOM; } + setZoomFactor(zoom); + } + + public enum InitialZoom { + NATIVE_SIZE("native"), + FIT_TO_WINDOW("fit_to_window"), + RESIZE_WINDOW("resize_window"); + + private String key; - /** - * Not used, implemented as a no-op. - */ - @Override - public void fontChanged(FontChangedEvent event) {} + InitialZoom(@Nonnull String key) { + this.key = key; + } + + @Nonnull + public String getKey() { + return key; + } } } diff --git a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewerPreferences.java b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewerPreferences.java new file mode 100644 index 0000000000..2cb9209f2d --- /dev/null +++ b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewerPreferences.java @@ -0,0 +1,60 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.viewer.image; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + +/** + * Image viewer preferences. + */ +@ParametersAreNonnullByDefault +public enum ImageViewerPreferences { + + INITIAL_ZOOM("initial_zoom", "image_viewer.initial_zoom_menu", "native"), + SHOW_STATUS_BAR("show_status_bar", "image_viewer.show_status_bar", Boolean.TRUE.toString()) + ; + + private String prefKey; + private String i18nKey; + private String value; + + ImageViewerPreferences(String prefKey, String i18nKey, String defaultValue) { + this.prefKey = prefKey; + this.i18nKey = i18nKey; + value = defaultValue; + } + + @Nonnull + public String getPrefKey() { + return prefKey; + } + + @Nonnull + public String getI18nKey() { + return i18nKey; + } + + @Nonnull + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewerSnapshot.java b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewerSnapshot.java new file mode 100644 index 0000000000..9ed42af6a8 --- /dev/null +++ b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ImageViewerSnapshot.java @@ -0,0 +1,38 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.viewer.image; + +import static com.mucommander.snapshot.MuSnapshot.FILE_PRESENTER_SECTION; + +import com.mucommander.snapshot.MuSnapshotable; + +/** + * Snapshot preferences for image viewer. + */ +public final class ImageViewerSnapshot extends MuSnapshotable { + /** + * Section describing information specific to image file presenter. + */ + public static final String IMAGE_FILE_PRESENTER_SECTION = FILE_PRESENTER_SECTION + "." + "image"; + + public ImageViewerSnapshot() { + super(ImageViewerPreferences::values, + ImageViewerPreferences::getValue, + ImageViewerPreferences::setValue, + pref -> pref.getPrefKey() != null ? IMAGE_FILE_PRESENTER_SECTION + "." + pref.getPrefKey() : null); + } +} diff --git a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ui/ImageStatusPanel.java b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ui/ImageStatusPanel.java new file mode 100644 index 0000000000..40bdcd4330 --- /dev/null +++ b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ui/ImageStatusPanel.java @@ -0,0 +1,85 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.viewer.image.ui; + +import javax.annotation.ParametersAreNonnullByDefault; + +import com.mucommander.text.Translator; + +/** + * Image viewer status panel. + */ +@ParametersAreNonnullByDefault +public class ImageStatusPanel extends javax.swing.JPanel { + + private javax.swing.JLabel imageSizeLabel; + private javax.swing.JLabel zoomLabel; + + public ImageStatusPanel() { + initComponents(); + } + + private void initComponents() { + imageSizeLabel = new javax.swing.JLabel(); + zoomLabel = new javax.swing.JLabel(); + + imageSizeLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + imageSizeLabel.setText("-"); + imageSizeLabel.setToolTipText(Translator.get("image_viewer.status.imageSizeLabel.toolTipText")); + imageSizeLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + zoomLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + zoomLabel.setText("-"); + zoomLabel.setToolTipText(Translator.get("image_viewer.status.zoomLabel.toolTipText")); + zoomLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, + layout.createSequentialGroup() + .addContainerGap(195, Short.MAX_VALUE) + .addComponent(zoomLabel, + javax.swing.GroupLayout.PREFERRED_SIZE, + 148, + javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(imageSizeLabel, + javax.swing.GroupLayout.PREFERRED_SIZE, + 168, + javax.swing.GroupLayout.PREFERRED_SIZE))); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(imageSizeLabel, + javax.swing.GroupLayout.DEFAULT_SIZE, + javax.swing.GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE) + .addComponent(zoomLabel, + javax.swing.GroupLayout.DEFAULT_SIZE, + javax.swing.GroupLayout.DEFAULT_SIZE, + Short.MAX_VALUE)); + } + + public void setZoomFactor(double zoomFactor) { + zoomLabel.setText((int) (zoomFactor * 100) + " %"); + } + + public void setImageSize(int imageWidth, int imageHeight) { + imageSizeLabel.setText(imageWidth + " x " + imageHeight); + } +} diff --git a/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ui/ImageViewerPanel.java b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ui/ImageViewerPanel.java new file mode 100644 index 0000000000..7f1f3d410b --- /dev/null +++ b/mucommander-viewer-image/src/main/java/com/mucommander/viewer/image/ui/ImageViewerPanel.java @@ -0,0 +1,189 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.viewer.image.ui; + +import com.mucommander.ui.theme.ColorChangedEvent; +import com.mucommander.ui.theme.FontChangedEvent; +import com.mucommander.ui.theme.Theme; +import com.mucommander.ui.theme.ThemeListener; +import com.mucommander.ui.theme.ThemeManager; + +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; +import javax.swing.JComponent; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.ImageObserver; + +/** + * Image viewer UI. + */ +@ParametersAreNonnullByDefault +public class ImageViewerPanel extends JComponent implements ThemeListener { + + private final ScallingImageObserver imageObserver = new ScallingImageObserver(); + private Image image; + private int imageWidth; + private int imageHeight; + private double zoomFactor; + private Color backgroundColor; + + public ImageViewerPanel() { + backgroundColor = ThemeManager.getCurrentColor(Theme.EDITOR_BACKGROUND_COLOR); + ThemeManager.addCurrentThemeListener(this); + } + + public double getZoomFactor() { + return zoomFactor; + } + + public void setZoomFactor(double zoomFactor) { + this.zoomFactor = zoomFactor; + } + + public int getImageWidth() { + return imageWidth; + } + + public int getImageHeight() { + return imageHeight; + } + + public void setImage(Image image) { + if (this.image != null) { + this.image.flush(); + } + this.image = image; + imageWidth = image.getWidth(null); + imageHeight = image.getHeight(null); + notifySizeChanged(); + } + + public void close() { + if (this.image != null) { + this.image.flush(); + } + } + + //////////////////////// + // Overridden methods // + //////////////////////// + + @Override + public void paint(Graphics g) { + int frameWidth = getWidth(); + int frameHeight = getHeight(); + + final int scaledWidth = getScaledX(imageWidth); + final int scaledHeight = getScaledY(imageHeight); + + final int offsetX = Math.max(0, (frameWidth - scaledWidth) / 2); + final int offsetY = Math.max(0, (frameHeight - scaledHeight) / 2); + g.drawImage(image, + offsetX, + offsetY, + offsetX + scaledWidth, + offsetY + scaledHeight, + 0, + 0, + imageWidth, + imageHeight, + backgroundColor, + imageObserver); + } + + @Nonnull + @Override + public synchronized Dimension getPreferredSize() { + return image == null ? new Dimension(320, 200) : new Dimension(getScaledX(imageWidth), getScaledY(imageHeight)); + } + + ////////////////////////////////// + // ThemeListener implementation // + ////////////////////////////////// + + /** + * Receives theme color changes notifications. + */ + @Override + public void colorChanged(ColorChangedEvent event) { + if (event.getColorId() == Theme.EDITOR_BACKGROUND_COLOR) { + backgroundColor = event.getColor(); + repaint(); + } + } + + /** + * Not used, implemented as a no-op. + */ + @Override + public void fontChanged(FontChangedEvent event) { + } + + private void notifySizeChanged() { + setSize(getPreferredSize()); + } + + private int getScaledX(int x) { + if (image == null) { + return 0; + } + return (int) (zoomFactor * x); + } + + private int getScaledY(int y) { + if (image == null) { + return 0; + } + return (int) (zoomFactor * y); + } + + private class ScallingImageObserver implements ImageObserver { + + @Override + public boolean imageUpdate(Image img, int infoFlags, int x, int y, int width, int height) { + // Update image size when changed during GIF animation + if ((infoFlags & ImageObserver.WIDTH) > 0) { + imageWidth = image.getWidth(null); + } + if ((infoFlags & ImageObserver.HEIGHT) > 0) { + imageHeight = image.getHeight(null); + } + if ((infoFlags & (ImageObserver.WIDTH + ImageObserver.HEIGHT)) > 0) { + notifySizeChanged(); + } + + // Notify image updated, but adjust affected position according to current zoom level + int frameWidth = getWidth(); + int frameHeight = getHeight(); + + final int scaledWidth = getScaledX(imageWidth); + final int scaledHeight = getScaledY(imageHeight); + + final int offsetX = Math.max(0, (frameWidth - scaledWidth) / 2); + final int offsetY = Math.max(0, (frameHeight - scaledHeight) / 2); + + int adjX = x + offsetX; + int adjY = y + offsetY; + int adjWidth = getScaledX((int) (width + zoomFactor + 1)) + offsetX; + int adjHeight = getScaledY((int) (height + zoomFactor + 1)) + offsetY; + return ImageViewerPanel.this.imageUpdate(img, infoFlags, adjX, adjY, adjWidth, adjHeight); + } + } +} diff --git a/mucommander-viewer-pdf/build.gradle b/mucommander-viewer-pdf/build.gradle index 4dd025157d..387bd976e6 100644 --- a/mucommander-viewer-pdf/build.gradle +++ b/mucommander-viewer-pdf/build.gradle @@ -3,44 +3,20 @@ dependencies { api project(':mucommander-viewer-api') api project(':mucommander-translator') - comprise group: 'com.levigo.jbig2', name: 'levigo-jbig2-imageio', version: '2.0' - comprise group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.57' - comprise group: 'org.bouncycastle', name: 'bcprov-ext-jdk15on', version: '1.57' - comprise group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.57' - comprise group: 'batik', name: 'batik-awt-util', version: '1.6' - comprise group: 'batik', name: 'batik-dom', version: '1.6' - comprise group: 'batik', name: 'batik-svg-dom', version: '1.6' - comprise group: 'batik', name: 'batik-svggen', version: '1.6' - comprise group: 'batik', name: 'batik-util', version: '1.6' - comprise group: 'batik', name: 'batik-xml', version: '1.6' - comprise group: 'batik', name: 'batik-gui-util', version: '1.6' - comprise group: 'batik', name: 'batik-css', version: '1.6' - comprise group: 'batik', name: 'batik-parser', version: '1.6' - comprise group: 'javax.media.jai', name: 'com.springsource.javax.media.jai.codec', version: '1.1.3' - comprise group: 'javax.media.jai', name: 'com.springsource.javax.media.jai.core', version: '1.1.3' - comprise group: 'org.jpedal', name: 'jpedal-lgpl', version: '4.74b27' - comprise group: 'org.apache.xmlcommons', name: 'com.springsource.org.apache.xmlcommons', version: '1.3.4' - comprise group: 'sax', name: 'sax', version: '2.0.1' - comprise files('libs/w3c.jar') + comprise 'com.github.pcorless.icepdf:icepdf-viewer:7.0.1' + comprise 'log4j:log4j:1.2.17' + comprise 'com.twelvemonkeys.imageio:imageio-psd:3.9.4' + comprise 'avalon-framework:avalon-framework:4.1.5' // Use JUnit test framework testImplementation 'junit:junit:4.12' } -repositories { - maven { - // for jpedal-lgpl - url 'https://clojars.org/repo' - } - maven { - // for jai.core and dai.codec - url 'https://maven.ceon.pl/artifactory/repo/' - } - mavenCentral() -} +repositories.mavenCentral() jar { - from configurations.comprise.collect { it.isDirectory() ? it : zipTree(it)} + bnd('-fixupmessages': '^Classes found in the wrong directory: .*') + from configurations.comprise.collect { it.isDirectory() ? it : zipTree(it) } duplicatesStrategy = DuplicatesStrategy.EXCLUDE bnd ('Bundle-Name': 'muCommander-viewer-pdf', 'Bundle-Vendor': 'muCommander', @@ -48,10 +24,12 @@ jar { 'Bundle-DocURL': 'https://www.mucommander.com', 'Export-Package': 'com.mucommander.viewer.pdf', 'Import-Package': - '!org.icepdf.core.pobjects.fonts.nfont,' + '!com.sun.*,' + - '!com.apple.*,' + '!javax.media.*,' + + '!com.ibm.uvm.tools,' + + '!magick,' + + '!com.inet.jortho,' + + '!org.apache.log.*,' + '*', 'Bundle-Activator': 'com.mucommander.viewer.pdf.Activator', 'Specification-Title': "muCommander", @@ -61,6 +39,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/Memento.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/Memento.java deleted file mode 100644 index f2b18d332b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/Memento.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core; - -/** - * Creates a memento containing a snapshot of the internal state. The state - * can be retreived when the restore method is called. This interface should - * be used by any object that plans to use the Caretaker implementation in the - * RI. - * - * @since 4.0 - */ -public interface Memento { - - /** - * Restore the state that was caputred when an instance of this object - * was created. - */ - public void restore(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/SecurityCallback.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/SecurityCallback.java deleted file mode 100644 index ab088ba68d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/SecurityCallback.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core; - -import org.icepdf.core.pobjects.Document; - -/** - * Security callback. - * An application that uses ICEpdf can provide it with the callback. - * This will allow the document class to ask an application for security related - * resources. - * - * @since 1.1 - */ -public interface SecurityCallback { - - /** - * This method is called when a security manager needs to receive a - * password for opening an encrypted PDF document. - * - * @param document document being opened. - * @return received password. - */ - public String requestPassword(Document document); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/application/ProductInfo.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/application/ProductInfo.java deleted file mode 100644 index 2e3f801dae..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/application/ProductInfo.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2006-2015 ICEsoft Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.application; - -public class ProductInfo { - - /** - * The company that owns this product. - */ - public static String COMPANY = "ICEsoft Technologies, Inc."; - - /** - * The name of the product. - */ - public static String PRODUCT = "ICEpdf"; - - /** - * The 3 levels of version identification, e.g. 1.0.0. - */ - public static String PRIMARY = "x"; - public static String SECONDARY = "x"; - public static String TERTIARY = "x"; - - /** - * The release type of the product (alpha, beta, production). - */ - public static String RELEASE_TYPE = "x"; - - /** - * The build number. Typically this would be tracked and maintained - * by the build system (i.e. Ant). - */ - public static String BUILD_NO = "x"; - - /** - * The revision number retrieved from the repository for this build. - * This is substitued automatically by subversion. - */ - public static String REVISION = "x"; - - /** - * Convenience method to get all the relevant product information. - * @return - */ - public String toString(){ - StringBuilder info = new StringBuilder(); - info.append( "\n" ); - info.append( COMPANY ); - info.append( "\n" ); - info.append( PRODUCT ); - info.append( " " ); - info.append( PRIMARY ); - info.append( "." ); - info.append( SECONDARY ); - info.append( "." ); - info.append( TERTIARY ); - info.append( " " ); - info.append( RELEASE_TYPE ); - info.append( "\n" ); - info.append( "Build number: " ); - info.append( BUILD_NO ); - info.append( "\n" ); - info.append( "Revision: " ); - info.append( REVISION ); - info.append( "\n" ); - return info.toString(); - } - - public String getVersion(){ - StringBuilder info = new StringBuilder(); - info.append( PRIMARY ); - info.append( "." ); - info.append( SECONDARY ); - info.append( "." ); - info.append( TERTIARY ); - info.append( " " ); - info.append( RELEASE_TYPE ); - return info.toString(); - } - - public static void main(String[] args) { - ProductInfo app = new ProductInfo(); - System.out.println( app.toString() ); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageImageEvent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageImageEvent.java deleted file mode 100644 index 7fc78e1154..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageImageEvent.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.events; - -import org.icepdf.core.pobjects.Page; - -/** - * PageImageEvent is fired when an image is done loading. The event stores - * the image number that was loaded and the total number of images. The total - * image is as specified by the parent page's resource dictionary and may not - * 100% reliable. It should also be noted that the total count also excludes - * inline images as the total inline images is only know after parsing is - * complete. - * - * @since 5.1.0 - */ -@SuppressWarnings("serial") -public class PageImageEvent extends PageInitializingEvent { - - private int index; - private int total; - private long duration; - - /** - * Construct a new PageImageEvent - * - * @param pageSource parent page. - * @param index index of image in the resource dictionary - * @param total total number of images to loaded. - * @param interrupted true if the image loading was interrupted in anyway. - */ - public PageImageEvent(Page pageSource, int index, int total, long duration, boolean interrupted) { - super(pageSource, interrupted); - this.index = index; - this.total = total; - this.duration = duration; - } - - /** - * The image index with respect to the total number of images. - * - * @return image index. - */ - public int getIndex() { - return index; - } - - /** - * The total number of images being loaded for the parent page. - * - * @return total number of images to load. - */ - public int getTotal() { - return total; - } - - public long getDuration() { - return duration; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageInitializingEvent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageInitializingEvent.java deleted file mode 100644 index 3fd210db0d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageInitializingEvent.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.events; - -/** - * The PageProcessingEvent event marks the start and end of all page level events. - * - * @since 5.1.0 - */ -@SuppressWarnings("serial") -public class PageInitializingEvent extends java.util.EventObject { - - private boolean interrupted; - - public PageInitializingEvent(Object source, boolean interrupted) { - super(source); - this.interrupted = interrupted; - } - - /** - * Indication if page processing was successful. - * - * @return true if processing event was successful otherwise false. - */ - public boolean isInterrupted() { - return interrupted; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageLoadingAdapter.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageLoadingAdapter.java deleted file mode 100644 index 6f116c9b49..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageLoadingAdapter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.events; - -/** - * Convenience adaptor for working with the PageProcessingListener interface. - * - * @since 5.1.0 - */ -public abstract class PageLoadingAdapter implements PageLoadingListener { - - public void pageLoadingStarted(PageLoadingEvent event) { - } - - public void pageInitializationStarted(PageInitializingEvent event) { - } - - public void pageInitializationEnded(PageInitializingEvent event) { - } - - public void pageImageLoaded(PageImageEvent event) { - } - - public void pagePaintingStarted(PagePaintingEvent event) { - } - - public void pagePaintingEnded(PagePaintingEvent event) { - } - - public void pageLoadingEnded(PageLoadingEvent event) { - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageLoadingEvent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageLoadingEvent.java deleted file mode 100644 index 94296dc633..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageLoadingEvent.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.events; - -import org.icepdf.core.pobjects.Page; - -/** - * PageLoadingEvent's are fired when page loading first starts and ends. It's - * the first and last event that will be sent to a listener. - * - * @since 5.1.0 - */ -@SuppressWarnings("serial") -public class PageLoadingEvent extends PageInitializingEvent { - - private int contentStreamCount; - private int imageResourceCount; - - public PageLoadingEvent(Page pageSource, int contentStreamCount, int imageResourceCount) { - super(pageSource, false); - this.contentStreamCount = contentStreamCount; - this.imageResourceCount = imageResourceCount; - } - - public PageLoadingEvent(Page pageSource, boolean interrupted) { - super(pageSource, interrupted); - } - - /** - * @return - */ - public int getContentStreamCount() { - return contentStreamCount; - } - - /** - * @return - */ - public int getImageResourceCount() { - return imageResourceCount; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageLoadingListener.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageLoadingListener.java deleted file mode 100644 index 1871ddf6eb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PageLoadingListener.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.events; - -/** - * The PageProcessingListener can be used to listen for a variety of Page - * level vents pertaining to the loading of the PDF page. The hierarchy - * and ordering of the events is as follows. PageImageEvent can happen at any - * point between the PageLoadingEvent. - *

- *

    - *
  • pageLoadingStarted(v event);
  • - *
      - *
    • pageInitializationStarted(PageProcessingEvent event);
    • - *
        - *
      • pageImageLoaded(PageImageEvent event)
      • - *
      - *
    • pageInitializationEnded(PageProcessingEvent event)
    • - *
    • pagePaintingStarted(PagePaintingEvent event)
    • - *
        - *
      • pageImageLoaded(PageImageEvent event)
      • - *
      - *
    • pagePaintingEnded(PagePaintingEvent event)
    • - *
    - *
  • pageLoadingEnded(PageLoadingEvent event)
  • - *
- * - * @since 5.1.0 - */ -public interface PageLoadingListener { - - /** - * Page loading has started. PageLoadingEvent can be used to get the total - * number content streams and image streams that will be parsed. - * - * @param event PageLoadingEvent is fired populated with data. - */ - public void pageLoadingStarted(PageLoadingEvent event); - - /** - * Page initialization has started which is the parsing of the Page's - * content stream. - * - * @param event PageProcessingEvent with data set to false. - */ - public void pageInitializationStarted(PageInitializingEvent event); - - /** - * Page initialization has be ended via successful parse or an interrupt - * exception. The PageProcessingEvent can be used to determine if the - * page was successfully parsed. - * - * @param event PageProcessingEvent can be used to see if page was - * successfully parsed or was interrupted. - */ - public void pageInitializationEnded(PageInitializingEvent event); - - /** - * A pages images has been parsed. The PageImageEvent can be used to find out - * if the parse was successful, image index and total number of images associated - * with the page. - * - * @param event PageImageEvent - */ - public void pageImageLoaded(PageImageEvent event); - - /** - * Page painting has begun. The PagePaintingEvent can be used to find out - * the number of shapes being painted. - * - * @param event PagePaintingEvent - */ - public void pagePaintingStarted(PagePaintingEvent event); - - /** - * Page painting has stopped. Teh PagePaintingEvent can be used to find out - * if the paint was completed or if there was an interrupt. - * - * @param event PagePaintingEvent - */ - public void pagePaintingEnded(PagePaintingEvent event); - - /** - * Page loading has completed and all images have been loaded, no further - * page processing will take place. - * - * @param event PageLoadingEvent - */ - public void pageLoadingEnded(PageLoadingEvent event); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PagePaintingEvent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PagePaintingEvent.java deleted file mode 100644 index 7e90ae83a1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PagePaintingEvent.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.events; - -import org.icepdf.core.pobjects.Page; - -/** - * PagePaintingEvent are fired when page painting starts and ends. The start - * event will indicate the number of shapes that will be painted. - * - * @since 5.1.0 - */ -@SuppressWarnings("serial") -public class PagePaintingEvent extends PageInitializingEvent { - - private int shapesCount; - - public PagePaintingEvent(Page pageSource, int shapesCount) { - super(pageSource, false); - this.shapesCount = shapesCount; - } - - public PagePaintingEvent(Page pageSource, boolean interrupted) { - super(pageSource, interrupted); - } - - public int getShapesCount() { - return shapesCount; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PaintPageEvent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PaintPageEvent.java deleted file mode 100644 index 54cbd2188b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PaintPageEvent.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.events; - -import org.icepdf.core.pobjects.Page; - -/** - * Paint Page event is generated from the Shapes class to let a viewer - * application know of a good time to paint the respective page. - * - * @since 2.5 - */ -@SuppressWarnings("serial") -public class PaintPageEvent extends java.util.EventObject { - - - public PaintPageEvent(Page pageSource) { - super(pageSource); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PaintPageListener.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PaintPageListener.java deleted file mode 100644 index 6b8be1b9d9..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/events/PaintPageListener.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.events; - -/** - * Listener for PaintPageEvents. Call is used ot mark a good time to - * paint the page. - * - * @since 2.5 - */ -public interface PaintPageListener extends java.util.EventListener { - - /** - * Invoked when it is a good time to paint a page. - * - * @param event paint event containg page information - */ - public void paintPage(PaintPageEvent event); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/exceptions/PDFException.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/exceptions/PDFException.java deleted file mode 100644 index af16827f9c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/exceptions/PDFException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.exceptions; - -/** - * Signals that a PDF exception has occurred. - * - * @since 1.0 - */ -@SuppressWarnings("serial") -public class PDFException extends Exception { - /** - * Constructs an instance of PDFException with the specified detail message. - * - * @param msg the detail message - */ - public PDFException(String msg) { - super(msg); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/exceptions/PDFSecurityException.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/exceptions/PDFSecurityException.java deleted file mode 100644 index a921721974..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/exceptions/PDFSecurityException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.exceptions; - -/** - * Signals that a PDF Security Exception has occurred. - * - * @since 1.0 - */ -@SuppressWarnings("serial") -public class PDFSecurityException extends Exception { - /** - * Constructs an instance of PDFException with the specified detail message. - * - * @param msg the detail message - */ - public PDFSecurityException(String msg) { - super(msg); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/BitStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/BitStream.java deleted file mode 100644 index 53d99b42f0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/BitStream.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * The class BitStream is designed to convert an input stream of - * bytes into bits. A BitStream is primarily used when bit - * manipulation of stream needed, such as when bit data is needed for encoding - * a image. - * - * @since 1.0 - */ -public class BitStream { - - // Input stream - InputStream in; - // Output stream - OutputStream out; - // bits left in stream - int bits; - // number of bits left in a byte - int bits_left; - boolean readEOF; - - // making value - private static final int masks[] = new int[32]; - - static { - for (int i = 0; i < 32; i++) { - masks[i] = ((1 << i) - 1); - } - } - - /** - * Create a new instance of a BitStream from the given - * input stream. - * - * @param i input stream to create a bit stream from. - */ - public BitStream(InputStream i) { - in = i; - bits = 0; - bits_left = 0; - readEOF = false; - } - - /** - * Create a new instance of a BitStream from the given - * output stream. - * - * @param o output stream to create a bit stream from. - */ - public BitStream(OutputStream o) { - out = o; - bits = 0; - bits_left = 0; - readEOF = false; - } - - /** - * Close all streams data associated with this object - * - * @throws IOException error closing stream - */ - public void close() throws IOException { - - // clean up the streams. - if (in != null) { - in.close(); - } - if (out != null) { - out.flush(); - out.close(); - } - } - - /** - * @param count - * @return - * @throws java.io.IOException - */ - public int getBits(int count) throws IOException { - if (count < 32) { - while (bits_left < count) { - int r = in.read(); - if (r < 0) { - readEOF = true; - break; - } - bits <<= 8; - bits |= (r & 0xFF); - bits_left += 8; - } - bits_left -= count; - return (bits >> bits_left) & masks[count]; - } else if (count == 32) { - return (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); - } - return 0; - } - - public boolean atEndOfFile() { - return readEOF && (bits_left <= 0); - } - - /** - * @param i - * @throws java.io.IOException - */ - public void putBit(int i) throws IOException { - bits <<= 1; - bits |= i; - bits_left++; - if (bits_left == 8) { - out.write(bits); - bits = 0; - bits_left = 0; - } - } - - /** - * @param i - * @param len - * @throws java.io.IOException - */ - public void putRunBits(int i, int len) throws IOException { - for (int j = len - 1; j >= 0; ) { - if (bits_left != 0 || j < 8) { - putBit(i); - j--; - } else { - if (i == 0) - out.write(0x00); - else - out.write(0xFF); - j -= 8; - } - } - } - - /** - * @return - * @throws java.io.IOException - */ - public int available() throws IOException { - if (bits_left == 0 && in.available() <= 0) - return 0; - return 1; - } - - /** - * @throws java.io.IOException - */ - public void skipByte() throws IOException { - bits_left = 0; - bits = 0; - } -} - - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/BufferedMarkedInputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/BufferedMarkedInputStream.java deleted file mode 100644 index d7c1d5dbd4..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/BufferedMarkedInputStream.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * BufferedMarkedInputStream extends BufferedInputStream and keeps count for the - * total number bytes read between buffer fills. This class is used by the - * linearTraversal loading mechanism so that the byte offset of found objects - * can be stored. The offset is then used to correct the cross reference - * table object offset. - * - * @since 5.0 - */ -public class BufferedMarkedInputStream extends BufferedInputStream { - - private int fillCount; - - public BufferedMarkedInputStream(InputStream in) { - super(in); - } - - public BufferedMarkedInputStream(InputStream in, int size) { - super(in, size); - } - - public int getMarkedPosition() { - return fillCount; - } - - @Override - public int read() throws IOException { - fillCount++; - return super.read(); - } - - @Override - public synchronized void reset() throws IOException { - if (markpos > 0) - fillCount -= (pos - markpos); - super.reset(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/ByteDoubleArrayInputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/ByteDoubleArrayInputStream.java deleted file mode 100644 index f160110e13..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/ByteDoubleArrayInputStream.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.io; - -import java.io.IOException; -import java.io.InputStream; - -/** - * This InputStream implementation allows an array of byte[]'s to be - * read. - * - * @since 5.0 - */ -public class ByteDoubleArrayInputStream extends InputStream { - - /** - * An array of bytes that was provided - * by the creator of the stream. Elements buf[0] - * through buf[count-1] are the - * only bytes that can ever be read from the - * stream; element buf[pos] is - * the next byte to be read. - */ - protected byte buf[][]; - - protected int bufOffset[]; - - /** - * The index of the next character to read from the input stream buffer. - * This value should always be nonnegative - * and not larger than the value of count. - * The next byte to be read from the input stream buffer - * will be buf[pos]. - */ - protected int pos; - - protected int posIndex; - - /** - * The currently marked position in the stream. - * ByteArrayInputStream objects are marked at position zero by - * default when constructed. They may be marked at another - * position within the buffer by the mark() method. - * The current buffer position is set to this point by the - * reset() method. - *

- * If no mark has been set, then the value of mark is the offset - * passed to the constructor (or 0 if the offset was not supplied). - * - * @since JDK1.1 - */ - protected int mark = 0; - protected int markIndex = 0; - - /** - * The index one greater than the last valid character in the input - * stream buffer. - * This value should always be nonnegative - * and not larger than the length of buf. - * It is one greater than the position of - * the last byte within buf that - * can ever be read from the input stream buffer. - */ - protected int count; - - /** - * Creates a ByteArrayInputStream - * so that it uses buf as its - * buffer array. - * The buffer array is not copied. - * The initial value of pos - * is 0 and the initial value - * of count is the length of - * buf. - * - * @param buf the input buffer. - */ - public ByteDoubleArrayInputStream(byte buf[][]) { - this.buf = buf; - this.pos = 0; - this.posIndex = 0; - bufOffset = new int[buf.length]; - for (int i = 0; i < buf.length; i++) { - bufOffset[i] = this.count; - this.count += buf[i].length; - } - } - - /** - * Reads the next byte of data from this input stream. The value - * byte is returned as an int in the range - * 0 to 255. If no byte is available - * because the end of the stream has been reached, the value - * -1 is returned. - *

- * This read method - * cannot block. - * - * @return the next byte of data, or -1 if the end of the - * stream has been reached. - */ - public synchronized int read() { - float posOffset = bufOffset[posIndex] + pos; - if (posOffset < count) { - if (posOffset < bufOffset[posIndex] + buf[posIndex].length) { - return (buf[posIndex][pos++] & 0xff); - } else { - posIndex++; - pos = 0; - return (buf[posIndex][pos++] & 0xff); - } - } else { - return -1; - } - } - - /** - * Reads up to len bytes of data into an array of bytes - * from this input stream. - * If pos equals count, - * then -1 is returned to indicate - * end of file. Otherwise, the number k - * of bytes read is equal to the smaller of - * len and count-pos. - * If k is positive, then bytes - * buf[pos] through buf[pos+k-1] - * are copied into b[off] through - * b[off+k-1] in the manner performed - * by System.arraycopy. The - * value k is added into pos - * and k is returned. - *

- * This read method cannot block. - * - * @param b the buffer into which the data is read. - * @param off the start offset of the data. - * @param len the maximum number of bytes read. - * @return the total number of bytes read into the buffer, or - * -1 if there is no more data because the end of - * the stream has been reached. - */ - public synchronized int read(byte b[], int off, int len) { - if (b == null) { - throw new NullPointerException(); - } else if ((off < 0) || (off > b.length) || (len < 0) || - ((off + len) > b.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } - if (posIndex >= buf.length) { - return -1; - } - - int posOffset = bufOffset[posIndex] + pos; - if (posOffset >= count) { - return -1; - } - if (posOffset + len > count) { - len = count - posOffset; - } - if (len <= 0) { - return 0; - } - // check if the current posIndex can handle the len copy - if (pos + len < buf[posIndex].length) { - System.arraycopy(buf[posIndex], pos, b, off, len); - pos += len; - } else { - // we need to copy to the end of the current posIndex and then move to the next array - int newLength = len; - int partialOffset = buf[posIndex].length - pos; - while (newLength > 0) { - System.arraycopy(buf[posIndex], pos, b, off, partialOffset); - off += partialOffset; - newLength -= partialOffset; - pos += partialOffset; - if (newLength == 0) { - break; - } - // setup the next buffer - posIndex++; - pos = 0; - if (pos + newLength < buf[posIndex].length) { - partialOffset = newLength; - } else { - partialOffset = buf[posIndex].length - pos; - } - } - } - return len; - } - - /** - * Skips n bytes of input from this input stream. Fewer - * bytes might be skipped if the end of the input stream is reached. - * The actual number k - * of bytes to be skipped is equal to the smaller - * of n and count-pos. - * The value k is added into pos - * and k is returned. - * - * @param n the number of bytes to be skipped. - * @return the actual number of bytes skipped. - */ - public synchronized long skip(long n) { - if (pos + n > count) { - n = count - pos; - } - if (n < 0) { - return 0; - } - if (pos + n < bufOffset[posIndex]) { - pos += n; - } else { - long partialOffset = (bufOffset[posIndex] - pos); - while (n > 0) { - n -= partialOffset; - posIndex++; - if (pos + n < bufOffset[posIndex]) { - partialOffset = n; - } else { - partialOffset = (bufOffset[posIndex] - pos); - } - } - } - return n; - } - - /** - * Returns the number of bytes that can be read from this input - * stream without blocking. - * The value returned is - * count - pos, - * which is the number of bytes remaining to be read from the input buffer. - * - * @return the number of bytes that can be read from the input stream - * without blocking. - */ - public synchronized int available() { - return count - (bufOffset[posIndex] + pos); - } - - /** - * Tests if this InputStream supports mark/reset. The - * markSupported method of ByteArrayInputStream - * always returns true. - */ - public boolean markSupported() { - return true; - } - - /** - * Set the current marked position in the stream. - * ByteArrayInputStream objects are marked at position zero by - * default when constructed. They may be marked at another - * position within the buffer by this method. - *

- * If no mark has been set, then the value of the mark is the - * offset passed to the constructor (or 0 if the offset was not - * supplied). - *

- *

Note: The readAheadLimit for this class - * has no meaning. - */ - public void mark(int readAheadLimit) { - mark = pos; - markIndex = posIndex; - } - - /** - * Resets the buffer to the marked position. The marked position - * is 0 unless another position was marked or an offset was specified - * in the constructor. - */ - public synchronized void reset() { - pos = mark; - posIndex = markIndex; - } - - /** - * Closing a ByteArrayInputStream has no effect. The methods in - * this class can be called after the stream has been closed without - * generating an IOException. - *

- */ - public void close() throws IOException { - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/ConservativeSizingByteArrayOutputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/ConservativeSizingByteArrayOutputStream.java deleted file mode 100644 index 118a4bd5ed..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/ConservativeSizingByteArrayOutputStream.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * @author Mark Collette - * @since 2.0 - */ -public class ConservativeSizingByteArrayOutputStream extends OutputStream { - protected byte buf[]; - protected int count; - - /** - * Creates a new byte array output stream, with the given initial - * buffer capacity - * - * @param capacity The initial capacity - * @throws IllegalArgumentException if capacity is negative - */ - public ConservativeSizingByteArrayOutputStream(int capacity) { - if (capacity < 0) { - throw new IllegalArgumentException("Negative initial capacity: " + capacity); - } - buf = allocateByteArray(capacity); - count = 0; - } - - /** - * Creates a new byte array output stream, with the given initial - * buffer - * - * @param buffer The initial buffer - * @throws IllegalArgumentException if capacity is negative - */ - public ConservativeSizingByteArrayOutputStream(byte[] buffer) { - if (buffer == null) - throw new IllegalArgumentException("Initial buffer is null"); - else if (buffer.length == 0) - throw new IllegalArgumentException("Initial buffer has zero length"); - buf = buffer; - count = 0; - } - - public synchronized void write(int b) throws IOException { - int newCount = count + 1; - if (newCount > buf.length) - resizeArrayToFit(newCount); - buf[count] = (byte) b; - count = newCount; - } - - public synchronized void write(byte b[], int off, int len) throws IOException { - if ((off < 0) || (off >= b.length) || (len < 0) || - ((off + len) > b.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } - if (len == 0) - return; - int newCount = count + len; - if (newCount > buf.length) - resizeArrayToFit(newCount); - System.arraycopy(b, off, buf, count, len); - count = newCount; - } - - public synchronized void reset() { - count = 0; - } - - /** - * Creates a newly allocated byte array. Its length is equal to the - * current count of bytes in this output stream. The data bytes are - * then copied into it. - * - * @return The current contents of this output stream, as a byte array. - */ - public synchronized byte[] toByteArray() { - byte newBuf[] = allocateByteArray(count); - System.arraycopy(buf, 0, newBuf, 0, count); - return newBuf; - } - - /** - * Returns the current size of the buffer. - * - * @return The number of valid bytes in this output stream. - */ - public int size() { - return count; - } - - /** - * Allows the caller to take ownership of this output stream's - * byte array. Note that this output stream will then make - * a new small buffer for itself and reset its size information, - * meaning that you should call size() before this. - */ - public synchronized byte[] relinquishByteArray() { - byte[] returnBuf = buf; - buf = new byte[64]; - count = 0; - return returnBuf; - } - - /** - * @return true, if there was enough memory to trim buf; false otherwise - */ - public boolean trim() { - if (count == 0 && (buf == null || buf.length == 0)) - return true; - if (count == buf.length) - return true; - - byte newBuf[] = allocateByteArray(count); - if (newBuf == null) - return false; - System.arraycopy(buf, 0, newBuf, 0, count); - buf = null; - buf = newBuf; - return true; - } - - protected void resizeArrayToFit(int newCount) { - int steppedSize = buf.length; - if (steppedSize == 0) - steppedSize = 64; - else if (steppedSize <= 1024) - steppedSize *= 4; - else if (steppedSize <= 4024) - steppedSize *= 2; - else if (steppedSize <= 2 * 1024 * 1024) { - steppedSize *= 2; - steppedSize &= (~0x0FFF); // Fit on even 4KB pages - } else if (steppedSize <= 4 * 1024 * 1024) { - steppedSize = (steppedSize * 3) / 2; // x 1.50 - steppedSize &= (~0x0FFF); // Fit on even 4KB pages - } else if (steppedSize <= 15 * 1024 * 1024) { - steppedSize = (steppedSize * 5) / 4; // x 1.25 - steppedSize &= (~0x0FFF); // Fit on even 4KB pages - } else { - steppedSize = (steppedSize + (3 * 1024 * 1024)); // Go up in 3MB increments - steppedSize &= (~0x0FFF); // Fit on even 4KB pages - } - - int newBufSize = Math.max(steppedSize, newCount); - byte newBuf[] = allocateByteArray(newBufSize); - System.arraycopy(buf, 0, newBuf, 0, count); - buf = newBuf; - } - - protected byte[] allocateByteArray(int size) { - return new byte[size]; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/CountingOutputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/CountingOutputStream.java deleted file mode 100644 index e2c1f08f25..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/CountingOutputStream.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * Keeps track of how many bytes have been written out - * - * @since 4.0 - */ - -public class CountingOutputStream extends OutputStream { - private OutputStream wrapped; - private long count; - - public CountingOutputStream(OutputStream wrap) { - wrapped = wrap; - count = 0L; - } - - public long getCount() { - return count; - } - - public void write(int i) throws IOException { - wrapped.write(i); - count++; - } - - public void write(byte[] bytes) throws IOException { - wrapped.write(bytes); - count += bytes.length; - } - - public void write(byte[] bytes, int offset, int len) throws IOException { - wrapped.write(bytes, offset, len); - int num = Math.min(len, bytes.length - offset); - count += num; - } - - public void flush() throws IOException { - wrapped.flush(); - } - - public void close() throws IOException { - wrapped.close(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/RandomAccessFileInputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/RandomAccessFileInputStream.java deleted file mode 100644 index 2c73b56d93..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/RandomAccessFileInputStream.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.*; -import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * @author Mark Collette - * @since 2.0 - */ -public class RandomAccessFileInputStream extends InputStream implements SeekableInput { - - private static final Logger logger = - Logger.getLogger(RandomAccessFileInputStream.class.toString()); - - private long m_lMarkPosition; - private RandomAccessFile m_RandomAccessFile; - - private final ReentrantLock lock = new ReentrantLock(); - - public static RandomAccessFileInputStream build(File file) throws FileNotFoundException { - RandomAccessFile raf = new RandomAccessFile(file, "r"); - return new RandomAccessFileInputStream(raf); - } - - protected RandomAccessFileInputStream(RandomAccessFile raf) { - super(); - m_lMarkPosition = 0L; - m_RandomAccessFile = raf; - } - - - // - // InputStream overrides - // - - public int read() throws IOException { - return m_RandomAccessFile.read(); - } - - public int read(byte[] buffer) throws IOException { - return m_RandomAccessFile.read(buffer); - } - - public int read(byte[] buffer, int offset, int length) throws IOException { - return m_RandomAccessFile.read(buffer, offset, length); - } - - public void close() throws IOException { - m_RandomAccessFile.close(); - } - - public int available() { - try { - return (int) (m_RandomAccessFile.getFilePointer()); - } catch (IOException e) { - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.WARNING, "Error calling available", e); - } - } - return 0; - } - - public void mark(int readLimit) { - try { - m_lMarkPosition = m_RandomAccessFile.getFilePointer(); - } catch (IOException e) { - throw new RuntimeException(e.toString()); - } - } - - public boolean markSupported() { - return true; - } - - public void reset() throws IOException { - m_RandomAccessFile.seek(m_lMarkPosition); - } - - public long skip(long n) throws IOException { - int nn = (int) (n & 0xFFFFFFFF); - return (long) m_RandomAccessFile.skipBytes(nn); - } - - - // - // SeekableInput implementation - // (which are not already covered by InputStream overrides) - // - - public void seekAbsolute(long absolutePosition) throws IOException { - m_RandomAccessFile.seek(absolutePosition); - } - - public void seekRelative(long relativeOffset) throws IOException { - long pos = m_RandomAccessFile.getFilePointer(); - pos += relativeOffset; - if (pos < 0L) - pos = 0L; - m_RandomAccessFile.seek(pos); - } - - public void seekEnd() throws IOException { - long end = m_RandomAccessFile.length(); - seekAbsolute(end); - } - - public long getAbsolutePosition() throws IOException { - return m_RandomAccessFile.getFilePointer(); - } - - public long getLength() throws IOException { - return m_RandomAccessFile.length(); - } - - public InputStream getInputStream() { - return this; - } - - public void beginThreadAccess() { - lock.lock(); - - } - - public void endThreadAccess() { - lock.unlock(); - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SeekableByteArrayInputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SeekableByteArrayInputStream.java deleted file mode 100644 index 6a8d3165fd..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SeekableByteArrayInputStream.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.Logger; - -/** - * @author Mark Collette - * @since 2.0 - */ -public class SeekableByteArrayInputStream extends ByteArrayInputStream implements SeekableInput { - - private static final Logger log = - Logger.getLogger(SeekableByteArrayInputStream.class.toString()); - - private int m_iBeginningOffset; - - private final ReentrantLock lock = new ReentrantLock(); - - public SeekableByteArrayInputStream(byte buf[]) { - super(buf); - m_iBeginningOffset = 0; - } - - public SeekableByteArrayInputStream(byte buf[], int offset, int length) { - super(buf, offset, length); - m_iBeginningOffset = offset; - } - - // - // SeekableInput implementation - // (which are not already covered by InputStream overrides) - // - - public void seekAbsolute(long absolutePosition) { - int absPos = (int) (absolutePosition & 0xFFFFFFFF); - pos = m_iBeginningOffset + absPos; - } - - public void seekRelative(long relativeOffset) { - int relOff = (int) (relativeOffset & 0xFFFFFFFF); - int currPos = pos + relOff; - if (currPos < m_iBeginningOffset) - currPos = m_iBeginningOffset; - pos = currPos; - } - - public void seekEnd() { - seekAbsolute(getLength()); - } - - public long getAbsolutePosition() { - int absPos = pos - m_iBeginningOffset; - return (((long) absPos) & 0xFFFFFFFF); - } - - public long getLength() { - int len = count - m_iBeginningOffset; - return (((long) len) & 0xFFFFFFFF); - } - - public InputStream getInputStream() { - return this; - } - - - public void beginThreadAccess() { - lock.lock(); - - } - - public void endThreadAccess() { - lock.unlock(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SeekableInput.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SeekableInput.java deleted file mode 100644 index 989837e1c7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SeekableInput.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.IOException; -import java.io.InputStream; - -/** - * @author Mark Collette - * @since 2.0 - */ -public interface SeekableInput { - // - // Methods from InputStream - // Since Java does not have multiple inheritance, we have to - // explicitly expose InputStream's methods as part of our interface - // - public int read() throws IOException; - - public int read(byte[] buffer) throws IOException; - - public int read(byte[] buffer, int offset, int length) throws IOException; - - public void close() throws IOException; - - public int available(); - - public void mark(int readLimit); - - public boolean markSupported(); - - public void reset() throws IOException; - - public long skip(long n) throws IOException; - - - // - // Special methods that make this truly seekable - // - - public void seekAbsolute(long absolutePosition) throws IOException; - - public void seekRelative(long relativeOffset) throws IOException; - - public void seekEnd() throws IOException; - - public long getAbsolutePosition() throws IOException; - - public long getLength() throws IOException; - - // To access InputStream methods, call this instead of casting - // This InputStream has to support mark(), reset(), and obviously markSupported() - public InputStream getInputStream(); - - - // - // For regulating competing Threads' access to our state and I/O - // - - public void beginThreadAccess(); - - public void endThreadAccess(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SeekableInputConstrainedWrapper.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SeekableInputConstrainedWrapper.java deleted file mode 100644 index 9505c58c0e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SeekableInputConstrainedWrapper.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.IOException; -import java.io.InputStream; - -/** - * @author Mark Collette - * @since 2.0 - */ -public class SeekableInputConstrainedWrapper extends InputStream { - private SeekableInput streamDataInput; - private long filePositionOfStreamData; - private long lengthOfStreamData; - private long filePositionBeforeUse; - private boolean usedYet; - - public SeekableInputConstrainedWrapper( - SeekableInput in, long offset, long length) { - streamDataInput = in; - filePositionOfStreamData = offset; - lengthOfStreamData = length; - filePositionBeforeUse = 0L; - usedYet = false; - } - - - private void ensureReadyOnFirstUse() throws IOException { - if (usedYet) - return; - usedYet = true; - filePositionBeforeUse = streamDataInput.getAbsolutePosition(); - streamDataInput.seekAbsolute(filePositionOfStreamData); - } - - private long getBytesRemaining() throws IOException { - long absPos = streamDataInput.getAbsolutePosition(); - if (absPos < filePositionOfStreamData) - return -1; - long end = filePositionOfStreamData + lengthOfStreamData; - return end - absPos; - } - - - // - // Methods from InputStream - // Since Java does not have multiple inheritance, we have to - // explicitly expose InputStream's methods as part of our interface - // - public int read() throws IOException { - ensureReadyOnFirstUse(); - long remain = getBytesRemaining(); - if (remain <= 0) - return -1; - return streamDataInput.read(); - } - - public int read(byte[] buffer) throws IOException { - return read(buffer, 0, buffer.length); - } - - public int read(byte[] buffer, int offset, int length) throws IOException { - ensureReadyOnFirstUse(); - long remain = getBytesRemaining(); - - if (remain <= 0) - return -1; - length = (int) Math.min(Math.min(remain, (long) length), (long) Integer.MAX_VALUE); - return streamDataInput.read(buffer, offset, length); - } - - public int available() { - return 0; - } - - public void mark(int readLimit) { - } - - public boolean markSupported() { - return false; - } - - public void reset() throws IOException { - } - - public long skip(long n) throws IOException { - ensureReadyOnFirstUse(); - long remain = getBytesRemaining(); - if (remain <= 0) - return -1; - n = (int) Math.min(Math.min(remain, n), (long) Integer.MAX_VALUE); - return streamDataInput.skip(n); - } - - - // - // Special methods that make this truly seekable - // - - public void seekAbsolute(long absolutePosition) throws IOException { - ensureReadyOnFirstUse(); - // The wrapper exists in a different coordinate system, - // where its beginning is location 0 - if (absolutePosition < 0L) - throw new IOException("Attempt to absolutely seek to negative location: " + absolutePosition); - // It's alright to seek beyond the end, it's just that read operations will fail - absolutePosition += filePositionOfStreamData; - streamDataInput.seekAbsolute(absolutePosition); - } - - public void seekRelative(long relativeOffset) throws IOException { - ensureReadyOnFirstUse(); - long pos = streamDataInput.getAbsolutePosition(); - pos += relativeOffset; - if (pos < filePositionOfStreamData) - pos = filePositionOfStreamData; - // It's alright to seek beyond the end, it's just that read operations will fail - streamDataInput.seekAbsolute(pos); - } - - public void seekEnd() throws IOException { - ensureReadyOnFirstUse(); - streamDataInput.seekAbsolute(filePositionOfStreamData + lengthOfStreamData); - } - - public long getAbsolutePosition() throws IOException { - ensureReadyOnFirstUse(); - long absolutePosition = getAbsolutePosition(); - absolutePosition -= filePositionOfStreamData; - return absolutePosition; - } - - public long getLength() { - return lengthOfStreamData; - } - - // To access InputStream methods, call this instead of casting - // This InputStream has to support mark(), reset(), and obviously markSupported() - public InputStream getInputStream() { - return this; - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(super.toString()); - sb.append(" ( "); - sb.append("pos=").append(filePositionOfStreamData).append(", "); - sb.append("len=").append(lengthOfStreamData).append(", "); - sb.append("posToRestore=").append(filePositionBeforeUse).append(", "); - sb.append(" ) "); - sb.append(": "); - if (streamDataInput == null) - sb.append("null "); - else - sb.append(streamDataInput.toString()); - return sb.toString(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SequenceInputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SequenceInputStream.java deleted file mode 100644 index 073b5d522a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SequenceInputStream.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -/** - * @author Mark Collette - * @since 2.0 - */ -public class SequenceInputStream extends InputStream { - private Iterator m_itInputStreams; - private InputStream m_isCurrent; - - public SequenceInputStream(InputStream... in) { - this(Arrays.asList(in)); - } - - public SequenceInputStream(List inputStreams) { - this(inputStreams, -1); - } - - public SequenceInputStream(List inputStreams, int streamSwitchValue) { - List in = new ArrayList(); - for (int i = 0; i < inputStreams.size(); i++) { - if (i > 0 && streamSwitchValue != -1) { - in.add(new ByteArrayInputStream(new byte[]{(byte) streamSwitchValue})); - } - in.add(inputStreams.get(i)); - } - m_itInputStreams = in.iterator(); - - try { - useNextInputStream(); - } catch (IOException e) { - throw new java.lang.IllegalStateException("Could not use first InputStream in SequenceInputStream(List) : " + e); - } - } - - private InputStream getCurrentInputStream() { - return m_isCurrent; - } - - private void useNextInputStream() throws IOException { - closeCurrentInputStream(); - - m_isCurrent = null; - while (m_itInputStreams.hasNext()) { - InputStream in = m_itInputStreams.next(); - if (in != null) { - m_isCurrent = in; - break; - } - } - } - - private void closeCurrentInputStream() throws IOException { - InputStream in = getCurrentInputStream(); - if (in != null) - in.close(); - } - - - public int available() throws IOException { - InputStream in = getCurrentInputStream(); - if (in != null) - return in.available(); - return 0; - } - - public int read() throws IOException { - while (true) { - InputStream in = getCurrentInputStream(); - if (in == null) { - useNextInputStream(); - in = getCurrentInputStream(); - if (in == null) - return -1; - } - - int readByte = in.read(); - if (readByte >= 0) - return readByte; - useNextInputStream(); - } - } - - public int read(byte buffer[], int off, int len) throws IOException { - if (buffer == null) { - throw new NullPointerException(); - } else if ((off < 0) || (off >= buffer.length) || - (len < 0) || ((off + len) > buffer.length) || - ((off + len) < 0)) { - throw new IndexOutOfBoundsException("Offset: " + off + ", Length: " + len + ", Buffer length: " + buffer.length); - } else if (len == 0) - return 0; - - int totalRead = 0; - while (totalRead < len) { - InputStream in = getCurrentInputStream(); - if (in == null) { - useNextInputStream(); - in = getCurrentInputStream(); - if (in == null) { - if (totalRead > 0) { - break; - } - return -1; - } - } - - int currRead = in.read(buffer, off + totalRead, len - totalRead); - if (currRead > 0) { - totalRead += currRead; - } else { - useNextInputStream(); - } - } - - return totalRead; - } - - public void close() throws IOException { - do { - useNextInputStream(); - } while (getCurrentInputStream() != null); - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(getClass().getName()); - sb.append(": "); - - List inputStreams = new ArrayList(); - while (m_itInputStreams.hasNext()) { - InputStream in = m_itInputStreams.next(); - sb.append("\n "); - sb.append(in.toString()); - sb.append(","); - inputStreams.add(in); - } - m_itInputStreams = inputStreams.iterator(); - - sb.append('\n'); - return sb.toString(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SizeInputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SizeInputStream.java deleted file mode 100644 index adeab91e8e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/SizeInputStream.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.IOException; -import java.io.InputStream; - -/** - * SizeInputStream wraps inputs streams of know lengths so that the available - * call can return a useful number. - * - * @sinece 5.0.3 - */ -public class SizeInputStream extends InputStream { - - private InputStream in = null; - - private int size = 0; - - private int bytesRead = 0; - - public SizeInputStream(InputStream in, int size) { - this.in = in; - this.size = size; - } - - public int available() { - return (size - bytesRead); - } - - public int read() throws IOException { - int b = in.read(); - if (b != -1) { - bytesRead++; - } - return b; - } - - public int read(byte[] b) throws IOException { - int read = in.read(b); - bytesRead += read; - return read; - } - - public int read(byte[] b, int off, int len) throws IOException { - int read = in.read(b, off, len); - bytesRead += read; - return read; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/ZeroPaddedInputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/ZeroPaddedInputStream.java deleted file mode 100644 index b3c132672a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/io/ZeroPaddedInputStream.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.io; - -import java.io.IOException; -import java.io.InputStream; - -/** - * When decoding CCITTFaxDecode images via JAI, we sometimes have - * to zero pad the input data, otherwise JAI will fail instead - * of it gracefully assuming zero data itself. - * As well, with some inline images, we can have some trailing - * whitespace that should be removed. - * It's typical to have to remove the whitespace and add the zeros. - * - * @author Mark Collette - * @since 2.2 - */ - -public class ZeroPaddedInputStream extends InputStream { - private InputStream in; - - public ZeroPaddedInputStream(InputStream in) { - this.in = in; - } - - // - // Methods from InputStream - // - public int read() throws IOException { - int r = in.read(); -//System.out.println("ZPIS.read() r: " + r); - if (r < 0) - return 0; - return r; - } - - public int read(byte[] buffer) throws IOException { - return read(buffer, 0, buffer.length); - } - - public int read(byte[] buffer, int offset, int length) throws IOException { - int readIn = in.read(buffer, offset, length); -//System.out.println("ZPIS.read( "+length+" ) readIn: " + readIn); - if (readIn < length) { -//String str = new String( buffer, offset, Math.max(0, readIn) ); -//System.out.println( str ); -//System.out.println("-----------"); -//System.out.println( org.icepdf.core.util.Utils.convertByteArrayToHexString(buffer, offset, Math.max(0, readIn), true, 0, '0') ); - if (readIn > 0) { - while ((buffer[offset + readIn - 1] == 0x0A || buffer[offset + readIn - 1] == 0x0D || buffer[offset + readIn - 1] == 0x20) && readIn > 0) - readIn--; - return readIn; - } - int end = offset + length; - for (int current = offset + Math.max(0, readIn); current < end; current++) - buffer[current] = 0; - } - return length; - } - - public void close() throws IOException { - in.close(); - } - - public int available() throws IOException { - int a = in.available(); -//System.out.println("ZPIS.available() : " + a); - if (a <= 0) - a = 1; - return a; - } - - public void mark(int readLimit) { - in.mark(readLimit); - } - - public boolean markSupported() { - return in.markSupported(); - } - - public void reset() throws IOException { - in.reset(); - } - - public long skip(long n) throws IOException { - long s = in.skip(n); -//System.out.println("ZPIS.skip( " + n + " ) : " + s); - return s; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Catalog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Catalog.java deleted file mode 100644 index eee6f2ffc7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Catalog.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.acroform.InteractiveForm; -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

The Catalog object represents the root of a PDF document's - * object heirarchy. The Catalog is located by means of the - * Root entry in the trailer of the PDF file. The catalog contains - * references to other objects defining the document's contents, outline, names, - * destinations, and other attributes.

- *

- *

The Catalog class can be accessed from the {@see Document} - * class for convenience, but can also be accessed via the {@see PTrailer} class. - * Useful information about the document can be extracted from the Catalog - * Dictionary, such as PDF version information and Viewer Preferences. All - * Catalog dictionary properties can be accesed via the getEntries method. - * See section 3.6.1 of the PDF Reference version 1.6 for more information on - * the properties available in the Catalog Object.

- * - * @since 1.0 - */ -public class Catalog extends Dictionary { - - private static final Logger logger = - Logger.getLogger(Catalog.class.toString()); - - public static final Name TYPE = new Name("Catalog"); - public static final Name DESTS_KEY = new Name("Dests"); - public static final Name VIEWERPREFERENCES_KEY = new Name("ViewerPreferences"); - public static final Name NAMES_KEY = new Name("Names"); - public static final Name OUTLINES_KEY = new Name("Outlines"); - public static final Name OCPROPERTIES_KEY = new Name("OCProperties"); - public static final Name PAGES_KEY = new Name("Pages"); - public static final Name PAGELAYOUT_KEY = new Name("PageLayout"); - public static final Name PAGEMODE_KEY = new Name("PageMode"); - public static final Name ACRO_FORM_KEY = new Name("AcroForm"); - public static final Name COLLECTION_KEY = new Name("Collection"); - public static final Name METADATA_KEY = new Name("Metadata"); - public static final Name PERMS_KEY = new Name("Perms"); - - public static final Name PAGE_MODE_USE_NONE_VALUE = new Name("UseNone"); - public static final Name PAGE_MODE_USE_OUTLINES_VALUE = new Name("UseOutlines"); - public static final Name PAGE_MODE_USE_THUMBS_VALUE = new Name("UseThumbs"); - public static final Name PAGE_MODE_FULL_SCREEN_VALUE = new Name("FullScreen"); - public static final Name PAGE_MODE_OPTIONAL_CONTENT_VALUE = new Name("UseOC"); - public static final Name PAGE_MODE_USE_ATTACHMENTS_VALUE = new Name("UseAttachments"); - - private PageTree pageTree; - private Outlines outlines; - private Names names; - private OptionalContent optionalContent; - private NamedDestinations dests; - private ViewerPreferences viewerPref; - private InteractiveForm interactiveForm; - - private boolean outlinesInited = false; - private boolean namesTreeInited = false; - private boolean destsInited = false; - private boolean viewerPrefInited = false; - private boolean optionalContentInited = false; - - // Announce ICEpdf Core - static { - if (logger.isLoggable(Level.INFO)) { - logger.info("ICEsoft ICEpdf Core " + Document.getLibraryVersion()); - } - } - - /** - * Creates a new instance of a Catalog. - * - * @param l document library. - * @param h Catalog dictionary entries. - */ - public Catalog(Library l, HashMap h) { - super(l, h); - } - - /** - * Initiate the PageTree. - */ - public synchronized void init() throws InterruptedException { - Object tmp = library.getObject(entries, PAGES_KEY); - pageTree = null; - if (tmp instanceof PageTree) { - pageTree = (PageTree) tmp; - } - // malformed core corner case, pages must not be references, but we - // have a couple cases that break the spec. - else if (tmp instanceof HashMap) { - pageTree = new PageTree(library, (HashMap) tmp); - } - // malformed corner case, just have a page object, instead of tree. - else if (tmp instanceof Page) { - Page tmpPage = (Page) tmp; - HashMap tmpPages = new HashMap(); - List kids = new ArrayList(); - kids.add(tmpPage.getPObjectReference()); - tmpPages.put("Kids", kids); - tmpPages.put("Count", 1); - pageTree = new PageTree(library, tmpPages); - } - - // let any exception bubble up. - if (pageTree != null) { - pageTree.init(); - } - - // check for the collections dictionary for the presence of a portable collection - tmp = library.getObject(entries, NAMES_KEY); - if (tmp != null) { - names = new Names(library, (HashMap) tmp); - names.init(); - } - - // load the Acroform data. - tmp = library.getObject(entries, ACRO_FORM_KEY); - if (tmp instanceof HashMap) { - interactiveForm = new InteractiveForm(library, (HashMap) tmp); - interactiveForm.init(); - } - // todo namesTree contains forms javascript, might need to be initialized here - - } - - /** - * Gets PageTree node that is the root of the document's page tree. - * The PageTree can be traversed to access child PageTree and Page objects. - * - * @return Catalogs PageTree. - * @see org.icepdf.core.pobjects.Page - */ - public PageTree getPageTree() { - return pageTree; - } - - /** - * Gets the Outlines Dictionary that is the root of the document's outline - * hierarchy. The Outline can be traversed to access child OutlineItems. - * - * @return Outlines object if one exists; null, otherwise. - * @see org.icepdf.core.pobjects.OutlineItem - */ - public Outlines getOutlines() { - if (!outlinesInited) { - outlinesInited = true; - Object o = library.getObject(entries, OUTLINES_KEY); - if (o != null) - outlines = new Outlines(library, (HashMap) o); - } - return outlines; - } - - /** - * A collection dictionary that a conforming reader shall use to enhance the presentation of file attachments - * stored in the PDF document. - * - * @return collection dictionary. - */ - public HashMap getCollection() { - return library.getDictionary(entries, COLLECTION_KEY); - } - - /** - * A name object specifying how the document shall be displayed when opened: - * - * @return one of the PageMode value contants, default is Default value: UseNone. - */ - public Name getPageMode() { - Name name = library.getName(entries, PAGEMODE_KEY); - if (name == null) { - return PAGE_MODE_USE_NONE_VALUE; - } else { - return name; - } - } - - /** - * Gets the document's Names dictionary. The Names dictionary contains - * a category of objects in a PDF file which can be referred to by name - * rather than by object reference. - * - * @return names object entry. If no names entries exists null - * is returned. - */ - public Names getNames() { - return names; - } - - /** - * Gets the Names object's embedded files name tree if present. The root node is also check to make sure - * the tree has values. - * - * @return A name tree mapping name strings to file specifications for embedded - * file streams. - */ - public NameTree getEmbeddedFilesNameTree() { - if (names != null) { - NameTree nameTree = names.getEmbeddedFilesNameTree(); - if (nameTree != null && nameTree.getRoot() != null) { - return nameTree; - } - } - return null; - } - - - /** - * Gets a dictionary of names and corresponding destinations. - * - * @return A Dictionary of Destinations; if none, null is returned. - */ - @SuppressWarnings("unchecked") - public NamedDestinations getDestinations() { - if (!destsInited) { - destsInited = true; - Object o = library.getObject(entries, DESTS_KEY); - if (o != null) { - dests = new NamedDestinations(library, (HashMap) o); - } - } - return dests; - } - - /** - * Gets a dictionary of keys and corresponding viewer preferences - * This can be used to pull information based on the PDF specification, - * such as HideToolbar or FitWindow - * - * @return the constructed ViewerPreferences object - */ - public ViewerPreferences getViewerPreferences() { - if (!viewerPrefInited) { - viewerPrefInited = true; - Object o = library.getObject(entries, VIEWERPREFERENCES_KEY); - if (o != null) { - viewerPref = new ViewerPreferences(library, (HashMap) o); - viewerPref.init(); - } - } - return viewerPref; - } - - /** - * Gets the the optional content properties dictionary if present. - * - * @return OptionalContent dictionary, null if none exists. - */ - public OptionalContent getOptionalContent() { - if (!optionalContentInited) { - optionalContentInited = true; - Object o = library.getObject(entries, OCPROPERTIES_KEY); - if (o != null && o instanceof HashMap) { - optionalContent = new OptionalContent(library, ((HashMap) o)); - optionalContent.init(); - } else { - optionalContent = new OptionalContent(library, new HashMap()); - optionalContent.init(); - } - } - return optionalContent; - } - - /** - * A metadata stream that shall contain metadata for the document. To - * access the metadata stream data make a call to getMetData().getDecodedStreamBytes() - * which can be used to create a String or open an InputStream. - * - * @return metadata stream if define, otherwise null. - */ - public Stream getMetaData() { - Object o = library.getObject(entries, METADATA_KEY); - if (o != null && o instanceof Stream) { - return (Stream) o; - } - return null; - } - - /** - * Gets the permissions of the catalog if present. Perms key. - * - * @return permissions if present, otherwise false. - */ - public Permissions getPermissions() { - HashMap hashMap = library.getDictionary(entries, PERMS_KEY); - if (hashMap != null) { - return new Permissions(library, hashMap); - } else { - return null; - } - } - - /** - * Gets the interactive form object that contains the form widgets for the given PDF. - * - * @return interactive form object, null if no forms are pressent. - */ - public InteractiveForm getInteractiveForm() { - return interactiveForm; - } - - /** - * Returns a summary of the Catalog dictionary values. - * - * @return dictionary values. - */ - public String toString() { - return "CATALOG= " + entries.toString(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/CrossReference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/CrossReference.java deleted file mode 100644 index b72591f7f9..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/CrossReference.java +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Parser; -import org.icepdf.core.util.Utils; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * @author Mark Collette - * @since 2.0 - */ - -public class CrossReference { - - private static final Logger logger = - Logger.getLogger(CrossReference.class.toString()); - - public static final Name SIZE_KEY = new Name("Size"); - public static final Name INDEX_KEY = new Name("Index"); - public static final Name W_KEY = new Name("W"); - - /** - * Map of all the objects in reference by the CrossReference table. Ojbects - * are retrieved by object number. - */ - private ConcurrentHashMap hObjectNumber2Entry; - /** - * In a Linearized PDF, we don't want to load all Trailers and their XRefs - * upfront, but would rather load the first upfront, and then lazily load - * the rest. - * If xrefPrevious != null, Then just use it - * If xrefPrevious == null And pTrailer == null, - * Then we can't do anything - * If xrefPrevious == null And pTrailer != null, - * Then use pTrailer to setup xrefPrevious - */ - private PTrailer pTrailer; - private CrossReference xrefPrevious; - private CrossReference xrefPeer; - // - private boolean bIsCrossReferenceTable; - private boolean bHaveTriedLoadingPrevious; - private boolean bHaveTriedLoadingPeer; - - // offset error for simple file error issue. - protected int offset; - - public CrossReference() { - hObjectNumber2Entry = new ConcurrentHashMap(4096); - } - - public void setTrailer(PTrailer trailer) { - pTrailer = trailer; - } - - /** - * Starts the parsing of an xRef table entries as found when using the - * Parser to Parse out an object via Parser.getObject(). - *

- * All entries are taken into consideration except for ones that are marked - * free. - * - * @param parser content parser - */ - - public void addXRefTableEntries(Parser parser) { - bIsCrossReferenceTable = true; - try { - while (true) { - Object startingObjectNumberOrTrailer = parser.getNumberOrStringWithMark(16); - if (!(startingObjectNumberOrTrailer instanceof Number)) { - parser.ungetNumberOrStringWithReset(); - break; - } - - int startingObjectNumber = ((Number) startingObjectNumberOrTrailer).intValue(); - int numEntries = ((Number) parser.getToken()).intValue(); - int currNumber = startingObjectNumber; - for (int i = 0; i < numEntries; i++) { - long filePosition = parser.getIntSurroundedByWhitespace(); // ( (Number) getToken() ).longValue(); - int generationNum = parser.getIntSurroundedByWhitespace(); // ( (Number) getToken() ).intValue(); - char usedOrFree = parser.getCharSurroundedByWhitespace(); // ( (String) getToken() ).charAt( 0 ); - if (usedOrFree == 'n') { // Used - addUsedEntry(currNumber, filePosition, generationNum); - } - // ignore any free entries. - else if (usedOrFree == 'f') { // Free - // check for the first entry 0000000000 65535 f and - // a object range where the first entry isn't zero. The - // code below will treat the first entry as zero and then - // start counting. - if (startingObjectNumber > 0 && - filePosition == 0 && generationNum == 65535) { - // offset the count so we start counting after the zeroed entry - currNumber--; - } -// addFreeEntry(currNumber, (int) filePosition, generationNum); - } - currNumber++; - } - } - } catch (IOException e) { - logger.log(Level.SEVERE, "Error parsing xRef table entries.", e); - } - } - - /** - * Once a XRef stream is found, the decoded streamInput is itereated over - * to build out the Xref structure. - * - * @param library The Document's Library - * @param xrefStreamHash Dictionary for XRef stream - * @param streamInput Decoded stream bytes for XRef stream - */ - @SuppressWarnings("unchecked") - public void addXRefStreamEntries(Library library, HashMap xrefStreamHash, InputStream streamInput) { - try { - // number +1 represented the highest object number. - int size = library.getInt(xrefStreamHash, SIZE_KEY); - // pair of integers for each subsection in this section. The first - // int is the first object number in this section and the second - // is the number of entries. - List objNumAndEntriesCountPairs = - (List) library.getObject(xrefStreamHash, INDEX_KEY); - if (objNumAndEntriesCountPairs == null) { - objNumAndEntriesCountPairs = new ArrayList(2); - objNumAndEntriesCountPairs.add(0); - objNumAndEntriesCountPairs.add(size); - } - // three int's: field values, x,y and z bytes in length. - List fieldSizesVec = (List) library.getObject(xrefStreamHash, W_KEY); - int[] fieldSizes = null; - if (fieldSizesVec != null) { - fieldSizes = new int[fieldSizesVec.size()]; - for (int i = 0; i < fieldSizesVec.size(); i++) - fieldSizes[i] = ((Number) fieldSizesVec.get(i)).intValue(); - } - // not doing anything with PREV. - - int fieldTypeSize = fieldSizes[0]; - int fieldTwoSize = fieldSizes[1]; - int fieldThreeSize = fieldSizes[2]; - // parse out the object data. - for (int xrefSubsection = 0; xrefSubsection < objNumAndEntriesCountPairs.size(); xrefSubsection += 2) { - int startingObjectNumber = objNumAndEntriesCountPairs.get(xrefSubsection).intValue(); - int entriesCount = objNumAndEntriesCountPairs.get(xrefSubsection + 1).intValue(); - int afterObjectNumber = startingObjectNumber + entriesCount; - for (int objectNumber = startingObjectNumber; objectNumber < afterObjectNumber; objectNumber++) { - int entryType = Entry.TYPE_USED; // Default value is 1 - if (fieldTypeSize > 0) - entryType = Utils.readIntWithVaryingBytesBE(streamInput, fieldTypeSize); - // used object but not compressed - if (entryType == Entry.TYPE_USED) { - long filePositionOfObject = Utils.readLongWithVaryingBytesBE( - streamInput, fieldTwoSize); - int generationNumber = 0; // Default value is 0 - if (fieldThreeSize > 0) { - generationNumber = Utils.readIntWithVaryingBytesBE( - streamInput, fieldThreeSize); - } - addUsedEntry(objectNumber, filePositionOfObject, generationNumber); - } - // entries define compress objects. - else if (entryType == Entry.TYPE_COMPRESSED) { - int objectNumberOfContainingObjectStream = Utils.readIntWithVaryingBytesBE( - streamInput, fieldTwoSize); - int indexWithinObjectStream = Utils.readIntWithVaryingBytesBE( - streamInput, fieldThreeSize); - addCompressedEntry( - objectNumber, objectNumberOfContainingObjectStream, indexWithinObjectStream); - - } - // free objects, no used. - else if (entryType == Entry.TYPE_FREE) { - // we do nothing but we still need to move the cursor. - Utils.readIntWithVaryingBytesBE( - streamInput, fieldTwoSize); - Utils.readIntWithVaryingBytesBE( - streamInput, fieldThreeSize); - } - } - } - } catch (IOException e) { - logger.log(Level.SEVERE, "Error parsing xRef stream entries.", e); - } - } - - public Entry getEntryForObject(Integer objectNumber) { - Entry entry = hObjectNumber2Entry.get(objectNumber); - if (entry != null) - return entry; - /// fall back code to look for another xref table. - if (bIsCrossReferenceTable && !bHaveTriedLoadingPeer && - xrefPeer == null && pTrailer != null) { - // Lazily load xrefPeer, using pTrailer - pTrailer.loadXRefStmIfApplicable(); - xrefPeer = pTrailer.getCrossReferenceStream(); - bHaveTriedLoadingPeer = true; - } - if (xrefPeer != null) { - entry = xrefPeer.getEntryForObject(objectNumber); - if (entry != null) - return entry; - } - - if (!bHaveTriedLoadingPrevious && - xrefPrevious == null && pTrailer != null) { - // Lazily load xrefPrevious, using pTrailer - pTrailer.onDemandLoadAndSetupPreviousTrailer(); - bHaveTriedLoadingPrevious = true; - } - if (xrefPrevious != null) { - entry = xrefPrevious.getEntryForObject(objectNumber); - if (entry != null) - return entry; - } - return entry; - } - - public void addToEndOfChainOfPreviousXRefs(CrossReference prev) { - if (xrefPrevious == null) - xrefPrevious = prev; - else - xrefPrevious.addToEndOfChainOfPreviousXRefs(prev); - } - - protected void addFreeEntry(int objectNumber, int nextFreeObjectNumber, int generationNumberIfReused) { - FreeEntry entry = new FreeEntry(objectNumber, nextFreeObjectNumber, generationNumberIfReused); -// m_vXRefEntries.add(entry); - } - - protected void addUsedEntry(int objectNumber, long filePositionOfObject, int generationNumber) { - UsedEntry entry = new UsedEntry(objectNumber, filePositionOfObject, generationNumber); - hObjectNumber2Entry.put(objectNumber, entry); - } - - protected void addCompressedEntry(int objectNumber, int objectNumberOfContainingObjectStream, int indexWithinObjectStream) { - CompressedEntry entry = new CompressedEntry(objectNumber, objectNumberOfContainingObjectStream, indexWithinObjectStream); - hObjectNumber2Entry.put(objectNumber, entry); - } - - - public static class Entry { - public static final int TYPE_FREE = 0; - public static final int TYPE_USED = 1; - public static final int TYPE_COMPRESSED = 2; - - private int Type; - private int objectNumber; - - Entry(int type, int objectNumber) { - Type = type; - this.objectNumber = objectNumber; - } - - int getType() { - return Type; - } - - int getObjectNumber() { - return objectNumber; - } - } - - public static class FreeEntry extends Entry { - private int nextFreeObjectNumber; - private int generationNumberIfReused; - - FreeEntry(int objectNumber, int nextFreeObjectNumber, int generationNumberIfReused) { - super(TYPE_FREE, objectNumber); - this.nextFreeObjectNumber = nextFreeObjectNumber; - this.generationNumberIfReused = generationNumberIfReused; - } - - public int getNextFreeObjectNumber() { - return nextFreeObjectNumber; - } - - public int getGenerationNumberIfReused() { - return generationNumberIfReused; - } - } - - public class UsedEntry extends Entry { - private long filePositionOfObject; - private int generationNumber; - - UsedEntry(int objectNumber, long filePositionOfObject, int generationNumber) { - super(TYPE_USED, objectNumber); - this.filePositionOfObject = filePositionOfObject; - this.generationNumber = generationNumber; - } - - public long getFilePositionOfObject() { - return filePositionOfObject + offset; - } - - public int getGenerationNumber() { - return generationNumber; - } - - public void setFilePositionOfObject(long filePositionOfObject) { - this.filePositionOfObject = filePositionOfObject; - } - } - - public static class CompressedEntry extends Entry { - private int objectNumberOfContainingObjectStream; - private int indexWithinObjectStream; - - CompressedEntry(int objectNumber, int objectNumberOfContainingObjectStream, int indexWithinObjectStream) { - super(TYPE_COMPRESSED, objectNumber); - this.objectNumberOfContainingObjectStream = objectNumberOfContainingObjectStream; - this.indexWithinObjectStream = indexWithinObjectStream; - } - - public int getObjectNumberOfContainingObjectStream() { - return objectNumberOfContainingObjectStream; - } - - public int getIndexWithinObjectStream() { - return indexWithinObjectStream; - } - } - - public void setOffset(int offset) { - this.offset = offset; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Destination.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Destination.java deleted file mode 100644 index a2d1ad930c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Destination.java +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

The Destination class defines a particular view of a - * PDF document consisting of the following items:

- *
    - *
  • The page of the document to be displayed.
  • - *
  • The location of the document window on that page.
  • - *
  • The magnification (zoom) factor to use when displaying the page - * Destinations may be associated with outline items, annotations, - * or actions.
  • - *
- *

Destination can be associated with outline items, annotations, or actions. - * In each case the destination specifies the view of the document to be presented - * when one of the respective objects is activated.

- *

The Destination class currently only supports the Destination syntaxes, - * [page /XYZ left top zoom], other syntax will be added in future releases. The - * syntax [page /XYZ left top zoom] is defined as follows:

- *
    - *
  • page - designated page to show (Reference to a page).
  • - *
  • /XYZ - named format of destination syntax.
  • - *
  • left - x value of the upper left-and coordinate.
  • - *
  • top - y value of the upper left-hand coordinate.
  • - *
  • zoom - zoom factor to magnify page by.
  • - *
- *

A null value for left, top or zoom specifies that the current view values - * will be unchanged when navigating to the specified page.

- * - * @see org.icepdf.core.pobjects.annotations.Annotation - * @see org.icepdf.core.pobjects.OutlineItem - * @see org.icepdf.core.pobjects.actions.Action - * @since 1.0 - */ -public class Destination { - - private static final Logger logger = - Logger.getLogger(Destination.class.toString()); - - public static final Name D_KEY = new Name("D"); - // Vector destination type formats. - public static final Name TYPE_XYZ = new Name("XYZ"); - public static final Name TYPE_FIT = new Name("Fit"); - public static final Name TYPE_FITH = new Name("FitH"); - public static final Name TYPE_FITV = new Name("FitV"); - public static final Name TYPE_FITR = new Name("FitR"); - public static final Name TYPE_FITB = new Name("FitB"); - public static final Name TYPE_FITBH = new Name("FitBH"); - public static final Name TYPE_FITBV = new Name("FitBV"); - - // library of all PDF document objects - private Library library; - - // object containing all of the destinations parameters - private Object object; - - // Reference object for destination - private Reference ref; - - // type, /XYZ, /Fit, /FitH... - private Name type; - - // Specified by /XYZ in the core, /(left)(top)(zoom) - private Float left = null; - private Float bottom = null; - private Float right = null; - private Float top = null; - private Float zoom = null; - - // named Destination name, can be a name or String - private Name namedDestination; - - // initiated flag - private boolean inited; - - /** - * Creates a new instance of a Destination. - * - * @param l document library. - * @param h Destination dictionary entries. - */ - public Destination(Library l, Object h) { - library = l; - object = h; - init(); - } - - /** - * Initiate the Destination. Retrieve any needed attributes. - */ - private void init() { - - // check for initiation - if (inited) { - return; - } - inited = true; - - // if vector we have found /XYZ - if (object instanceof List) { - parse((List) object); - } - - // find named Destinations, this however is incomplete - // @see #parser for more detailed information - else if (object instanceof Name || object instanceof StringObject) { - String s; - // Make sure to decrypt this attribute - if (object instanceof StringObject) { - StringObject stringObject = (StringObject) object; - s = stringObject.getDecryptedLiteralString(library.getSecurityManager()); - } else { - s = object.toString(); - } - - // store the name - namedDestination = new Name(s); - - boolean found = false; - Catalog catalog = library.getCatalog(); - if (catalog != null && catalog.getNames() != null) { - NameTree nameTree = catalog.getNames().getDestsNameTree(); - if (nameTree != null) { - Object o = nameTree.searchName(s); - if (o != null) { - if (o instanceof List) { - parse((List) o); - found = true; - } else if (o instanceof HashMap) { - HashMap h = (HashMap) o; - Object o1 = h.get(D_KEY); - if (o1 instanceof List) { - parse((List) o1); - found = true; - } - } - } - } - if (!found) { - Dictionary dests = catalog.getDestinations(); - if (dests != null) { - Object ob = dests.getObject((Name) object); - // list of destinations name->Dest pairs. - if (ob instanceof List) { - parse((List) ob); - } - // corner case for d attached list. - else if (ob instanceof HashMap) { - parse((List) (((HashMap) ob).get(D_KEY))); - } else { - if (logger.isLoggable(Level.FINE)) { - logger.warning("Destination type missed=" + ob); - } - } - } - } - } - } - } - - /** - * Get the dictionary object, name, string or array. - * - * @return - */ - public Object getObject() { - return object; - } - - /** - * Utility method for parsing the Destination attributes - * - * @param v vector of attributes associated with the Destination - */ - private void parse(List v) { - - if (v == null) return; - - // Assign a Reference - Object ob = getDestValue(0, v); - if (ob instanceof Reference) { - ref = (Reference) ob; - } - // store type. - ob = getDestValue(1, v); - if (ob instanceof Name) { - type = (Name) ob; - } else if (ob != null) { - type = new Name(ob.toString()); - } - // [page /XYZ left top zoom ] - if (TYPE_XYZ.equals(type)) { - ob = getDestValue(2, v); - if (ob != null && !ob.equals("null")) { - left = ((Number) ob).floatValue(); - } - ob = getDestValue(3, v); - if (ob != null && !ob.equals("null")) { - top = ((Number) ob).floatValue(); - } - // zoom can be a value but zero and null are treated as no zoom change. - ob = getDestValue(4, v); - if (ob != null && !ob.equals("null") && !ob.equals("0")) { - zoom = ((Number) ob).floatValue(); - } - } - // [page /FitH top] - else if (TYPE_FITH.equals(type)) { - ob = getDestValue(2, v); - if (ob != null && !ob.equals("null")) { - top = ((Number) ob).floatValue(); - } - } - // [page /FitR left bottom right top] - else if (TYPE_FITR.equals(type)) { - ob = getDestValue(2, v); - if (ob != null && !ob.equals("null")) { - left = ((Number) ob).floatValue(); - } - ob = getDestValue(3, v); - if (ob != null && !ob.equals("null")) { - bottom = ((Number) ob).floatValue(); - } - ob = getDestValue(4, v); - if (ob != null && !ob.equals("null")) { - right = ((Number) ob).floatValue(); - } - ob = getDestValue(5, v); - if (ob != null && !ob.equals("null")) { - top = ((Number) ob).floatValue(); - } - } - // [page /FitB] - else if (TYPE_FITB.equals(type)) { - // nothing to parse - } - // [page /FitBH top] - else if (TYPE_FITBH.equals(type)) { - ob = getDestValue(2, v); - if (ob != null && !ob.equals("null")) { - top = ((Number) ob).floatValue(); - } - } - // [page /FitBV left] - else if (TYPE_FITBV.equals(type)) { - ob = getDestValue(2, v); - if (ob != null && !ob.equals("null")) { - left = ((Number) ob).floatValue(); - } - } - } - - // utility to avoid indexing issues with malformed dest type formats. - private static Object getDestValue(int index, List params) { - if (params.size() > index) { - return params.get(index); - } - return null; - } - - /** - * Gets the name of the named destination. - * - * @return name of destination if present, null otherwise. - */ - public Name getNamedDestination() { - return namedDestination; - } - - /** - * Sets the named destination as a Named destination. It is assumed - * the named destination already exists in the document. - * - * @param dest destination to associate with. - */ - public void setNamedDestination(Name dest) { - namedDestination = dest; - // only write out destination as names so we don't have worry about - // encryption. - object = dest; - // re-parse as object should point to a new destination. - inited = false; - init(); - } - - /** - * Sets the destination syntax to the specified value. The Destinatoin - * object clears the named destination and re initializes itself after the - * assignment has been made. - * - * @param destinationSyntax new vector of destination syntax. - */ - public void setDestinationSyntax(List destinationSyntax) { - // clear named destination - namedDestination = null; - object = destinationSyntax; - // re-parse as object should point to a new destination. - inited = false; - init(); - } - - /** - * Utility for creating a /Fit or FitB syntax vector. - * - * @param page destination page pointer. - * @param type type of destionation - * @return new instance of vector containing well formed destination syntax. - */ - public static List destinationSyntax( - Reference page, final Name type) { - List destSyntax = new ArrayList(2); - destSyntax.add(page); - destSyntax.add(type); - return destSyntax; - } - - /** - * Utility for creating a /FitH, /FitV, /FitBH or /FitBV syntax vector. - * - * @param page destination page pointer. - * @param type type of destionation - * @param offset offset coordinate value in page space for specified dest type. - * @return new instance of vector containing well formed destination syntax. - */ - public static List destinationSyntax( - Reference page, final Name type, Object offset) { - List destSyntax = new ArrayList(3); - destSyntax.add(page); - destSyntax.add(type); - destSyntax.add(offset); - return destSyntax; - } - - /** - * Utility for creating a /XYZ syntax vector. - * - * @param page destination page pointer. - * @param type type of destionation - * @param left offset coordinate value in page space for specified dest type. - * @param top offset coordinate value in page space for specified dest type. - * @param zoom page zoom, 0 or null indicates no zoom. - * @return new instance of vector containing well formed destination syntax. - */ - public static List destinationSyntax( - Reference page, final Object type, Object left, Object top, Object zoom) { - List destSyntax = new ArrayList(5); - destSyntax.add(page); - destSyntax.add(type); - destSyntax.add(left); - destSyntax.add(top); - destSyntax.add(zoom); - return destSyntax; - } - - /** - * Utility for creating a /FitR syntax vector. - * - * @param page destination page pointer. - * @param type type of destionation - * @param left offset coordinate value in page space for specified dest type. - * @param top offset coordinate value in page space for specified dest type. - * @param bottom offset coordinate value in page space for specified dest type. - * @param right offset coordinate value in page space for specified dest type. - * @return new instance of vector containing well formed destination syntax. - */ - public static List destinationSyntax( - Reference page, final Object type, Object left, Object bottom, - Object right, Object top) { - List destSyntax = new ArrayList(6); - destSyntax.add(page); - destSyntax.add(type); - destSyntax.add(left); - destSyntax.add(bottom); - destSyntax.add(right); - destSyntax.add(top); - return destSyntax; - } - - /** - * Gets the Page Reference specified by the destination. - * - * @return a Reference to the Page Object associated with this destination. - */ - public Reference getPageReference() { - return ref; - } - - /** - * Gets the left offset from the top, left position of the page specified by - * this destination. - * - * @return the left offset from the top, left position of the page. If not - * specified Float.NaN is returned. - */ - public Float getLeft() { - return left; - } - - /** - * Gets the top offset from the top, left position of the page specified by - * this destination. - * - * @return the top offset from the top, left position of the page. If not - * specified Float.NaN is returned. - */ - public Float getTop() { - return top; - } - - /** - * Gets the zoom level specifed by the destination. - * - * @return the specified zoom level, Float.NaN if not specified. - */ - public Float getZoom() { - return zoom; - } - - /** - * Gets the page reference represented by this destination - * - * @return reference of page that destination should show when executed. - */ - public Reference getRef() { - return ref; - } - - /** - * Gets the type used in a vector of destination syntax. Will be null - * if a named destination is used. - * - * @return type of destination syntax as defined by class constants. - */ - public Name getType() { - return type; - } - - /** - * Bottom coordinate of a zoom box, if present left, right and top should - * also be available. - * - * @return bottom coordinate of magnifcation box. - */ - public Float getBottom() { - return bottom; - } - - /** - * Right coordinate of a zoom box, if present bottom, left and top should - * also be available. - * - * @return rigth coordinate of zoom box - */ - public Float getRight() { - return right; - } - - /** - * Get the destination properties encoded in post script form. - * - * @return either a destination Name or a Vector representing the - * destination - */ - public Object getEncodedDestination() { - // write out the destination name - if (namedDestination != null) { - return namedDestination; - } - // build and return a fector of changed valued. - else if (object instanceof List) { - List v = new ArrayList(7); - if (ref != null) { - v.add(ref); - } - // named dest type - if (type != null) { - v.add(type); - } - // left - if (left != Float.NaN) { - v.add(left); - } - // bottom - if (bottom != Float.NaN) { - v.add(bottom); - } - // right - if (right != Float.NaN) { - v.add(right); - } - // top - if (top != Float.NaN) { - v.add(top); - } - // zoom - if (zoom != Float.NaN) { - v.add(zoom); - } - return v; - } - return null; - } - - /** - * Returns a summary of the annotation dictionary values. - * - * @return dictionary values. - */ - public String toString() { - return "Destination ref: " + getPageReference() + " , top: " + - getTop() + " , left: " + getLeft() + " , zoom: " + getZoom(); - } -} - - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Dictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Dictionary.java deleted file mode 100644 index 939ec076b5..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Dictionary.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - *

This class represents a PDF document's Dictionary object. A - * Dictionary object is an associative table containing pairs of objects, - * known as the dictionary's entries. The first element of each entry is the key - * and the second element is the value. Dictionary objects are the main building - * blocks of a PDF document. They are commonly used to collect and tie together - * the attributes of complex objects such as fonts or pages within a - * document.

- *

Most of the Objects found in the package org.icepdf.core.pobject.* extend - * this class. Dictionary objects by convention have a "Type" entry which - * identifies the type of object the dictionary describes. Classes that extend - * Dictionary add functionality based on the specified Dictionary type.

- * - * @since 1.0 - */ -public class Dictionary { - - public static final Name TYPE_KEY = new Name("Type"); - - public static final Name SUBTYPE_KEY = new Name("Subtype"); - - public static final Name LENGTH_KEY = new Name("Length"); - - public static final Name FORM_TYPE_KEY = new Name("FormType"); - - /** - * Pointer to the documents Library object which - * acts a central repository for the access of PDF object in the document. - */ - protected Library library; - - /** - * Table of associative pairs of objects. - */ - protected HashMap entries; - - /** - * Indicates if Dictionary has been initiated. - */ - protected boolean inited; - - /** - * Flag to indicate this object has been flaged for deletion. - */ - protected boolean isDeleted; - - /** - * Flags the object as new and not previously saved in the file - */ - protected boolean isNew; - - // reference of stream, needed for encryption support - private Reference pObjectReference; - - /** - * Creates a new instance of a Dictionary. - * - * @param library document library. - * @param entries dictionary entries. - */ - @SuppressWarnings("unchecked") - public Dictionary(Library library, HashMap entries) { - this.library = library; - this.entries = entries; - if (this.entries == null) { - this.entries = new HashMap(); - } - } - - /** - *

Sets the reference used to identify this Dictionary in the PDF document. - * The reference number and generation number of this reference is needed by - * the encryption algorithm to correctly decrypt this object.

- *

This method should only be used by the PDF Parser. Use of this method - * outside the context of the PDF Parser may result in unpredictable - * behavior.

- * - * @param reference Reference used to identify this Dictionary in the PDF - * document. - * @see #getPObjectReference() - */ - public void setPObjectReference(Reference reference) { - pObjectReference = reference; - } - - /** - *

Gets the reference used to identify this Dictionary in the PDF - * document. The reference number and generation number of this reference - * is needed by the encryption algorithm to correctly decrypt this object.

- * - * @return Reference used to identify this Dictionary in a PDF document. - * @see #setPObjectReference(org.icepdf.core.pobjects.Reference) - */ - public Reference getPObjectReference() { - return pObjectReference; - } - - /** - * Initiate the Dictionary. Retrieve any needed attributes. - */ - public void init() throws InterruptedException { - } - - /** - * Gets a copy of the entries that make up the Dictionary. - * - * @return a copy of the Dictionary's entries. - */ - public HashMap getEntries() { - return entries; - } - - public Object getObject(Name key) { - return library.getObject(entries, key); - } - - /** - * Gets a Number specified by the key in the dictionary - * entries. If the value is a reference, the Number object that the - * reference points to is returned. If the key cannot be found, - * or the resulting object is not a Number, then null is returned. - * - * @param key key to find in entries HashMap. - * @return Number that the key refers to - */ - protected Number getNumber(Name key) { - return library.getNumber(entries, key); - } - - /** - * Gets an int specified by the key in the dictionary - * entries. If the value is a reference, the int value that the - * reference points to is returned. - * - * @param key key to find in entries HashMap. - * @return int value if a valid key, else zero if the key does not point - * to an int or is invalid. - */ - public int getInt(Name key) { - return library.getInt(entries, key); - } - - /** - * Gets a float specified by the key in the dictionary - * entries. If the value is a reference, the float value that the - * reference points to is returned. - * - * @param key key to find in entries HashMap. - * @return float value if a valid key, else zero if the key does not point - * to a float or is invalid. - */ - public float getFloat(Name key) { - return library.getFloat(entries, key); - } - - /** - * Gets the PDF Documents Library. A Library object is the central repository - * of all objects that make up the PDF document hierarchy. - * - * @return documents library. - */ - public Library getLibrary() { - return library; - } - - public boolean isDeleted() { - return isDeleted; - } - - public void setDeleted(boolean deleted) { - isDeleted = deleted; - } - - public boolean isNew() { - return isNew; - } - - public void setNew(boolean aNew) { - isNew = aNew; - } - - /** - * Sets the dictionary key value, handling any encryption so dictionary can be written correctly. - * - * @param key dictionary key - * @param value key value. - * @return string value of the newly set string which will always be decrypted. - */ - protected String setString(final Name key, String value) { - // make sure we store an encrypted documents string as encrypted - entries.put(key, new LiteralStringObject(value, getPObjectReference(), library.getSecurityManager())); - return value; - } - - /** - * Sets the dictionary key value, handling any encryption so dictionary can be written correctly. - * - * @param key dictionary key - * @param value key value. - * @return string value of the newly set string which will always be decrypted. - */ - protected String setHexString(final Name key, String value) { - // make sure we store an encrypted documents string as encrypted - entries.put(key, new HexStringObject(value, getPObjectReference(), library.getSecurityManager())); - return value; - } - - /** - * Returns a summary of the dictionary entries. - * - * @return dictionary values. - */ - public String toString() { - return getClass().getName() + "=" + entries.toString(); - } -} - - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Document.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Document.java deleted file mode 100644 index ea2c4d6c5b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Document.java +++ /dev/null @@ -1,1339 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.SecurityCallback; -import org.icepdf.core.application.ProductInfo; -import org.icepdf.core.exceptions.PDFException; -import org.icepdf.core.exceptions.PDFSecurityException; -import org.icepdf.core.io.*; -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.pobjects.acroform.InteractiveForm; -import org.icepdf.core.pobjects.annotations.AbstractWidgetAnnotation; -import org.icepdf.core.pobjects.graphics.WatermarkCallback; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.pobjects.security.SecurityManager; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.LazyObjectLoader; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Parser; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.*; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

The Document class represents a PDF document and provides - * access to the hierarchy of objects contained in the body section of the - * PDF document. Most of the objects in the hierarchy are dictionaries which - * contain references to page content and other objects such such as annotations. - * For more information on the document object hierarchy, see the ICEpdf - * Developer's Guide.

- *

- *

The Document class also provides access to methods responsible - * for rendering PDF document content. Methods are available to capture page - * content to a graphics context or extract image and text data on a page-by-page - * basis.

- *

- *

If your PDF rendering application will be accessing encrypted documents, - * it is important to implement the SecurityCallback. This interface provides - * methods for getting password data from a user if needed.

- * - * @since 1.0 - */ -public class Document { - - private static final Logger logger = - Logger.getLogger(Document.class.toString()); - - /** - * Gets the version number of ICEpdf rendering core. This is not the version - * number of the PDF format used to encode this document. - * - * @return version number of ICEpdf's rendering core. - */ - public static String getLibraryVersion() { - return ProductInfo.PRIMARY + "." + ProductInfo.SECONDARY + "." + - ProductInfo.TERTIARY + " " + ProductInfo.RELEASE_TYPE; - } - - private static final String INCREMENTAL_UPDATER = - "org.icepdf.core.util.IncrementalUpdater"; - public static boolean foundIncrementalUpdater; - - static { - // check class bath for NFont library, and declare results. - try { - Class.forName(INCREMENTAL_UPDATER); - foundIncrementalUpdater = true; - } catch (ClassNotFoundException e) { - logger.log(Level.WARNING, "PDF write support was not found on the class path"); - } - } - - // optional watermark callback - private WatermarkCallback watermarkCallback; - - // core catalog, root of the document hierarchy. - private Catalog catalog; - - // We used to keep the document main PTrailer's PInfo, - // but now that's lazily loaded, so instead we keep the - // PTrailer itself, which can get us the PInfo whenever - private PTrailer pTrailer; - - // state manager for tracking object that have been touched in some way - // for editing purposes, - private StateManager stateManager; - - // This is the original file or url path of where the PDF document was load - // from - private String origin; - - // This is the location of the file when it is saved to the hard drive. This - // is usually only different from the origin if the the PDF document - // was loaded from a URL - private String cachedFilePath; - - // callback for password dialogs, or command line access. - private SecurityCallback securityCallback; - - // disable/enable file caching, overrides fileCachingSize. - private static boolean isCachingEnabled; - private static boolean isFileCachingEnabled; - private static int fileCacheMaxSize; - - // repository of all PDF object associated with this document. - private Library library = null; - private SeekableInput documentSeekableInput; - - static { - // sets if file caching is enabled or disabled. - isCachingEnabled = - Defs.sysPropertyBoolean("org.icepdf.core.streamcache.enabled", - false); - - isFileCachingEnabled = Defs.sysPropertyBoolean("org.icepdf.core.filecache.enabled", - true); - fileCacheMaxSize = Defs.intProperty("org.icepdf.core.filecache.size", 200000000); - } - - /** - * Creates a new instance of a Document. A Document class represents - * one PDF document. - */ - public Document() { - } - - /** - * Sets a page watermark implementation to be painted on top of the page - * content. Watermark can be specified for each page or once by calling - * document.setWatermark(). - * - * @param watermarkCallback watermark implementation. - */ - public void setWatermarkCallback(WatermarkCallback watermarkCallback) { - this.watermarkCallback = watermarkCallback; - } - - /** - * Utility method for setting the origin (filepath or URL) of this Document - * - * @param o new origin value - * @see #getDocumentOrigin() - */ - private void setDocumentOrigin(String o) { - origin = o; - if (logger.isLoggable(Level.CONFIG)) { - logger.config( - "MEMFREE: " + Runtime.getRuntime().freeMemory() + " of " + - Runtime.getRuntime().totalMemory()); - logger.config("LOADING: " + o); - } - } - - /** - * Sets the cached file path in the case of opening a file from a URL. - * - * @param o new cached file path value - * @see #getDocumentCachedFilePath - */ - private void setDocumentCachedFilePath(String o) { - cachedFilePath = o; - } - - /** - * Returns the cached file path in the case of opening a file from a URL. - * - * @return file path - */ - private String getDocumentCachedFilePath() { - return cachedFilePath; - } - - /** - * Load a PDF file from the given path and initiates the document's Catalog. - * - * @param filepath path of PDF document. - * @throws PDFException if an invalid file encoding. - * @throws PDFSecurityException if a security provider cannot be found - * or there is an error decrypting the file. - * @throws IOException if a problem setting up, or parsing the file. - */ - public void setFile(String filepath) - throws PDFException, PDFSecurityException, IOException { - setDocumentOrigin(filepath); - File file = new File(filepath); - FileInputStream inputStream = new FileInputStream(file); - int fileLength = inputStream.available(); - if (isFileCachingEnabled && file.length() > 0 && fileLength <= fileCacheMaxSize) { - // copy the file contents into byte[], for direct memory mapping. - byte[] data = new byte[fileLength]; - inputStream.read(data); - setByteArray(data, 0, fileLength, filepath); - } else { - RandomAccessFileInputStream rafis = - RandomAccessFileInputStream.build(new File(filepath)); - setInputStream(rafis); - } - if (inputStream != null) { - inputStream.close(); - } - } - - /** - * Load a PDF file from the given URL and initiates the document's Catalog. - * If the system property org.icepdf.core.streamcache.enabled=true, the file - * will be cached to a temp file; otherwise, the complete document stream will - * be stored in memory. - * - * @param url location of file. - * @throws PDFException an invalid file encoding. - * @throws PDFSecurityException if a security provider can not be found - * or there is an error decrypting the file. - * @throws IOException if a problem downloading, setting up, or parsing the file. - */ - public void setUrl(URL url) - throws PDFException, PDFSecurityException, IOException { - InputStream in = null; - try { - // make a connection - URLConnection urlConnection = url.openConnection(); - - // Create a stream on the URL connection - in = urlConnection.getInputStream(); - - String pathOrURL = url.toString(); - - setInputStream(in, pathOrURL); - } finally { - if (in != null) { - in.close(); - } - } - } - - /** - * Load a PDF file from the given input stream and initiates the document's Catalog. - * If the system property org.icepdf.core.streamcache.enabled=true, the file - * will be cached to a temp file; otherwise, the complete document stream will - * be stored in memory. - * - * @param in input stream containing PDF data - * @param pathOrURL value assigned to document origin - * @throws PDFException an invalid stream or file encoding - * @throws PDFSecurityException if a security provider can not be found - * or there is an error decrypting the file. - * @throws IOException if a problem setting up, or parsing the SeekableInput. - */ - public void setInputStream(InputStream in, String pathOrURL) - throws PDFException, PDFSecurityException, IOException { - setDocumentOrigin(pathOrURL); - - if (!isCachingEnabled) { -//System.out.println("Started downloading PDF to memory : " + (new java.util.Date())); - // read into memory first - ConservativeSizingByteArrayOutputStream byteArrayOutputStream = - new ConservativeSizingByteArrayOutputStream(100 * 1024); - - // write the bytes. - byte[] buffer = new byte[4096]; - int length; -// int pdfFileSize = 0; - // in.read will block until the end of the file is read. - while ((length = in.read(buffer, 0, buffer.length)) > 0) { - byteArrayOutputStream.write(buffer, 0, length); -// pdfFileSize += length; - } - byteArrayOutputStream.flush(); - byteArrayOutputStream.close(); - int size = byteArrayOutputStream.size(); - byteArrayOutputStream.trim(); - byte[] data = byteArrayOutputStream.relinquishByteArray(); -//System.out.println("Finished downloading PDF to memory : " + (new java.util.Date()) + " pdfFileSize: " + pdfFileSize); - - // finally read the cached file - SeekableByteArrayInputStream byteArrayInputStream = - new SeekableByteArrayInputStream(data, 0, size); - setInputStream(byteArrayInputStream); - } - // if caching is allowed cache the url to file - else { -//System.out.println("Started downloading PDF to disk : " + (new java.util.Date())); - // create tmp file and write bytes to it. - File tempFile = File.createTempFile( - "ICEpdfTempFile" + getClass().hashCode(), - ".tmp"); - // Delete temp file on exit - tempFile.deleteOnExit(); - - // Write the data to the temp file. - FileOutputStream fileOutputStream = - new FileOutputStream(tempFile.getAbsolutePath(), true); - - // write the bytes. - byte[] buffer = new byte[4096]; - int length; -// int pdfFileSize = 0; - while ((length = in.read(buffer, 0, buffer.length)) > 0) { - fileOutputStream.write(buffer, 0, length); -// pdfFileSize += length; - } - fileOutputStream.flush(); - fileOutputStream.close(); -//System.out.println("Finished downloading PDF to disk : " + (new java.util.Date()) + " pdfFileSize: " + pdfFileSize); - - setDocumentCachedFilePath(tempFile.getAbsolutePath()); - - // finally read the cached file - RandomAccessFileInputStream rafis = - RandomAccessFileInputStream.build(tempFile); - setInputStream(rafis); - } - } - - /** - * Load a PDF file from the given byte array and initiates the document's Catalog. - * If the system propertyorg.icepdf.core.streamcache.enabled=true, the file - * will be cached to a temp file; otherwise, the complete document stream will - * be stored in memory. - * The given byte array is not necessarily copied, and will try to be directly - * used, so do not modify it after passing it to this method. - * - * @param data byte array containing PDF data - * @param offset the index into the byte array where the PDF data begins - * @param length the number of bytes in the byte array belonging to the PDF data - * @param pathOrURL value assigned to document origin - * @throws PDFException an invalid stream or file encoding - * @throws PDFSecurityException if a security provider can not be found - * or there is an error decrypting the file. - * @throws IOException if a problem setting up, or parsing the SeekableInput. - */ - public void setByteArray(byte[] data, int offset, int length, String pathOrURL) - throws PDFException, PDFSecurityException, IOException { - setDocumentOrigin(pathOrURL); - - if (!isCachingEnabled) { - // finally read the cached file - SeekableByteArrayInputStream byteArrayInputStream = - new SeekableByteArrayInputStream(data, offset, length); - setInputStream(byteArrayInputStream); - } - // if caching is allowed cache the url to file - else { -//System.out.println("Started downloading PDF to disk : " + (new java.util.Date())); - // create tmp file and write bytes to it. - File tempFile = File.createTempFile( - "ICEpdfTempFile" + getClass().hashCode(), - ".tmp"); - // Delete temp file on exit - tempFile.deleteOnExit(); - - // Write the data to the temp file. - FileOutputStream fileOutputStream = - new FileOutputStream(tempFile.getAbsolutePath(), true); - - // write the bytes. -// int pdfFileSize = 0; - fileOutputStream.write(data, offset, length); -// pdfFileSize += length; - fileOutputStream.flush(); - fileOutputStream.close(); -//System.out.println("Finished downloading PDF to disk : " + (new java.util.Date()) + " pdfFileSize: " + pdfFileSize); - - setDocumentCachedFilePath(tempFile.getAbsolutePath()); - - // finally read the cached file - RandomAccessFileInputStream rafis = - RandomAccessFileInputStream.build(tempFile); - setInputStream(rafis); - } - } - - /** - * Load a PDF file from the given SeekableInput stream and initiates the - * document's Catalog. - * - * @param in input stream containing PDF data - * @param pathOrURL value assigned to document origin - * @throws PDFException an invalid stream or file encoding - * @throws PDFSecurityException if a security provider can not be found - * or there is an error decrypting the file. - * @throws IOException if a problem setting up, or parsing the SeekableInput. - */ - public void setInputStream(SeekableInput in, String pathOrURL) - throws PDFException, PDFSecurityException, IOException { - setDocumentOrigin(pathOrURL); - setInputStream(in); - } - - /** - * Sets the input stream of the PDF file to be rendered. - * - * @param in inputStream containing PDF data stream - * @throws PDFException if error occurs - * @throws PDFSecurityException security error - * @throws IOException io error during stream handling - */ - private void setInputStream(final SeekableInput in) - throws PDFException, PDFSecurityException, IOException { - try { - documentSeekableInput = in; - - // create library to hold all document objects - library = new Library(); - - // reference the stream and origin with library so we can handle verification and writing of signatures. - library.setDocumentInput(documentSeekableInput); - - // if interactive show visual progress bar - //ProgressMonitorInputStream monitor = null; - - boolean loaded = false; - try { - loadDocumentViaXRefs(in); - - // initiate the catalog, build the outline for the document - // this is the best test to see if everything is in order. - if (catalog != null) { - catalog.init(); - } - - loaded = true; - } catch (PDFException e) { - throw e; - } catch (PDFSecurityException e) { - throw e; - } catch (Exception e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Cross reference deferred loading failed, will fall back to linear reading."); - } - } - - if (!loaded) { - // Cleanup any bits left behind by the failed xref loading - if (catalog != null) { - catalog = null; - } - if (library != null) { - library = null; - } - library = new Library(); - pTrailer = null; - - in.seekAbsolute(0L); - loadDocumentViaLinearTraversal(in); - - // initiate the catalog, build the outline for the document - if (catalog != null) { - catalog.init(); - } - } - - // create new instance of state manager and add it to the library - stateManager = new StateManager(pTrailer); - library.setStateManager(stateManager); - } catch (PDFException e) { - logger.log(Level.FINE, "Error loading PDF file during linear parse.", e); - dispose(); - throw e; - } catch (PDFSecurityException e) { - dispose(); - throw e; - } catch (IOException e) { - dispose(); - throw e; - } catch (Exception e) { - dispose(); - logger.log(Level.SEVERE, "Error loading PDF Document.", e); - throw new IOException(e.getMessage()); - } - } - - /** - * Uitility method for loading the documents objects from the Xref table. - * - * @param in input stream to parse - * @throws IOException an i/o problem - * @throws PDFException an invalid stream or file encoding - * @throws PDFSecurityException if a security provider can not be found - * or there is an error decrypting the file. - */ - private void loadDocumentViaXRefs(SeekableInput in) - throws PDFException, PDFSecurityException, IOException { - //if( true ) throw new RuntimeException("Fallback to linear traversal"); - int offset = skipPastAnyPrefixJunk(in); - long xrefPosition = getInitialCrossReferencePosition(in) + offset; - PTrailer documentTrailer = null; - if (xrefPosition > 0L) { - in.seekAbsolute(xrefPosition); - - Parser parser = new Parser(in); - Object obj = parser.getObject(library); - if (obj instanceof PObject) - obj = ((PObject) obj).getObject(); - PTrailer trailer = (PTrailer) obj; - //PTrailer trailer = (PTrailer) parser.getObject( library ); - if (trailer == null) - throw new RuntimeException("Could not find trailer"); - if (trailer.getPrimaryCrossReference() == null) - throw new RuntimeException("Could not find cross reference"); - trailer.setPosition(xrefPosition); - - documentTrailer = trailer; - // any prev/next trails are loaded lazily - } - if (documentTrailer == null) - throw new RuntimeException("Could not find document trailer"); - if (offset > 0) { - // mark the offset, so that it can be correct for later during - // object retrieval. - documentTrailer.getCrossReferenceTable().setOffset(offset); - } - - LazyObjectLoader lol = new LazyObjectLoader( - library, in, documentTrailer.getPrimaryCrossReference()); - library.setLazyObjectLoader(lol); - - pTrailer = documentTrailer; - catalog = documentTrailer.getRootCatalog(); - library.setCatalog(catalog); - - if (catalog == null) - throw new NullPointerException("Loading via xref failed to find catalog"); - - boolean madeSecurityManager = makeSecurityManager(documentTrailer); - if (madeSecurityManager) { - attemptAuthorizeSecurityManager(); - } - // setup a signature permission dictionary - configurePermissions(); - } - - private long getInitialCrossReferencePosition(SeekableInput in) throws IOException { - in.seekEnd(); - - long endOfFile = in.getAbsolutePosition(); - long currentPosition = endOfFile - 1; - long afterStartxref = -1; - String startxref = "startxref"; - int startxrefIndexToMatch = startxref.length() - 1; - - while (currentPosition >= 0 && (endOfFile - currentPosition) < 2048) { - in.seekAbsolute(currentPosition); - int curr = in.read(); - if (curr < 0) - throw new EOFException("Could not find startxref at end of file"); - if (curr == startxref.charAt(startxrefIndexToMatch)) { - // If we've matched the whole string - if (startxrefIndexToMatch == 0) { - afterStartxref = currentPosition + startxref.length(); - break; - } - startxrefIndexToMatch--; - } else - startxrefIndexToMatch = startxref.length() - 1; - currentPosition--; - } - if (afterStartxref < 0) - throw new EOFException("Could not find startxref near end of file"); - - in.seekAbsolute(afterStartxref); - Parser parser = new Parser(in); - Number xrefPositionObj = (Number) parser.getToken(); - if (xrefPositionObj == null) - throw new RuntimeException("Could not find ending cross reference position"); - return xrefPositionObj.longValue(); - } - - /** - * Uitily method for parsing a PDF documents object. This should only be - * called when the xref lookup fails or the file is being loaded - * via byte input because file caching is not enabled. - * - * @param seekableInput stream representing whole pdf document - * @throws PDFException an invalid stream or file encoding - * @throws PDFSecurityException if a security provider can not be found - * or there is an error decrypting the file. - */ - private void loadDocumentViaLinearTraversal(SeekableInput seekableInput) - throws PDFException, PDFSecurityException, IOException { - - InputStream in = seekableInput.getInputStream(); - - int objectsOffset = skipPastAnyPrefixJunk(in); - - library.setLinearTraversal(); - - // NOTE: when we implement linerized document we should be able to - // rework this method. - Parser parser = new Parser(in); - - // document Trailer, holds encryption info - PTrailer documentTrailer = null; - - // Loop through all objects that where parsed from the data stream - List documentObjects = new ArrayList(); - Object pdfObject; - while (true) { - // parse all of the objects in the stream, objects are added - // to the library object. - pdfObject = parser.getObject(library); - - // eof or io error result in break - if (pdfObject == null) { - break; - } - - // unwrap pObject for catalog and ptrailer lookups. - if (pdfObject instanceof PObject) { - PObject tmp = (PObject) pdfObject; - // apply the offset value of the object. - tmp.setLinearTraversalOffset(objectsOffset + parser.getLinearTraversalOffset()); - // store reference so we can rebuild the xref table. - documentObjects.add(tmp); - Object obj = tmp.getObject(); - if (obj != null) - pdfObject = obj; - } - - // find the catalog which has information on outlines - // which is need by the gui - if (pdfObject instanceof Catalog) { - catalog = (Catalog) pdfObject; - } - - // Find the trailer object so that we can get the encryption information - // trailer information is not a PObject and thus there should - if (pdfObject instanceof PTrailer) { - if (documentTrailer == null) { - documentTrailer = (PTrailer) pdfObject; - } else { - // add more trailer data to the original - PTrailer nextTrailer = (PTrailer) pdfObject; - if (nextTrailer.getPrev() > 0) { - documentTrailer.addNextTrailer(nextTrailer); - documentTrailer = nextTrailer; - } - } - } - } - - // apply the new object offset values so that the object can be retrieved - // using the actual index in the file - CrossReference refs = documentTrailer.getPrimaryCrossReference(); - Object entry; - for (PObject pObject : documentObjects) { - entry = refs.getEntryForObject(pObject.getReference().getObjectNumber()); - if (entry != null && entry instanceof CrossReference.UsedEntry) { - ((CrossReference.UsedEntry) entry).setFilePositionOfObject( - pObject.getLinearTraversalOffset()); - } else { - refs.addUsedEntry(pObject.getReference().getObjectNumber(), - pObject.getLinearTraversalOffset(), - pObject.getReference().getGenerationNumber()); - } - } - - if (logger.isLoggable(Level.FINER)) { - for (PObject pobjects : documentObjects) { - // display object information in debug mode - logger.finer(pobjects.getClass().getName() + " " + - pobjects.getLinearTraversalOffset() + " " + - pobjects); - } - } - - - // The LazyObjectLoader is used for both reading from a SeekableInput, - // and also accessing ObjectStreams. - // So, even with linear traversal, we still need it for PDF 1.5 documents - if (documentTrailer != null) { - LazyObjectLoader lol = new LazyObjectLoader( - library, seekableInput, documentTrailer.getPrimaryCrossReference()); - library.setLazyObjectLoader(lol); - } - - pTrailer = documentTrailer; - library.setCatalog(catalog); - - // Add Document information object to catalog - if (documentTrailer != null) { - boolean madeSecurityManager = makeSecurityManager(documentTrailer); - if (madeSecurityManager) - attemptAuthorizeSecurityManager(); - } - - // setup a signature handler - configurePermissions(); - } - - /** - * Typically, if we're doing a linear traversal, it's because the PDF file - * is corrupted, usually by junk being appended to it, or the ending - * being truncated, or, in this case, from junk being inserted into the - * beginning of the file, skewing all the xref object offsets. - *

- * We're going to look for the "%PDF-1." string that most PDF files start - * with. If we do find it, then leave the InputStream after the next - * whitespace, else rewind back to the beginning, in case the file was - * never encoded with the PDF version comment. - * - * @param in InputStream derived from SeekableInput.getInputStream() - */ - private int skipPastAnyPrefixJunk(InputStream in) { - if (!in.markSupported()) - return 0; - try { - final int scanLength = 2048; - final String scanFor = "%PDF-"; - final int scanForLength = scanFor.length(); - int scanForIndex = 0; - boolean scanForWhiteSpace = false; - in.mark(scanLength); - for (int i = 0; i < scanLength; i++) { - int data = in.read(); - if (data < 0) { - in.reset(); - return 0; - } - // scan to the end of the comment line and return the offset - if (scanForWhiteSpace) { - scanForIndex++; - if (Parser.isWhitespace((char) data)) { - return scanForIndex; - } - } else { - if (data == scanFor.charAt(scanForIndex)) { - scanForIndex++; - if (scanForIndex == scanForLength) { - // Now read until we find white space - scanForWhiteSpace = true; - } - } else - scanForIndex = 0; - } - } - // Searched through scanLength number of bytes and didn't find it, - // so reset, in case it was never there to find - in.reset(); - } catch (IOException e) { - try { - in.reset(); - } catch (IOException e2) { - // forget about it. - } - } - return 0; - } - - /** - * Skips junk and keeps track of the offset so that later corrections can - * be made for object seeks. - * - * @param in input stream to parse. - * @return 0 if file header is well formed, otherwise the offset to where - * the document header starts. - */ - private int skipPastAnyPrefixJunk(SeekableInput in) { - if (!in.markSupported()) - return 0; - try { - final int scanLength = 2048; - final String scanFor = "%PDF-1."; - int scanForIndex = 0; - in.mark(scanLength); - for (int i = 0; i < scanLength; i++) { - int data = in.read(); - if (data < 0) { - in.reset(); - return 0; - } - if (data == scanFor.charAt(scanForIndex)) { - return i; - } else { - scanForIndex = 0; - } - } - // Searched through scanLength number of bytes and didn't find it, - // so reset, in case it was never there to find - in.reset(); - } catch (IOException e) { - try { - in.reset(); - } catch (IOException e2) { - // forget about it. - } - } - return 0; - } - - - /** - * Utility method for building the SecurityManager if the document - * contains a crypt entry in the PTrailer. - * - * @param documentTrailer document trailer - * @return Whether or not a SecurityManager was made, and set in the Library - * @throws PDFSecurityException if there is an issue finding encryption libraries. - */ - private boolean makeSecurityManager(PTrailer documentTrailer) throws PDFSecurityException { - /** - * Before a security manager can be created or needs to be created - * we need the following - * 1. The trailer object must have an encrypt entry - * 2. The trailer object must have an ID entry - */ - boolean madeSecurityManager = false; - HashMap encryptDictionary = documentTrailer.getEncrypt(); - List fileID = documentTrailer.getID(); - // check for a missing file ID. - if (fileID == null) { - // we have a couple malformed documents that don't specify a FILE ID. - // but proving two empty string allows the document to be decrypted. - fileID = new ArrayList(2); - fileID.add(new LiteralStringObject("")); - fileID.add(new LiteralStringObject("")); - } - - if (encryptDictionary != null && fileID != null) { - // create new security manager - library.setSecurityManager(new SecurityManager( - library, encryptDictionary, fileID)); - madeSecurityManager = true; - } - return madeSecurityManager; - } - - /** - * Initializes permission object as it is uses with encrypt permission to define - * document characteristics at load time. - * - * @return true if permissions where found, false otherwise. - */ - private boolean configurePermissions() { - if (catalog != null) { - Permissions permissions = catalog.getPermissions(); - if (permissions != null) { - library.setPermissions(permissions); - if (logger.isLoggable(Level.FINER)) { - logger.finer("Document perms dictionary found and configured. "); - } - return true; - } - } - return false; - } - - /** - * If the document has a SecurityManager it is encrypted and as a result the - * following method is used with the SecurityCallback to prompt a user for - * a password if needed. - * - * @throws PDFSecurityException error during authorization manager setup - */ - private void attemptAuthorizeSecurityManager() throws PDFSecurityException { - // check if pdf is password protected, by passing in black - // password - if (!library.getSecurityManager().isAuthorized("")) { - // count password tries - int count = 1; - // store temporary password - String password; - - // Give user 3 chances to type the correct password - // before throwing security exceptions - while (true) { - // Display password dialog - // make sure a callback has been set. - if (securityCallback != null) { - password = securityCallback.requestPassword(this); - if (password == null) { - throw new PDFSecurityException("Encryption error"); - } - } else { - throw new PDFSecurityException("Encryption error"); - } - - // Verify new password, proceed if authorized, - // fatal exception otherwise. - if (library.getSecurityManager().isAuthorized(password)) { - break; - } - count++; - // after 3 tries throw the the error. - if (count > 3) { - throw new PDFSecurityException("Encryption error"); - } - } - } - - // set the encryption flag on catalog - library.setEncrypted(true); - } - - /** - * Gets the page dimension of the indicated page number using the specified - * rotation factor. - * - * @param pageNumber Page number for the given dimension. The page - * number is zero-based. - * @param userRotation Rotation, in degrees, that has been applied to page - * when calculating the dimension. - * @return page dimension for the specified page number - * @see #getPageDimension(int, float, float) - */ - public PDimension getPageDimension(int pageNumber, float userRotation) { - Page page = catalog.getPageTree().getPage(pageNumber); - return page.getSize(userRotation); - } - - /** - * Gets the page dimension of the indicated page number using the specified - * rotation and zoom settings. If the page does not exist then a zero - * dimension is returned. - * - * @param pageNumber Page number for the given dimension. The page - * number is zero-based. - * @param userRotation Rotation, in degrees, that has been applied to page - * when calculating the dimension. - * @param userZoom Any deviation from the page's actual size, by zooming in or out. - * @return page dimension for the specified page number. - * @see #getPageDimension(int, float) - */ - public PDimension getPageDimension(int pageNumber, float userRotation, float userZoom){ - Page page = catalog.getPageTree().getPage(pageNumber); - if (page != null) { - return page.getSize(userRotation, userZoom); - } else { - return new PDimension(0, 0); - } - } - - /** - * Returns the origin (filepath or URL) of this Document. This is the original - * location of the file where the method getDocumentLocation returns the actual - * location of the file. The origin and location of the document will only - * be different if it was loaded from a URL or an input stream. - * - * @return file path or URL - * @see #getDocumentLocation - */ - public String getDocumentOrigin() { - return origin; - } - - /** - * Returns the file location or URL of this Document. This location may be different - * from the file origin if the document was loaded from a URL or input stream. - * If the file was loaded from a URL or input stream the file location is - * the path to where the document content is cached. - * - * @return file path - * @see #getDocumentOrigin() - */ - public String getDocumentLocation() { - if (cachedFilePath != null) - return cachedFilePath; - return origin; - } - - /** - * Gets an instance of the the document state manager which stores references - * of object that need to be written to file. - * - * @return stateManager instance for this document. - */ - public StateManager getStateManager() { - return stateManager; - } - - /** - * Returns the total number of pages in this document. - * - * @return number of pages in the document - */ - public int getNumberOfPages() { - try { - return catalog.getPageTree().getNumberOfPages(); - } catch (Exception e) { - logger.log(Level.FINE, "Error getting number of pages.", e); - } - return 0; - } - - /** - * Paints the contents of the given page number to the graphics context using - * the specified rotation, zoom, rendering hints and page boundary. - * - * @param pageNumber Page number to paint. The page number is zero-based. - * @param g graphics context to which the page content will be painted. - * @param renderHintType Constant specified by the GraphicsRenderingHints class. - * There are two possible entries, SCREEN and PRINT, each with configurable - * rendering hints settings. - * @param pageBoundary Constant specifying the page boundary to use when - * painting the page content. - * @param userRotation Rotation factor, in degrees, to be applied to the rendered page. - * @param userZoom Zoom factor to be applied to the rendered page. - */ - public void paintPage(int pageNumber, Graphics g, final int renderHintType, - final int pageBoundary, float userRotation, float userZoom) throws InterruptedException { - Page page = catalog.getPageTree().getPage(pageNumber); - page.init(); - PDimension sz = page.getSize(userRotation, userZoom); - int pageWidth = (int) sz.getWidth(); - int pageHeight = (int) sz.getHeight(); - - Graphics gg = g.create(0, 0, pageWidth, pageHeight); - page.paint(gg, renderHintType, pageBoundary, userRotation, userZoom); - - gg.dispose(); - } - - /** - * Dispose of Document, freeing up all used resources. - */ - public void dispose() { - - if (documentSeekableInput != null) { - try { - documentSeekableInput.close(); - } catch (IOException e) { - logger.log(Level.FINE, "Error closing document input stream.", e); - } - documentSeekableInput = null; - } - - String fileToDelete = getDocumentCachedFilePath(); - if (fileToDelete != null) { - File file = new File(fileToDelete); - boolean success = file.delete(); - if (!success && logger.isLoggable(Level.WARNING)) { - logger.warning("Error deleting URL cached to file " + fileToDelete); - } - } - } - - /** - * Takes the internal PDF data, which may be in a file or in RAM, - * and write it to the provided OutputStream. - * The OutputStream is not flushed or closed, in case this method's - * caller requires otherwise. - * - * @param out OutputStream to which the PDF file bytes are written. - * @return The length of the PDF file copied - * @throws IOException if there is some problem reading or writing the PDF data - */ - public long writeToOutputStream(OutputStream out) throws IOException { - long documentLength = documentSeekableInput.getLength(); - SeekableInputConstrainedWrapper wrapper = new SeekableInputConstrainedWrapper( - documentSeekableInput, 0L, documentLength); - try { - - - byte[] buffer = new byte[4096]; - int length; - while ((length = wrapper.read(buffer, 0, buffer.length)) > 0) { - out.write(buffer, 0, length); - } - } catch (Throwable e) { - logger.log(Level.FINE, "Error writing PDF output stream.", e); - throw new IOException(e.getMessage()); - } finally { - try { - wrapper.close(); - } catch (IOException e) { - // forget about it. - } - } - return documentLength; - } - - /** - * Copies the pre-existing PDF file, and appends an incremental update for - * any edits, to the specified OutputStream. For the pre-existing PDF - * content copying, writeToOutputStream(OutputStream out) is used. - * - * @param out OutputStream to which the PDF file bytes are written. - * @return The length of the PDF file saved - * @throws IOException if there is some problem reading or writing the PDF data - */ - public long saveToOutputStream(OutputStream out) throws IOException { - long documentLength = writeToOutputStream(out); - if (foundIncrementalUpdater) { - try { - Class incrementalUpdaterClass = Class.forName(INCREMENTAL_UPDATER); - Object[] argValues = {this, out, documentLength}; - Method method = incrementalUpdaterClass.getDeclaredMethod( - "appendIncrementalUpdate", - new Class[]{Document.class, OutputStream.class, Long.TYPE}); - long appendedLength = (Long) method.invoke(null, argValues); - return documentLength + appendedLength; - } catch (Throwable e) { - logger.log(Level.FINE, "Could not call incremental updater.", e); - } - } - return documentLength; - } - - /** - * Gets an Image of the specified page. The image size is automatically - * calculated given the page boundary, user rotation and zoom. The rendering - * quality is defined by GraphicsRenderingHints.SCREEN. - * - * @param pageNumber Page number of the page to capture the image rendering. - * The page number is zero-based. - * @param renderHintType Constant specified by the GraphicsRenderingHints class. - * There are two possible entries, SCREEN and PRINT each with configurable - * rendering hints settings. - * @param pageBoundary Constant specifying the page boundary to use when - * painting the page content. Typically use Page.BOUNDARY_CROPBOX. - * @param userRotation Rotation factor, in degrees, to be applied to the rendered page. - * Arbitrary rotations are not currently supported for this method, - * so only the following values are valid: 0.0f, 90.0f, 180.0f, 270.0f. - * @param userZoom Zoom factor to be applied to the rendered page. - * @return an Image object of the current page. - */ - public Image getPageImage(int pageNumber, - final int renderHintType, final int pageBoundary, - float userRotation, float userZoom) throws InterruptedException { - Page page = catalog.getPageTree().getPage(pageNumber); - page.init(); - PDimension sz = page.getSize(pageBoundary, userRotation, userZoom); - - int pageWidth = (int) sz.getWidth(); - int pageHeight = (int) sz.getHeight(); - - BufferedImage image = ImageUtility.createCompatibleImage(pageWidth, pageHeight); - Graphics g = image.createGraphics(); - - page.paint(g, renderHintType, - pageBoundary, userRotation, userZoom); - g.dispose(); - - return image; - } - - /** - * Exposes a page's PageText object which can be used to get text with - * in the PDF document. The PageText.toString() is the simplest way to - * get a pages text. This utility call does not parse the whole stream - * and is best suited for text extraction functionality as it faster then - * #getPageViewText(int). - * - * @param pageNumber Page number of page in which text extraction will act on. - * The page number is zero-based. - * @return page PageText data Structure. - * @see #getPageViewText(int). - */ - public PageText getPageText(int pageNumber) throws InterruptedException { - PageTree pageTree = catalog.getPageTree(); - if (pageNumber >= 0 && pageNumber < pageTree.getNumberOfPages()) { - Page pg = pageTree.getPage(pageNumber); - return pg.getText(); - } else { - return null; - } - } - - /** - * Exposes a page's PageText object which can be used to get text with - * in the PDF document. The PageText.toString() is the simplest way to - * get a pages text. The pageText hierarchy can be used to search for - * selected text or used to set text as highlighted. - * - * @param pageNumber Page number of page in which text extraction will act on. - * The page number is zero-based. - * @return page PageText data Structure. - */ - public PageText getPageViewText(int pageNumber) throws InterruptedException{ - PageTree pageTree = catalog.getPageTree(); - if (pageNumber >= 0 && pageNumber < pageTree.getNumberOfPages()) { - Page pg = pageTree.getPage(pageNumber); - return pg.getViewText(); - } else { - return null; - } - } - - /** - * Gets the security manager for this document. If the document has no - * security manager null is returned. - * - * @return security manager for document if available. - */ - public SecurityManager getSecurityManager() { - return library.getSecurityManager(); - } - - /** - * Sets the security callback to be used for this document. The security - * callback allows a mechanism for prompting a user for a password if the - * document is password protected. - * - * @param securityCallback a class which implements the SecurityCallback - * interface. - */ - public void setSecurityCallback(SecurityCallback securityCallback) { - this.securityCallback = securityCallback; - } - - /** - * Gets the document's information as specified in the PTrailer in the document - * hierarchy. - * - * @return document information - * @see org.icepdf.core.pobjects.PInfo for more information. - */ - public PInfo getInfo() { - if (pTrailer == null) - return null; - return pTrailer.getInfo(); - } - - /** - * Enables or disables the form widget annotation highlighting. Generally not use for print but can be very - * useful for highlight input fields in a Viewer application. - * - * @param highlight true to enable highlight mode, otherwise; false. - */ - public void setFormHighlight(boolean highlight) { - // iterate over the document annotations and set the appropriate highlight value. - if (catalog != null && catalog.getInteractiveForm() != null) { - InteractiveForm interactiveForm = catalog.getInteractiveForm(); - ArrayList widgets = interactiveForm.getFields(); - if (widgets != null) { - for (Object widget : widgets) { - descendFormTree(widget, highlight); - } - } - } - } - - /** - * Recursively set highlight on all the form fields. - * - * @param formNode root form node. - */ - private void descendFormTree(Object formNode, boolean highLight) { - if (formNode instanceof AbstractWidgetAnnotation) { - ((AbstractWidgetAnnotation) formNode).setEnableHighlightedWidget(highLight); - } else if (formNode instanceof FieldDictionary) { - // iterate over the kid's array. - FieldDictionary child = (FieldDictionary) formNode; - formNode = child.getKids(); - if (formNode != null) { - ArrayList kidsArray = (ArrayList) formNode; - for (Object kid : kidsArray) { - if (kid instanceof Reference) { - kid = library.getObject((Reference) kid); - } - if (kid instanceof AbstractWidgetAnnotation) { - ((AbstractWidgetAnnotation) kid).setEnableHighlightedWidget(highLight); - } else if (kid instanceof FieldDictionary) { - descendFormTree(kid, highLight); - } - } - } - - } - } - - /** - * Gets a vector of Images where each index represents an image inside - * the specified page. The images are returned in the size in which they - * where embedded in the PDF document, which may be different than the - * size displayed when the complete PDF page is rendered. - * - * @param pageNumber page number to act on. Zero-based page number. - * @return vector of Images inside the current page - */ - public List getPageImages(int pageNumber) throws InterruptedException { - Page pg = catalog.getPageTree().getPage(pageNumber); - pg.init(); - return pg.getImages(); - } - - /** - * Gets the Document Catalog's PageTree entry as specified by the Document - * hierarchy. The PageTree can be used to obtain detailed information about - * the Page object which makes up the document. - * - * @return PageTree specified by the document hierarchy. Null if the document - * has not yet loaded or the catalog can not be found. - */ - public PageTree getPageTree() { - if (catalog != null) { - PageTree pageTree = catalog.getPageTree(); - if (pageTree != null) { - pageTree.setWatermarkCallback(watermarkCallback); - } - return pageTree; - } else { - return null; - } - } - - /** - * Gets the Document's Catalog as specified by the Document hierarchy. The - * Catalog can be used to traverse the Document's hierarchy. - * - * @return document's Catalog object; null, if one does not exist. - */ - public Catalog getCatalog() { - return catalog; - } - - /** - * Sets the caching mode when handling file loaded by an URI. If enabled - * URI streams will be cached to disk, otherwise they will be stored in - * memory. This method must be set before a call to setByteArray() or - * setInputStream() is called. - * - * @param cachingEnabled true to enable, otherwise false. - */ - public static void setCachingEnabled(boolean cachingEnabled) { - isCachingEnabled = cachingEnabled; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/EmbeddedFileStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/EmbeddedFileStream.java deleted file mode 100644 index 702a8534f2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/EmbeddedFileStream.java +++ /dev/null @@ -1,192 +0,0 @@ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.security.SecurityManager; -import org.icepdf.core.util.Library; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; - -/** - * If a PDF file contains file specifications that refer to an external file and the PDF file is archived or - * transmitted, some provision should be made to ensure that the external references will remain valid. One way to - * do this is to arrange for copies of the external files to accompany the PDF file. Embedded file streams (PDF 1.3) - * address this problem by allowing the contents of referenced files to be embedded directly within the body of the - * PDF file. This makes the PDF file a self-contained unit that can be stored or transmitted as a single entity. - * - * @since 6.2 - */ -public class EmbeddedFileStream extends Dictionary { - - /** - * An embedded file parameter dictionary that shall contain additional file-specific information. - */ - public static final Name PARAMS_KEY = new Name("Params"); - - /** - * The size of the uncompressed embedded file, in bytes. - */ - public static final Name PARAMS_SIZE_KEY = new Name("Size"); - - /** - * The date and time when the embedded file was created. - */ - public static final Name PARAMS_CREATION_DATE_KEY = new Name("CreationDate"); - - /** - * The date and time when the embedded file was last modified. - */ - public static final Name PARAMS_MOD_DATE_KEY = new Name("ModDate"); - - /** - * A sub dictionary containing additional information specific to Mac OS files (see Table 47). - */ - public static final Name PARAMS_MAC_KEY = new Name("Mac"); - /** - * The embedded file’s file type. It shall be encoded as an integer according to Mac OS conventions: a 4-character - * ASCII text literal, that shall be a 32-bit integer, with the high-order byte first. - */ - public static final Name PARAMS_MAC_SUBTYPE_KEY = new Name("Subtype"); - /** - * The embedded file’s creator signature shall be encoded in the same way as Subtype. - */ - public static final Name PARAMS_MAC_CREATOR_KEY = new Name("Creator"); - /** - * the binary contents of the embedded file’s resource fork. - */ - public static final Name PARAMS_MAC_RES_FORK_KEY = new Name("ResFork"); - - /** - * A 16-byte string that is the checksum of the bytes of the uncompressed embedded file. The checksum shall be - * calculated by applying the standard MD5 message-digest algorithm (described in Internet RFC 1321, The MD5 - * Message-Digest Algorithm; see the Bibliography) to the bytes of the embedded file stream. - */ - public static final Name PARAMS_CHECK_SUM_KEY = new Name("CheckSum"); - - protected Stream fileStream; - private SecurityManager securityManager; - - public EmbeddedFileStream(Library library, Stream fileStream) { - super(library, fileStream.getEntries()); - this.securityManager = library.getSecurityManager(); - this.fileStream = fileStream; - } - - /** - * (Optional) The type of PDF object that this dictionary describes; if present, shall be EmbeddedFile for an - * embedded file stream. - * - * @return type value if present otherwise null. - */ - public Name getType() { - return library.getName(entries, TYPE_KEY); - } - - /** - * (Optional) The subtype of the embedded file. The value of this entry shall be a first-class name, as defined in - * Annex E. Names without a registered prefix shall conform to the MIME media type names defined in - * Internet RFC 2046, Multipurpose Internet Mail Extensions (MIME), Part Two: Media Types (see the Bibliography), - * with the provision that characters not allowed in names shall use the 2-character hexadecimal code format - * described in 7.3.5, "Name Objects." - * - * @return mime media type of object - */ - public Name getSubType() { - return library.getName(entries, SUBTYPE_KEY); - } - - /** - * An embedded file parameter dictionary that shall contain additional file-specific information. - * - * @return the raw dictionary. - */ - public HashMap getParams() { - return library.getDictionary(entries, PARAMS_KEY); - } - - /** - * (Optional) The size of the uncompressed embedded file, in bytes. - * - * @return uncompressed size in bytes, null if not specified. - */ - public int getParamUncompressedSize() { - int size = library.getInt(getParams(), PARAMS_SIZE_KEY); - if (size == 0){ - size = fileStream.getDecodedStreamBytes().length; - } - return size; - } - - /** - * Get compressed size in bytes. - * - * @return - */ - public int getCompressedSize() { - return fileStream.getRawBytes().length; - } - - /** - * Gets the file streams decoded data stream which can be used to open or save the file given the appropriate - * file handler. - * - * @return decoded byte array input stream. - * @throws IOException io exception during stream decoding. - */ - public InputStream getDecodedStreamData() throws IOException { - return fileStream.getDecodedByteArrayInputStream(); - } - - /** - * (Optional) The date and time when the embedded file was created. - * - * @return creation date if set, null otherwise. - */ - public PDate getParamCreationData() { - Object value = library.getObject(getParams(), PARAMS_CREATION_DATE_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return new PDate(securityManager, text.getDecryptedLiteralString(securityManager)); - } - return null; - } - - /** - * (Optional) The date and time when the embedded file was created. - * - * @return creation date if set, null otherwise. - */ - public PDate getParamLastModifiedData() { - Object value = library.getObject(getParams(), PARAMS_MOD_DATE_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return new PDate(securityManager, text.getDecryptedLiteralString(securityManager)); - } - return null; - } - - /** - * (Optional) A sub dictionary containing additional information specific to Mac OS files - * - * @return mac sub dictionary, or null if not set. - */ - public HashMap getMacDictionary() { - return library.getDictionary(getParams(), PARAMS_MAC_KEY); - } - - /** - * (Optional) A 16-byte string that is the checksum of the bytes of the uncompressed embedded file. The checksum - * shall be calculated by applying the standard MD5 message-digest algorithm (described in Internet RFC 1321, - * The MD5 Message-Digest Algorithm; see the Bibliography) to the bytes of the embedded file stream. - * - * @return checksum or null; - */ - public String getCheckSum() { - Object value = library.getObject(getParams(), PARAMS_CHECK_SUM_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return text.getDecryptedLiteralString(securityManager); - } - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/FileSpecification.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/FileSpecification.java deleted file mode 100644 index a81a348a01..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/FileSpecification.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.util.HashMap; - -/** - *

The File Specification diction provides more flexibility then the string - * form. allowing different files to be specified for different file systems or - * platforms, or for file system other than the standard ones (DOS/Windows, Mac - * OS, and Unix).

- * - * @author ICEsoft Technologies, Inc. - * @since 2.6 - */ -public class FileSpecification extends Dictionary { - - /** - * The name of the file system that shall be used to interpret this file - * specification. If this entry is present, all other entries in the dictionary - * shall be interpreted by the designated file system. PDF shall define only - * one standard file system name, URL; an application can register other - * names. This entry shall be independent of the F, UF, DOS, Mac, and - * Unix entries. - */ - public static final Name FS_KEY = new Name("FS"); - - /** - * (Required if the DOS, Mac, and Unix entries are all absent; amended with - * the UF entry for PDF 1.7) A file specification string of the form - * described in 7.11.2, "File Specification Strings," or (if the file system is URL) - * a uniform resource locator, as described in 7.11.5, "URL Specifications." - *

- * The UF entry should be used in addition to the F entry. The UF entry provides - * cross-platform and cross-language compatibility and the F entry provides - * backwards compatibility. - */ - public static final Name F_KEY = new Name("F"); - - /** - * A Unicode text string that provides file specification of the form - * described in 7.11.2, "File Specification Strings." This is a text string - * encoded using PDFDocEncoding or UTF-16BE with a leading byte-order marker - * (as defined in 7.9.2.2, "Text String Type"). The F entry should be included - * along with this entry for backwards compatibility reasons. - */ - public static final Name UF_KEY = new Name("UF"); - - /** - * A file specification string (see 7.11.2, "File Specification Strings") - * representing a DOS file name. - *

- * This entry is obsolescent and should not be used by conforming writers. - */ - public static final Name DOS_KEY = new Name("DOS"); - - /** - * A file specification string (see 7.11.2, "File Specification - * Strings") representing a Mac OS file name. - *

- * This entry is obsolescent and should not be used by conforming writers. - */ - public static final Name MAC_KEY = new Name("Mac"); - - /** - * A file specification string (see 7.11.2, "File Specification Strings") - * representing a UNIX file name. - *

- * This entry is obsolescent and should not be used by conforming writers. - */ - public static final Name UNIX_KEY = new Name("Unix"); - - /** - * An array of two byte strings constituting a file identifier that should - * be included in the referenced file. - *

- * NOTE - * The use of this entry improves an application's chances of finding the - * intended file and allows it to warn the user if the file has changed - * since the link was made. - */ - public static final Name ID_KEY = new Name("ID"); - - /** - * flag indicating whether the file referenced by the file specification is - * volatile (changes frequently with time). If the value is true, applications - * shall not cache a copy of the file. For example, a movie annotation - * referencing a URL to a live video camera could set this flag to true to - * notify the conforming reader that it should re-acquire the movie each time - * it is played. Default value: false. - */ - public static final Name V_KEY = new Name("V"); - - /** - * (Required if RF is present; PDF 1.3; amended to include the UF key in PDF - * 1.7) A dictionary containing a subset of the keys F, UF, DOS, Mac, and Unix, - * corresponding to the entries by those names in the file specification dictionary. - * The value of each such key shall be an embedded file stream (see 7.11.4, - * "Embedded File Streams") containing the corresponding file. If this entry - * is present, the Type entry is required and the file specification dictionary - * shall be indirectly referenced. - *

- * The F and UF entries should be used in place of the DOS, Mac, or Unix entries. - */ - public static final Name EF_KEY = new Name("EF"); - - /** - * A dictionary with the same structure as the EF dictionary, which shall be - * present. Each key in the RF dictionary shall also be present in the EF - * dictionary. Each value shall be a related files array (see 7.11.4.2, - * "Related Files Arrays") identifying files that are related to the - * corresponding file in the EF dictionary. If this entry is present, the - * Type entry is required and the file specification dictionary shall be - * indirectly referenced. - */ - public static final Name RF_KEY = new Name("RF"); - - /** - * Descriptive text associated with the file specification. It shall be used - * for files in the EmbeddedFiles name tree - */ - public static final Name DESC_KEY = new Name("Desc"); - - /** - * A collection item dictionary, which shall be used to create the user - * interface for portable collections (see 7.11.6, "Collection Items"). - */ - public static final Name CI_KEY = new Name("CI"); - - /** - * Constructs a new specification dictionary. - * - * @param l document library. - * @param h dictionary entries. - */ - public FileSpecification(Library l, HashMap h) { - super(l, h); - } - - /** - * The type of the PDF object that this dictionary describes which is always - * "Filespec". - * - * @return type of PDF object, "Filespec". - */ - public Name getType() { - return library.getName(entries, TYPE_KEY); - } - - /** - * Gets the name of the file system to be used to interpret this file - * specification. This entry is independent of the F, DOS, Mac and Unix - * entries. - * - * @return the name of the file system to be used to interpret this file. - */ - public Name getFileSystemName() { - return library.getName(entries, FS_KEY); - } - - /** - * Gets the file specification string. - * - * @return file specification string. - */ - public String getFileSpecification() { - Object tmp = library.getObject(entries, F_KEY); - if (tmp instanceof StringObject) { - return Utils.convertStringObject(library, (StringObject) tmp); - } else { - return null; - } - } - - /** - * Gets the unicode file specification string. - * - * @return file specification string. - */ - public String getUnicodeFileSpecification() { - Object tmp = library.getObject(entries, UF_KEY); - if (tmp instanceof StringObject) { - return Utils.convertStringObject(library, (StringObject) tmp); - } else { - return null; - } - } - - /** - * Gets the file specification string representing a DOS file name. - * - * @return DOS file name. - */ - public String getDos() { - Object tmp = library.getObject(entries, DOS_KEY); - if (tmp instanceof StringObject) { - return ((StringObject) tmp) - .getDecryptedLiteralString( - library.getSecurityManager()); - } else { - return null; - } - } - - /** - * Gets the file specification string representing a Mac file name. - * - * @return Mac file name. - */ - public String getMac() { - Object tmp = library.getObject(entries, MAC_KEY); - if (tmp instanceof StringObject) { - return ((StringObject) tmp) - .getDecryptedLiteralString( - library.getSecurityManager()); - } else { - return null; - } - } - - /** - * Gets the file specification string representing a Unix file name. - * - * @return Unix file name. - */ - public String getUnix() { - Object tmp = library.getObject(entries, UNIX_KEY); - if (tmp instanceof StringObject) { - return ((StringObject) tmp) - .getDecryptedLiteralString( - library.getSecurityManager()); - } else { - return null; - } - } - - /** - * Gets an array of two strings constituting a file identifier that is also - * included in the referenced file. - * - * @return file identifier. - */ - public String getId() { - Object tmp = library.getObject(entries, ID_KEY); - if (tmp != null) { - return tmp.toString(); - } else { - return null; - } - } - - /** - * Returns a flag indicating whether the file referenced by the file - * specification is volatile (changes frequently with time). - * - * @return true indicates the file is volitile and should not be cached, - * otherwise true. - */ - public Boolean isVolitile() { - return library.getBoolean(entries, V_KEY); - } - - /** - * Gets a dictionary containing a subset of the keys F, DOS, Mac, and - * Unix. The value of each key is an embedded file stream. - * - * @return embbed file stream properties. - */ - public HashMap getEmbeddedFileDictionary() { - return library.getDictionary(entries, EF_KEY); - } - - /** - * Gets the full file specification if present. If null is returned then the file specification is simple - * and a call should be made to dos, mac or unix, however these are obsolescent and likely won't be - * encountered. - * - * @return associated EmbeddedFileStream object if present, null otherwise. - */ - public EmbeddedFileStream getEmbeddedFileStream(){ - HashMap fileDictionary = getEmbeddedFileDictionary(); - Reference fileRef = (Reference) fileDictionary.get(FileSpecification.F_KEY); - if (fileRef != null) { - Stream fileStream = (Stream) library.getObject(fileRef); - if (fileStream != null) { - return new EmbeddedFileStream(library, fileStream); - } - } - return null; - } - - /** - * Gets a dictionary with the same structure as the EF dectionary, which - * must also b present. EAch key in the RF dictionary must also be present - * in the EF diciontary. Each value is a related file array identifying - * files that a re related to the corresponding file in the EF dictionary. - * - * @return related files dictionary. - */ - public HashMap getRelatedFilesDictionary() { - return library.getDictionary(entries, RF_KEY); - } - - /** - * Gets the descriptive text associated with the file specification. - * - * @return file identifier. - */ - public String getDescription() { - Object description = library.getObject(entries, DESC_KEY); - if (description instanceof StringObject) { - return Utils.convertStringObject(library, (StringObject) description); - } else if (description instanceof String) { - return description.toString(); - } else { - return null; - } - } - - /** - * GA collection item dictionary, which shall be used to create the user - * interface for portable collections (see 7.11.6, "Collection Items"). - * - * @return related files dictionary. - */ - public HashMap getCollectionItemDictionary() { - return library.getDictionary(entries, CI_KEY); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Form.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Form.java deleted file mode 100644 index 3aa1ac1069..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Form.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.io.SeekableInputConstrainedWrapper; -import org.icepdf.core.pobjects.graphics.ExtGState; -import org.icepdf.core.pobjects.graphics.GraphicsState; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.content.ContentParser; -import org.icepdf.core.util.content.ContentParserFactory; - -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Form XObject class. Not currently part of the public api. - *

- * Forms are grouped into the 'Resource' category and can be shared. As a result we need to make sure - * that the init method are synchronized as they can be accessed by different page loading threads. - * - * @since 1.0 - */ -public class Form extends Stream { - - private static final Logger logger = - Logger.getLogger(Form.class.toString()); - - public static final Name TYPE_VALUE = new Name("XObject"); - public static final Name SUB_TYPE_VALUE = new Name("Form"); - public static final Name GROUP_KEY = new Name("Group"); - public static final Name I_KEY = new Name("I"); - public static final Name K_KEY = new Name("K"); - public static final Name MATRIX_KEY = new Name("Matrix"); - public static final Name BBOX_KEY = new Name("BBox"); - public static final Name RESOURCES_KEY = new Name("Resources"); - - private AffineTransform matrix = new AffineTransform(); - private Rectangle2D bbox; - private Shapes shapes; - // Graphics state object to be used by content parser - private GraphicsState graphicsState; - private ExtGState extGState; - private Resources resources; - private Resources parentResource; - // transparency grouping data - private boolean transparencyGroup; - private boolean isolated; - private boolean knockOut; - private boolean shading; - private boolean inited = false; - - /** - * Creates a new instance of the xObject. - * - * @param l document library - * @param h xObject dictionary entries. - * @param streamInputWrapper content stream of image or post script commands. - */ - public Form(Library l, HashMap h, SeekableInputConstrainedWrapper streamInputWrapper) { - super(l, h, streamInputWrapper); - - // check for grouping flags so we can do special handling during the - // xform content stream parsing. - HashMap group = library.getDictionary(entries, GROUP_KEY); - if (group != null) { - transparencyGroup = true; - isolated = library.getBoolean(group, I_KEY); - knockOut = library.getBoolean(group, K_KEY); - } - } - - public HashMap getGroup() { - return library.getDictionary(entries, GROUP_KEY); - } - - @SuppressWarnings("unchecked") - public void setAppearance(Shapes shapes, AffineTransform matrix, Rectangle2D bbox) { - inited = false; - this.shapes = shapes; - this.matrix = matrix; - this.bbox = bbox; - entries.put(Form.BBOX_KEY, PRectangle.getPRectangleVector(bbox)); - entries.put(Form.MATRIX_KEY, matrix); - } - - /** - * Sets the GraphicsState which should be used by the content parser when - * parsing the Forms content stream. The GraphicsState should be set - * before init() is called, or it will have not effect on the rendered - * content. - * - * @param graphicsState current graphic state - */ - public void setGraphicsState(GraphicsState graphicsState) { - if (graphicsState != null) { - this.graphicsState = graphicsState; - this.extGState = graphicsState.getExtGState(); - } - } - - /** - * Gets the associated graphic state instance for this form. - * - * @return external graphic state, can be null. - */ - public GraphicsState getGraphicsState() { - return graphicsState; - } - - /** - * Gets the extended graphics state for the form at the time of creation. This contains any masking and blending - * data that might bet over written during the forms parsing. - * - * @return extended graphic state at the time of creation. - */ - public ExtGState getExtGState() { - return extGState; - } - - /** - * Utility method for parsing a vector of affinetranform values to an - * affine transform. - * - * @param v vectory containing affine transform values. - * @return affine tansform based on v - */ - private static AffineTransform getAffineTransform(List v) { - float f[] = new float[6]; - for (int i = 0; i < 6; i++) { - f[i] = ((Number) v.get(i)).floatValue(); - } - return new AffineTransform(f); - } - - /** - * As of the PDF 1.2 specification, a resource entry is not required for - * a XObject and thus it needs to point to the parent resource to enable - * to correctly load the content stream. - * - * @param parentResource parent objects resourse when available. - */ - public void setParentResources(Resources parentResource) { - this.parentResource = parentResource; - } - - /** - * - */ - public synchronized void init() { - if (inited) { - return; - } - Object v = library.getObject(entries, MATRIX_KEY); - if (v != null && v instanceof List) { - matrix = getAffineTransform((List) v); - } else if (v != null && v instanceof AffineTransform) { - matrix = (AffineTransform) v; - } - bbox = library.getRectangle(entries, BBOX_KEY); - // try and find the form's resources dictionary. - Resources leafResources = library.getResources(entries, RESOURCES_KEY); - // apply parent resource, if the current resources is null - if (leafResources != null) { - resources = leafResources; - } else { - leafResources = parentResource; - } - // Build a new content parser for the content streams and apply the - // content stream of the calling content stream. - ContentParser cp = ContentParserFactory.getInstance() - .getContentParser(library, leafResources); - cp.setGraphicsState(graphicsState); - byte[] in = getDecodedStreamBytes(); - if (in != null) { - try { - if (logger.isLoggable(Level.FINER)) { - logger.finer("Parsing form " + getPObjectReference()); - } - shapes = cp.parse(new byte[][]{in}, null).getShapes(); - } catch (Throwable e) { - // reset shapes vector, we don't want to mess up the paint stack - shapes = new Shapes(); - logger.log(Level.FINE, "Error parsing Form content stream.", e); - } - } - inited = true; - } - - public Resources getResources() { - Resources leafResources = library.getResources(entries, RESOURCES_KEY); - if (leafResources == null) { - leafResources = new Resources(library, new HashMap()); - } - return leafResources; - } - - @SuppressWarnings("unchecked") - public void setResources(Resources resources) { - entries.put(RESOURCES_KEY, resources.getEntries()); - } - - - /** - * Gets the shapes that where parsed from the content stream. - * - * @return shapes object for xObject. - */ - public Shapes getShapes() { - return shapes; - } - - /** - * Gets the bounding box for the xObject. - * - * @return rectangle in PDF coordinate space representing xObject bounds. - */ - public Rectangle2D getBBox() { - return bbox; - } - - /** - * Gets the optional matrix which describes how to convert the coordinate - * system in xObject space to the parent coordinates space. - * - * @return affine transform representing the xObject's pdf to xObject space - * transform. - */ - public AffineTransform getMatrix() { - return matrix; - } - - /** - * If the xObject has a transparency group flag. - * - * @return true if a transparency group exists, false otherwise. - */ - public boolean isTransparencyGroup() { - return transparencyGroup; - } - - /** - * Only present if a transparency group is present. Isolated groups are - * composed on a fully transparent back drop rather then the groups. - * - * @return true if the transparency group is isolated. - */ - public boolean isIsolated() { - return isolated; - } - - /** - * Only present if a transparency group is present. Knockout groups individual - * elements composed with the groups initial back drop rather then the stack. - * - * @return true if the transparency group is a knockout. - */ - public boolean isKnockOut() { - return knockOut; - } - - public boolean isShading() { - return shading; - } - - public void setShading(boolean shading) { - this.shading = shading; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/HexStringObject.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/HexStringObject.java deleted file mode 100644 index 13f625fd35..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/HexStringObject.java +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.fonts.Font; -import org.icepdf.core.pobjects.fonts.FontFile; -import org.icepdf.core.pobjects.security.SecurityManager; -import org.icepdf.core.util.Utils; - -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

This class represents a PDF Hexadecimal String Object. Hexadecimal String - * objects are written as a sequence of literal characters enclosed in - * angled brackets <>.

- * - * @since 2.0 - */ -public class HexStringObject implements StringObject { - - private static Logger logger = - Logger.getLogger(HexStringObject.class.toString()); - - // core data used to represent the literal string information - private StringBuilder stringData; - - // Reference is need for standard encryption - Reference reference; - - /** - *

Creates a new hexadecimal string object so that it represents the same - * sequence of bytes as in the bytes argument. In other words, the - * initial content of the hexadecimal string is the characters represented - * by the byte data.

- * - * @param bytes array of bytes which will be interpreted as hexadecimal - * data. - */ - public HexStringObject(byte[] bytes) { - this(new StringBuilder(bytes.length).append(new String(bytes))); - } - - /** - *

Creates a new hexadecimal string object so that it represents the same - * sequence of character data specified by the argument. This constructor should - * only be used in the context of the parser which has leading and ending - * angled brackets which are removed by this method.

- * - * @param stringBuffer the initial contents of the hexadecimal string object - */ - public HexStringObject(StringBuilder stringBuffer) { - // remove angled brackets, passed in by parser - stringBuffer.deleteCharAt(0); - stringBuffer.deleteCharAt(stringBuffer.length() - 1); - // append string data - stringData = new StringBuilder(stringBuffer.length()); - stringData.append(normalizeHex(stringBuffer, 2).toString()); - } - - public HexStringObject(String string) { - stringData = new StringBuilder(string.length()); - stringData.append(normalizeHex(new StringBuilder(string), 2).toString()); - } - - /** - *

Creates a new literal string object so that it represents the same - * sequence of character data specified by the arguments. The string - * value is assumed to be unencrypted and will be encrypted. The - * method #LiteralStringObject(String string) should be used if the string - * is all ready encrypted. This method is used for creating new - * LiteralStringObject's that are created post document parse.

- * - * @param string the initial contents of the literal string object, - * unencrypted. - * @param reference of parent PObject - * @param securityManager security manager used ot encrypt the string. - */ - public HexStringObject(String string, Reference reference, - SecurityManager securityManager) { - // append string data - this.reference = reference; - // convert string data to hex encoded - stringData = encodeHexString(string); - // save and encrypt the hex value. TODO: encryption still not working correctly, likely a -> byte[] error. - stringData = new StringBuilder(encryption(stringData.toString(), false, securityManager)); - } - - /** - * Encodes the given contents string into a 4 byte hex string. This allows us to easily account for - * mixed encoding of 2-byte and 4 byte string content. - * - * @param contents string to be encoded into hex format. - * @return original content stream with contents encoded in the hex string format. - */ - private StringBuilder encodeHexString(String contents) { - StringBuilder hex = new StringBuilder(); - if (contents != null && contents.length() > 0) { - char[] chars = contents.toCharArray(); - hex.append("FEFF"); - String hexCode; - for (char aChar : chars) { - hexCode = Integer.toHexString((int) aChar); - if (hexCode.length() == 2) { - hexCode = "00" + hexCode; - } else if (hexCode.length() == 1) { - hexCode = "000" + hexCode; - } - hex.append(hexCode); - } - } - return hex; - } - - /** - * Gets the integer value of the hexidecimal data specified by the start and - * offset parameters. - * - * @param start the begining index, inclusive - * @param offset the length of bytes to process - * @return unsigned integer value of the specifed data range - */ - public int getUnsignedInt(int start, int offset) { - if (start < 0 || stringData.length() < (start + offset)) - return 0; - int unsignedInt = 0; - try { - unsignedInt = Integer.parseInt( - stringData.substring(start, start + offset), 16); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.FINER)) { - logger.finer("Number Format Exception " + unsignedInt); - } - } - return unsignedInt; - } - - public int getUnsignedInt(String data) { - int unsignedInt = 0; - try { - unsignedInt = Integer.parseInt(data, 16); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.FINER)) { - logger.finer("Number Format Exception " + unsignedInt); - } - } - return unsignedInt; - } - - /** - *

Returns a string representation of the object. - * The hex data is converted to an equivalent string representation

- * - * @return a string representing the object. - */ - public String toString() { - return getLiteralString(); - } - - /** - *

Gets a hexadecimal String representation of this object's data, which - * is in fact, the raw data contained in this object

- * - * @return a String representation of the object's data in hexadecimal notation. - */ - public String getHexString() { - return stringData.toString(); - } - - /** - *

Gets a hexadecimal StringBuffer representation of this object's data, - * which is in fact the raw data contained in this object.

- * - * @return a StringBufffer representation of the objects data in hexadecimal. - */ - public StringBuilder getHexStringBuffer() { - return stringData; - } - - /** - *

Gets a literal StringBuffer representation of this object's data. - * The hexadecimal data is converted to an equivalent string representation

- * - * @return a StringBuffer representation of the object's data. - */ - public StringBuilder getLiteralStringBuffer() { - return hexToString(stringData); - } - - /** - *

Gets a literal String representation of this object's data. - * The hexadecimal data is converted to an equivalent string representation.

- * - * @return a String representation of the object's data. - */ - public String getLiteralString() { - return hexToString(stringData).toString(); - } - - /** - *

Gets a literal String representation of this object's data using the - * specifed font and format. The font is used to verify that the - * specific character codes can be rendered; if they can not, they may be - * removed or combined with the next character code to get a displayable - * character code. - * - * @param fontFormat the type of font which will be used to display - * the text. Valid values are CID_FORMAT and SIMPLE_FORMAT for Adobe - * Composite and Simple font types respectively - * @param font font used to render the literal string data. - * @return StringBuffer which contains all renderaable characters for the - * given font. - */ - public StringBuilder getLiteralStringBuffer(final int fontFormat, FontFile font) { - if (fontFormat == Font.SIMPLE_FORMAT) { - stringData = new StringBuilder(normalizeHex(stringData, 2).toString()); - int charOffset = 2; - int length = getLength(); - StringBuilder tmp = new StringBuilder(length); - int lastIndex = 0; - int charValue; - int offset; - for (int i = 0; i < length; i += charOffset) { - offset = lastIndex + charOffset; - charValue = getUnsignedInt(i - lastIndex, offset); - // 0 cid is valid, so we have ot be careful we don't exclude the - // cid 00 = 0 or 0000 = 0, not 0000 = 00. - if (!(offset < length && charValue == 0) && - font.canDisplayEchar((char) charValue)) { - tmp.append((char) charValue); - lastIndex = 0; - } else { - lastIndex += charOffset; - } - } - return tmp; - } else if (fontFormat == Font.CID_FORMAT) { - stringData = new StringBuilder(normalizeHex(stringData, 4).toString()); - int charOffset = 2; - int length = getLength(); - int charValue; - StringBuilder tmp = new StringBuilder(length); - // attempt to detect mulibyte encoded strings. - for (int i = 0; i < length; i += charOffset) { - String first = stringData.substring(i, i + 2); - if (first.charAt(0) != '0') { - // check range for possible 2 byte char ie mixed mode. - charValue = getUnsignedInt(first); - if (font.getByteEncoding() == FontFile.ByteEncoding.MIXED_BYTE && - font.canDisplayEchar((char) charValue) && font.getSource() != null) { - tmp.append((char) charValue); - } else { - charValue = getUnsignedInt(i, 4); - if (font.canDisplayEchar((char) charValue)) { - tmp.append((char) charValue); - i += 2; - } - } - } else { - charValue = getUnsignedInt(i, 4); - // should never have a 4 digit zero value. - if (font.canDisplayEchar((char) charValue)) { - tmp.append((char) charValue); - i += 2; - } - } - } - return tmp; - } - return null; - } - - /** - * The length of the underlying objects data. - * - * @return length of object's data. - */ - public int getLength() { - return stringData.length(); - } - - /** - * Utility method to removed all none hex character from the string and - * ensure that the length is an even length. - * - * @param hex hex data to normalize - * @param step 2 or 4 character codes. - * @return normalized pure hex StringBuffer - */ - private static StringBuilder normalizeHex(StringBuilder hex, int step) { - // strip and white space - int length = hex.length(); - for (int i = 0; i < length; i++) { - if (isNoneHexChar(hex.charAt(i))) { - hex.deleteCharAt(i); - length--; - i--; - } - } - length = hex.length(); - if (step == 2) { - // pre append 0's to uneven length, be careful as the 0020 isn't the same as 2000 - if (length % 2 != 0) { - hex = new StringBuilder("0").append(hex); - } - } - if (step == 4) { - if (length % 4 != 0) { - hex = new StringBuilder("00").append(hex); - } - } - return hex; - } - - /** - * Utility method to test if the char is a none hexadecimal char. - * - * @param c charact to text - * @return true if the character is a none hexadecimal character - */ - private static boolean isNoneHexChar(char c) { - // make sure the char is the following - return !(((c >= 48) && (c <= 57)) || // 0-9 - ((c >= 65) && (c <= 70)) || // A-F - ((c >= 97) && (c <= 102))); // a-f - } - - /** - * Utility method for converting a hexadecimal string to a literal string. - * - * @param hh StringBuffer containing data in hexadecimal form. - * @return StringBuffer containing data in literal form. - */ - private StringBuilder hexToString(StringBuilder hh) { - - // make sure we have a valid hex value to convert to string. - // can't decrypt an empty string. - if (hh != null && hh.length() == 0) { - return new StringBuilder(); - } - - StringBuilder sb; - // special case, test for not a 4 byte character code format - if (!((hh.charAt(0) == 'F' | hh.charAt(0) == 'f') - && (hh.charAt(1) == 'E' | hh.charAt(1) == 'e') - && (hh.charAt(2) == 'F' | hh.charAt(2) == 'f') - && (hh.charAt(3) == 'F') | hh.charAt(3) == 'f')) { - return getRawHexToString(); - } - // otherwise, assume 4 byte character codes - else { - int length = hh.length(); - sb = new StringBuilder(length / 4); - String subStr; - // make sure to skip the marker - for (int i = 4; i < length; i = i + 4) { - subStr = hh.substring(i, i + 4); - sb.append((char) Integer.parseInt(subStr, 16)); - } - return sb; - } - } - - /** - * Gets the raw string values not taking into account any special cases for FEFF byte - * marking. - * - * @return two byte hex string converted to plain string. - */ - public StringBuilder getRawHexToString() { - - StringBuilder sb; - - int length = stringData.length(); - sb = new StringBuilder(length / 2); - String subStr; - - for (int i = 0; i < length; i = i + 2) { - subStr = stringData.substring(i, i + 2); - sb.append((char) Integer.parseInt(subStr, 16)); - } - return sb; - } - - /** - * Sets the parent PDF object's reference. - * - * @param reference parent object reference. - */ - public void setReference(Reference reference) { - this.reference = reference; - } - - /** - * Sets the parent PDF object's reference. - * - * @return returns the reference used for encryption. - */ - public Reference getReference() { - return reference; - } - - /** - * Gets the decrypted literal string value of the data using the key provided by the - * security manager. - * - * @param securityManager security manager associated with parent document. - */ - public String getDecryptedLiteralString(SecurityManager securityManager) { - // get the security manager instance - if (securityManager != null && reference != null) { - // get the key - byte[] key = securityManager.getDecryptionKey(); - - // convert string to bytes. - byte[] textBytes = - Utils.convertByteCharSequenceToByteArray(getLiteralString()); - - // Decrypt String - textBytes = securityManager.decrypt(reference, - key, - textBytes); - - // convert back to a string - return Utils.convertByteArrayToByteString(textBytes); - } - return getLiteralString(); - } - - /** - * Decrypts or encrypts a string. - * - * @param string string to encrypt or decrypt - * @param decrypt true to decrypt string, false otherwise; - * @param securityManager security manager for document. - * @return encrypted or decrypted string, depends on value of decrypt param. - */ - public String encryption(String string, boolean decrypt, - SecurityManager securityManager) { - // get the security manager instance - if (securityManager != null && reference != null) { - // get the key - byte[] key = securityManager.getDecryptionKey(); - - // convert string to bytes. - byte[] textBytes = - Utils.convertByteCharSequenceToByteArray(string); - - // Decrypt String - if (decrypt) { - textBytes = securityManager.decrypt(reference, - key, - textBytes); - } else { - textBytes = securityManager.encrypt(reference, - key, - textBytes); - } - - // convert back to a string - return Utils.convertByteArrayToByteString(textBytes); - } - return string; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ImageStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ImageStream.java deleted file mode 100644 index b7cbaa920e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ImageStream.java +++ /dev/null @@ -1,1196 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - - -import org.icepdf.core.io.BitStream; -import org.icepdf.core.io.SeekableInputConstrainedWrapper; -import org.icepdf.core.pobjects.filters.CCITTFax; -import org.icepdf.core.pobjects.filters.CCITTFaxDecoder; -import org.icepdf.core.pobjects.graphics.*; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; - -import javax.imageio.ImageIO; -import javax.imageio.ImageReadParam; -import javax.imageio.ImageReader; -import javax.imageio.stream.ImageInputStream; -import java.awt.*; -import java.awt.color.ColorSpace; -import java.awt.image.BufferedImage; -import java.awt.image.ColorConvertOp; -import java.awt.image.WritableRaster; -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * ImageStream contains image data that is contains in an XObject of subtype - * Image. - * - * @since 5.0 - */ -public class ImageStream extends Stream { - - private static final Logger logger = - Logger.getLogger(ImageStream.class.toString()); - - public static final Name TYPE_VALUE = new Name("Image"); - public static final Name BITSPERCOMPONENT_KEY = new Name("BitsPerComponent"); - public static final Name BPC_KEY = new Name("BPC"); - public static final Name DECODE_KEY = new Name("Decode"); - public static final Name D_KEY = new Name("D"); - public static final Name SMASK_KEY = new Name("SMask"); - public static final Name MASK_KEY = new Name("Mask"); - public static final Name JBIG2GLOBALS_KEY = new Name("JBIG2Globals"); - public static final Name DECODEPARMS_KEY = new Name("DecodeParms"); - public static final Name DP_KEY = new Name("DP"); - public static final Name K_KEY = new Name("K"); - public static final Name ENCODEDBYTEALIGN_KEY = new Name("EncodedByteAlign"); - public static final Name COLUMNS_KEY = new Name("Columns"); - public static final Name ROWS_KEY = new Name("Rows"); - public static final Name BLACKIS1_KEY = new Name("BlackIs1"); - // filter names - protected static final String[] CCITTFAX_DECODE_FILTERS = new String[]{"CCITTFaxDecode", "/CCF", "CCF"}; - protected static final String[] DCT_DECODE_FILTERS = new String[]{"DCTDecode", "/DCT", "DCT"}; - protected static final String[] JBIG2_DECODE_FILTERS = new String[]{"JBIG2Decode"}; - protected static final String[] JPX_DECODE_FILTERS = new String[]{"JPXDecode"}; - - // paper size for rare corner case when ccittfax is missing a dimension. - private static double pageRatio; - - // flag the forces jai to be use over our fax decode class. - private static boolean forceJaiccittfax; - - private PColorSpace colourSpace; - private final Object colorSpaceAssignmentLock = new Object(); - - private static boolean isLevigoJBIG2ImageReaderClass; - - /** - * Gets the value of the system property "org.icepdf.core.ccittfax.checkParentBlackIs1". - */ - public static boolean CHECK_PARENT_BLACK_IS_1; - - static { - // define alternate page size ration w/h, default Legal. - pageRatio = - Defs.sysPropertyDouble("org.icepdf.core.pageRatio", - 8.26 / 11.68); - // force jai as the default ccittfax decode. - forceJaiccittfax = - Defs.sysPropertyBoolean("org.icepdf.core.ccittfax.jai", - false); - try { - Class.forName("com.levigo.jbig2.JBIG2ImageReader"); - isLevigoJBIG2ImageReaderClass = true; - logger.info("Levigo JBIG2 image library was found on classpath"); - } catch (ClassNotFoundException e) { - logger.info("Levigo JBIG2 image library was not found on classpath"); - } - - CHECK_PARENT_BLACK_IS_1 = Defs.booleanProperty("org.icepdf.core.ccittfax.checkParentBlackIs1", false); - } - - private int width; - private int height; - - /** - * Create a new instance of a Stream. - * - * @param l library containing a hash of all document objects - * @param h HashMap of parameters specific to the Stream object. - * @param streamInputWrapper Accessor to stream byte data - */ - public ImageStream(Library l, HashMap h, SeekableInputConstrainedWrapper streamInputWrapper) { - super(l, h, streamInputWrapper); - init(); - } - - public ImageStream(Library l, HashMap h, byte[] rawBytes) { - super(l, h, rawBytes); - init(); - } - - public void init() { - // get dimension of image stream - width = library.getInt(entries, WIDTH_KEY); - height = library.getInt(entries, HEIGHT_KEY); - // PDF-458 corner case/one off for trying to guess the width or height - // of an CCITTfax image that is basically the same use as the page, we - // use the page dimensions to try and determine the page size. - // This will fail miserably if the image isn't full page. - if (height == 0) { - height = (int) ((1 / pageRatio) * width); - } else if (width == 0) { - width = (int) (pageRatio * height); - } - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - /** - * Gets the image object for the given resource. This method can optionally - * scale an image to reduce the total memory foot print or to increase the - * perceived render quality on screen at low zoom levels. - * - * @param graphicsState graphic state for image or parent form - * @param resources resources containing image reference - * @return new image object - */ - // was synchronized, not think it is needed? - @SuppressWarnings("unchecked") - public synchronized BufferedImage getImage(GraphicsState graphicsState, Resources resources) throws InterruptedException { - // check the pool encase we already parse this image. - - if (pObjectReference != null) { - BufferedImage tmp = library.getImagePool().get(pObjectReference); - if (tmp != null) { - return tmp; - } - } - - // parse colour space, lock is to insure that getColorSpace() - // will return only after colourSpace has been set. - synchronized (colorSpaceAssignmentLock) { - Object o = entries.get(COLORSPACE_KEY); - if (resources != null && o != null) { - colourSpace = resources.getColorSpace(o); - } - // assume b&w image is no colour space - if (colourSpace == null) { - colourSpace = new DeviceGray(library, null); - } - } - // A flag indicating whether the image shall be treated as an image mask - boolean isImageMask = isImageMask(); - - // If this flag is true, the value of BitsPerComponent shall be 1 and - // Mask and ColorSpace shall not be specified; unmasked areas shall be - // painted using the current nonstroking colour - int bitsPerComponent = library.getInt(entries, BITSPERCOMPONENT_KEY); - if (isImageMask && bitsPerComponent == 0) { - bitsPerComponent = 1; - } - - // check for available memory, get colour space and bit count - // to better estimate size of image in memory - int colorSpaceCompCount = colourSpace.getNumComponents(); - - // parse decode information - int maxValue = ((int) Math.pow(2, bitsPerComponent)) - 1; - float[] decode = new float[2 * colorSpaceCompCount]; - List decodeVec = (List) library.getObject(entries, DECODE_KEY); - if (decodeVec == null) { - // add a decode param for each colour channel. - for (int i = 0, j = 0; i < colorSpaceCompCount; i++) { - decode[j++] = 0.0f; - decode[j++] = 1.0f / maxValue; - } - } else { - for (int i = 0, j = 0; i < colorSpaceCompCount; i++) { - float Dmin = decodeVec.get(j).floatValue(); - float Dmax = decodeVec.get(j + 1).floatValue(); - decode[j++] = Dmin; - decode[j++] = (Dmax - Dmin) / maxValue; - } - } - BufferedImage smaskImage = null; - BufferedImage maskImage = null; - int[] maskMinRGB = null; - int[] maskMaxRGB = null; - int maskMinIndex = -1; - int maskMaxIndex = -1; - Object smaskObj = library.getObject(entries, SMASK_KEY); - Object maskObj = library.getObject(entries, MASK_KEY); - - // If present, this entry shall override the current soft mask in the - // graphics state, as well as the image’s Mask entry, if any. However, - // the other transparency-related graphics state parameters—blend mode - // and alpha constant—shall remain in effect. - if (smaskObj instanceof Stream) { - ImageStream smaskStream = (ImageStream) smaskObj; - if (smaskStream.isImageSubtype()) { - smaskImage = smaskStream.getImage(graphicsState, resources); - } - } - - // An image XObject defining an image mask to be applied to this image - // ("Explicit Masking"), or an array specifying a range of colours to be - // applied to it as a colour key mask ("Colour Key Masking"). - if (maskObj != null && smaskImage == null) { - if (maskObj instanceof Stream) { - ImageStream maskStream = (ImageStream) maskObj; - if (maskStream.isImageSubtype()) { - maskImage = maskStream.getImage(graphicsState, resources); - } - } else if (maskObj instanceof List) { - List maskVector = (List) maskObj; - int[] maskMinOrigCompsInt = new int[colorSpaceCompCount]; - int[] maskMaxOrigCompsInt = new int[colorSpaceCompCount]; - for (int i = 0; i < colorSpaceCompCount; i++) { - if ((i * 2) < maskVector.size()) - maskMinOrigCompsInt[i] = ((Number) maskVector.get(i * 2)).intValue(); - if ((i * 2 + 1) < maskVector.size()) - maskMaxOrigCompsInt[i] = ((Number) maskVector.get(i * 2 + 1)).intValue(); - } - if (colourSpace instanceof Indexed) { - Indexed icolourSpace = (Indexed) colourSpace; - Color[] colors = icolourSpace.accessColorTable(); - if (colors != null && - maskMinOrigCompsInt.length >= 1 && - maskMaxOrigCompsInt.length >= 1) { - maskMinIndex = maskMinOrigCompsInt[0]; - maskMaxIndex = maskMaxOrigCompsInt[0]; - if (maskMinIndex >= 0 && maskMinIndex < colors.length && - maskMaxIndex >= 0 && maskMaxIndex < colors.length) { - Color minColor = colors[maskMinOrigCompsInt[0]]; - Color maxColor = colors[maskMaxOrigCompsInt[0]]; - maskMinRGB = new int[]{minColor.getRed(), minColor.getGreen(), minColor.getBlue()}; - maskMaxRGB = new int[]{maxColor.getRed(), maxColor.getGreen(), maxColor.getBlue()}; - } - } - } else { - PColorSpace.reverseInPlace(maskMinOrigCompsInt); - PColorSpace.reverseInPlace(maskMaxOrigCompsInt); - float[] maskMinOrigComps = new float[colorSpaceCompCount]; - float[] maskMaxOrigComps = new float[colorSpaceCompCount]; - colourSpace.normaliseComponentsToFloats(maskMinOrigCompsInt, maskMinOrigComps, (1 << bitsPerComponent) - 1); - colourSpace.normaliseComponentsToFloats(maskMaxOrigCompsInt, maskMaxOrigComps, (1 << bitsPerComponent) - 1); - - Color minColor = colourSpace.getColor(maskMinOrigComps); - Color maxColor = colourSpace.getColor(maskMaxOrigComps); - PColorSpace.reverseInPlace(maskMinOrigComps); - PColorSpace.reverseInPlace(maskMaxOrigComps); - maskMinRGB = new int[]{minColor.getRed(), minColor.getGreen(), minColor.getBlue()}; - maskMaxRGB = new int[]{maxColor.getRed(), maxColor.getGreen(), maxColor.getBlue()}; - } - } - } - - BufferedImage image = getImage( - colourSpace, graphicsState, width, height, - colorSpaceCompCount, bitsPerComponent, - isImageMask, - decode, - smaskImage, maskImage, - maskMinRGB, maskMaxRGB, maskMinIndex, maskMaxIndex); - // add the image to the pool, just encase it get painted again. - if (pObjectReference != null) { - library.getImagePool().put(pObjectReference, image); - } - return image; - } - - /** - * Utility to to the image work, the public version pretty much just - * parses out image dictionary parameters. This method start the actual - * image decoding. - * - * @param colourSpace colour space of image. - * @param graphicsState graphic state used to render image. - * @param width width of image. - * @param height heigth of image - * @param colorSpaceCompCount colour space component count, 1, 3, 4 etc. - * @param bitsPerComponent number of bits that represent one component. - * @param isImageMask boolean flag to use image mask or not. - * @param decode decode array, 1,0 or 0,1 can effect colour interpretation. - * @param sMaskImage smaask image value, optional. - * @param maskImage buffered image image mask to apply to decoded image, optional. - * @param maskMinRGB max rgb values for the mask - * @param maskMaxRGB min rgb values for the mask. - * @param maskMinIndex max indexed colour values for the mask. - * @param maskMaxIndex min indexed colour values for the mask. - * @return buffered image of decoded image stream, null if an error occured. - */ - private BufferedImage getImage( - PColorSpace colourSpace, - GraphicsState graphicsState, - int width, int height, - int colorSpaceCompCount, - int bitsPerComponent, - boolean isImageMask, - float[] decode, - BufferedImage sMaskImage, - BufferedImage maskImage, - int[] maskMinRGB, int[] maskMaxRGB, - int maskMinIndex, int maskMaxIndex) { - - // check to see if we need to create an imge with alpha, a mask - // will have imageMask=true and in this case we don't need alpha - BufferedImage decodedImage = null; - - // JPEG writes out image if successful - if (shouldUseDCTDecode()) { - decodedImage = dctDecode(width, height, colourSpace, bitsPerComponent, decode); - } - // JBIG2 writes out image if successful - else if (shouldUseJBIG2Decode()) { - decodedImage = jbig2Decode(width, height, colourSpace, bitsPerComponent, decode); - } - // JPEG2000 writes out image if successful - else if (shouldUseJPXDecode()) { - decodedImage = jpxDecode(width, height, colourSpace, bitsPerComponent, decode); - } - // CCITTFax data is raw byte decode. - else if (shouldUseCCITTFaxDecode()) { - // try default ccittfax decode. - decodedImage = ccittFaxDecode(colourSpace, graphicsState, width, height, - colorSpaceCompCount, bitsPerComponent, isImageMask, decode, sMaskImage, maskImage, - maskMinRGB, maskMaxRGB, maskMinIndex, maskMaxIndex, false); - } - // we have some raw data so, CCITTfax or some other image primitive. - else { - byte[] data = getDecodedStreamBytes( - width * height - * colourSpace.getNumComponents() - * bitsPerComponent / 8); - int dataLength = data.length; - // finally push the bytes though the common image processor to try - // and build a a Buffered image. - try { - decodedImage = ImageUtility.makeImageWithRasterFromBytes( - colourSpace, - graphicsState, - width, height, - colorSpaceCompCount, - bitsPerComponent, - isImageMask, - decode, - sMaskImage, - maskImage, - maskMinRGB, maskMaxRGB, - maskMinIndex, maskMaxIndex, - data, dataLength); -// ImageUtility.displayImage(decodedImage, pObjectReference.toString()); - } catch (Exception e) { - logger.log(Level.FINE, "Error building image raster.", e); - } - } - - // Fallback image cod the will use pixel primitives to build out the image. - if (decodedImage == null) { - byte[] data = getDecodedStreamBytes( - width * height - * colourSpace.getNumComponents() - * bitsPerComponent / 8); - // decodes the image stream and returns an image object. Legacy fallback - // code, should never get here, but there are always corner cases. . - decodedImage = parseImage( - width, - height, - colourSpace, - isImageMask, - graphicsState, - bitsPerComponent, - decode, - data); - } - if (decodedImage != null) { -// ImageUtility.displayImage(decodedImage, pObjectReference.toString()); -// ImageUtility.writeImage(decodedImage, pObjectReference.toString(), "D:\\log\\"); - if (isImageMask) { - decodedImage = ImageUtility.applyExplicitMask(decodedImage, graphicsState.getFillColor()); - } - - // apply common mask and sMask processing - if (sMaskImage != null) { - decodedImage = ImageUtility.applyExplicitSMask(decodedImage, sMaskImage); - } - if (maskImage != null) { - decodedImage = ImageUtility.applyExplicitMask(decodedImage, maskImage); - } - - // experimental check for different blending modes and apply a basic white = transparent, -// ExtGState extGState = graphicsState.getExtGState(); -// if (extGState != null && extGState.getBlendingMode() != null ) { -// decodedImage = ImageUtility.applyBlendingMode(decodedImage, extGState.getBlendingMode(), Color.WHITE); -// } - // ImageUtility.displayImage(decodedImage, pObjectReference.toString()); - - // with little luck the image is ready for viewing. - return decodedImage; - } - return null; - } - - /** - * Utility to try and parse out the CCITTFax data. We have two code paths one using our own decode algorithms - * as well as the use of JAI if available on the class path. We've had trouble in the past with gracefully falling - * back onto working implementation as each decoding method often errors without any exception. - */ - private BufferedImage ccittFaxDecode( - PColorSpace colourSpace, - GraphicsState graphicsState, - int width, int height, - int colorSpaceCompCount, - int bitsPerComponent, - boolean isImageMask, - float[] decode, - BufferedImage sMaskImage, - BufferedImage maskImage, - int[] maskMinRGB, int[] maskMaxRGB, - int maskMinIndex, int maskMaxIndex, boolean forceJAI) { - BufferedImage decodedImage = null; - - byte[] data = getDecodedStreamBytes( - width * height - * colourSpace.getNumComponents() - * bitsPerComponent / 8); - int dataLength = data.length; - // try default ccittfax decode. - try { - // corner case where a user may want to use JAI because of - // speed or compatibility requirements. - if (forceJaiccittfax || forceJAI) { - throw new Throwable("Forcing CCITTFAX decode via JAI"); - } - data = ccittFaxDecode(data, width, height); - dataLength = data.length; - } catch (Throwable e) { - // on a failure then fall back to JAI for a try. likely - // will not happen. - try { - decodedImage = CCITTFax.attemptDeriveBufferedImageFromBytes( - this, library, entries, graphicsState.getFillColor()); - } catch (Throwable e1) { - // fall back on ccittfax code. - data = ccittFaxDecode(data, width, height); - dataLength = data.length; - } - if (decodedImage != null) { - return decodedImage; - } - } - // basic error check for an all white or black image, if we try and load the image again. - boolean allWhite = true; - boolean allBlack = true; - for (int i = 0; i < dataLength; i++) { - if (data[i] != -1) { - allWhite = false; - break; - } - } - for (int i = 0; i < dataLength; i++) { - if (data[i] != 0) { - allBlack = false; - break; - } - } - if (!forceJaiccittfax && (allBlack || allWhite)) { - try { - decodedImage = CCITTFax.attemptDeriveBufferedImageFromBytes( - this, library, entries, graphicsState.getFillColor()); - if (decodedImage != null) { - return decodedImage; - } - } catch (Throwable e1) { - logger.finer("Failed to do secondary load attempt with JAI"); - } - } else if (forceJaiccittfax && (allBlack || allWhite)) { - try { - data = ccittFaxDecode(data, width, height); - dataLength = data.length; - } catch (Throwable e) { - logger.finer("Failed to do secondary load attempt with ccittFax"); - } - } - try { - decodedImage = ImageUtility.makeImageWithRasterFromBytes( - colourSpace, - graphicsState, - width, height, - colorSpaceCompCount, - bitsPerComponent, - isImageMask, - decode, - sMaskImage, - maskImage, - maskMinRGB, maskMaxRGB, - maskMinIndex, maskMaxIndex, - data, dataLength); - } catch (Exception e) { - logger.log(Level.FINE, "Error building image raster.", e); - if (!forceJAI) { - decodedImage = ccittFaxDecode(colourSpace, graphicsState, width, height, - colorSpaceCompCount, bitsPerComponent, isImageMask, decode, sMaskImage, maskImage, - maskMinRGB, maskMaxRGB, maskMinIndex, maskMaxIndex, true); - } - } - return decodedImage; - } - - /** - * The DCTDecode filter decodes grayscale or color image data that has been - * encoded in the JPEG baseline format. Because DCTDecode only deals - * with images, the instance of image is update instead of decoded - * stream. - * - * @return buffered images representation of the decoded JPEG data. Null - * if the image could not be properly decoded. - */ - private BufferedImage dctDecode( - int width, int height, PColorSpace colourSpace, int bitspercomponent, - float[] decode) { - - // BIS's buffer size should be equal to mark() size, and greater than data size (below) - InputStream input = getDecodedByteArrayInputStream(); - // Used to just read 1000, but found a PDF that included thumbnails first - final int MAX_BYTES_TO_READ_FOR_ENCODING = 2048; - BufferedInputStream bufferedInput = new BufferedInputStream( - input, MAX_BYTES_TO_READ_FOR_ENCODING); - bufferedInput.mark(MAX_BYTES_TO_READ_FOR_ENCODING); - - // We don't use the PColorSpace to determine how to decode the JPEG, because it tends to be wrong - // Some files say DeviceCMYK, or ICCBased, when neither would work, because it's really YCbCrA - // What does work though, is to look into the JPEG headers themself, via getJPEGEncoding() - - int jpegEncoding; - BufferedImage tmpImage = null; - ImageReader reader = null; - ImageInputStream imageInputStream = null; - try { - // get the full image data. - byte[] data = getDecodedStreamBytes( - width * height - * colourSpace.getNumComponents() - * bitspercomponent / 8); - - int dataRead = data.length; - if (dataRead > MAX_BYTES_TO_READ_FOR_ENCODING) { - dataRead = MAX_BYTES_TO_READ_FOR_ENCODING; - } - // check the encoding type for colour conversion. - jpegEncoding = ImageUtility.getJPEGEncoding(data, dataRead); - - imageInputStream = ImageIO.createImageInputStream( - new ByteArrayInputStream(data)); - - // get a reader that supports getting the raster. - Iterator iter = ImageIO.getImageReaders(imageInputStream); - while (iter.hasNext()) { - reader = iter.next(); - if (reader.canReadRaster()) { - if (logger.isLoggable(Level.FINER)) { - logger.finer("DCTDecode Image reader: " + reader + " " + width + "x" + height); - } - break; - } - } - // should never happen but bail on an empty reader. - if (reader == null) { - imageInputStream.close(); - return null; - } - reader.setInput(imageInputStream, true, true); - // read the raster data only, as we have our own logic to covert - // the raster data to RGB colours. - ImageReadParam param = reader.getDefaultReadParam(); - WritableRaster wr = (WritableRaster) reader.readRaster(0, param); - - if (jpegEncoding == ImageUtility.JPEG_ENC_RGB && bitspercomponent == 8) { - tmpImage = ImageUtility.convertSpaceToRgb(wr, colourSpace, decode); - } else if (jpegEncoding == ImageUtility.JPEG_ENC_CMYK && bitspercomponent == 8) { - tmpImage = ImageUtility.convertCmykToRgb(wr, decode); - } else if (jpegEncoding == ImageUtility.JPEG_ENC_YCbCr && bitspercomponent == 8 && - !(colourSpace instanceof Indexed)) { - tmpImage = ImageUtility.convertYCbCrToRGB(wr, decode); - } else if (jpegEncoding == ImageUtility.JPEG_ENC_YCCK && bitspercomponent == 8) { - // YCCK to RGB works better if an CMYK intermediate is used, but slower. - tmpImage = ImageUtility.convertYCCKToRgb(wr, decode); - } else if (jpegEncoding == ImageUtility.JPEG_ENC_GRAY && bitspercomponent == 8) { - // In DCTDecode with ColorSpace=DeviceGray, the samples are gray values (2000_SID_Service_Info.core) - // In DCTDecode with ColorSpace=Separation, the samples are Y values (45-14550BGermanForWeb.core AKA 4570.core) - // Avoid converting images that are already likely gray. - if (!(colourSpace instanceof DeviceGray) && - !(colourSpace instanceof ICCBased) && - !(colourSpace instanceof Indexed)) { - if (colourSpace instanceof Separation && - ((Separation) colourSpace).isNamedColor()) { - tmpImage = ImageUtility.convertGrayToRgb(wr, decode); - } else { - tmpImage = ImageUtility.convertSpaceToRgb(wr, colourSpace, decode); - } - } else { - if (colourSpace instanceof Indexed){ - tmpImage = ImageUtility.applyIndexColourModel(wr, colourSpace, bitspercomponent); - } else if (wr.getNumBands() == 1) { - tmpImage = ImageUtility.makeGrayBufferedImage(wr); - }else { - tmpImage = ImageUtility.convertYCbCrToRGB(wr, decode); - } - } - } else { - if (colourSpace instanceof Indexed) { - return ImageUtility.applyIndexColourModel(wr, colourSpace, bitspercomponent); - } - // assume gray based jpeg. - if (wr.getNumBands() == 1) { - tmpImage = ImageUtility.convertSpaceToRgb(wr, colourSpace, decode); - } - // otherwise assume YCbCr bands = 3. - else { - tmpImage = ImageUtility.convertYCbCrToRGB(wr, decode); - } - } - - } catch (IOException e) { - logger.log(Level.FINE, "Problem loading JPEG image via ImageIO: ", e); - } finally { - try { - input.close(); - // clean up the image reader and image stream - if (reader != null) { - reader.dispose(); - } - if (imageInputStream != null) { - imageInputStream.close(); - } - } catch (IOException e) { - logger.log(Level.FINE, "Problem loading JPEG image via ImageIO: ", e); - } - } - // legacy fallback code for creating Image. -// if (tmpImage == null) { -// try { -// //System.out.println("Stream.dctDecode() Toolkit"); -// byte[] data = getDecodedStreamBytes(width * height -// * colourSpace.getNumComponents() -// * bitspercomponent / 8); -// if (data != null) { -// Image img = Toolkit.getDefaultToolkit().createImage(data); -// if (img != null) { -// tmpImage = ImageUtility.makeRGBABufferedImageFromImage(img); -// } -// } -// } catch (Exception e) { -// logger.log(Level.FINE, "Problem loading JPEG image via Toolkit: ", e); -// } -// } - return tmpImage; - } - - /** - * Utility method to decode JBig2 images. - * - * @param width width of image - * @param height height of image - * @return buffered image of decoded jbig2 image stream. Null if an error - * occured during decode. - */ - private BufferedImage jbig2Decode(int width, int height, - PColorSpace colourSpace, - int bitsPerComponent, float[] decode) { - BufferedImage tmpImage; - - // get the decode params form the stream - HashMap decodeParms = library.getDictionary(entries, DECODEPARMS_KEY); - Stream globalsStream = null; - if (decodeParms != null) { - Object jbigGlobals = library.getObject(decodeParms, JBIG2GLOBALS_KEY); - if (jbigGlobals instanceof Stream) { - globalsStream = (Stream) jbigGlobals; - } - } - // grab the data, - byte[] data = getDecodedStreamBytes( - width * height - * colourSpace.getNumComponents() - * bitsPerComponent / 8); - - // ICEpdf-pro has a commercial license of the levigo library but the OS - // library can use it to if the project can comply with levigo's open - // source licence. - if (isLevigoJBIG2ImageReaderClass) { - try { - tmpImage = ImageUtility.proJbig2Decode( - ImageIO.createImageInputStream(new ByteArrayInputStream(data)), - decodeParms, globalsStream); - } catch (Exception e) { - logger.log(Level.WARNING, "Problem loading JBIG2 image using Levigo: ", e); - // fall back and try and load with the OS jbig2 implementation. - tmpImage = ImageUtility.jbig2Decode( - data, - decodeParms, globalsStream); - } - } else { - tmpImage = ImageUtility.jbig2Decode( - data, - decodeParms, globalsStream); - } - // apply decode - if ((colourSpace instanceof DeviceGray)) { - tmpImage = ImageUtility.applyGrayDecode(tmpImage, bitsPerComponent, decode); - } - - // apply the fill colour and alpha if masking is enabled. - return tmpImage; - } - - /** - * Utility method to decode JPEG2000 images. - * - * @param width width of image. - * @param height height of image. - * @param colourSpace colour space to apply to image. - * @param bitsPerComponent bits used to represent a colour - * @return buffered image of the jpeg2000 image stream. Null if a problem - * occurred during the decode. - */ - private BufferedImage jpxDecode(int width, int height, PColorSpace colourSpace, - int bitsPerComponent, float[] decode) { - BufferedImage tmpImage = null; - try { - // Verify that ImageIO can read JPEG2000 - Iterator iterator = ImageIO.getImageReadersByFormatName("JPEG2000"); - if (!iterator.hasNext()) { - logger.info( - "ImageIO missing required plug-in to read JPEG 2000 images. " + - "You can download the JAI ImageIO Tools from: " + - "http://www.oracle.com/technetwork/java/current-142188.html"); - return null; - } - // decode the image. - byte[] data = getDecodedStreamBytes( - width * height - * colourSpace.getNumComponents() - * bitsPerComponent / 8); - ImageInputStream imageInputStream = ImageIO.createImageInputStream( - new ByteArrayInputStream(data)); - - - // getting the raster for JPX seems to fail in most cases. - Iterator iter = ImageIO.getImageReaders(imageInputStream); - ImageReader reader = null; - while (iter.hasNext()) { - reader = iter.next(); - if (reader.canReadRaster()) { - if (logger.isLoggable(Level.FINER)) { - logger.finer("JPXDecode Image reader: " + reader); - } - break; - } - } - - // read the raster data only, as we have our own logic to covert - // the raster data to RGB colours. - if (reader == null) { - imageInputStream.close(); - return null; - } - ImageReadParam param = reader.getDefaultReadParam(); - reader.setInput(imageInputStream, true, true); - try { - tmpImage = reader.read(0, param); - } finally { - reader.dispose(); - imageInputStream.close(); - } - WritableRaster wr = tmpImage.getRaster(); - - // special fallback scenario for ICCBased colours. - if (colourSpace instanceof ICCBased) { - ICCBased iccBased = (ICCBased) colourSpace; - // first try and apply the color space - try { - ColorSpace cs = iccBased.getColorSpace(); - ColorConvertOp cco = new ColorConvertOp(cs, null); - tmpImage = ImageUtility.makeRGBBufferedImage(wr); - cco.filter(tmpImage, tmpImage); - } catch (Throwable e) { - logger.warning("Error processing ICC Color profile, failing " + - "back to alternative."); - // set the alternate as the current and try and process - // using the below rules. - colourSpace = iccBased.getAlternate(); - } - } - // apply respective colour models to the JPEG2000 image. - if (colourSpace instanceof DeviceRGB && bitsPerComponent == 8) { - tmpImage = ImageUtility.convertSpaceToRgb(wr, colourSpace, decode); - } else if (colourSpace instanceof DeviceCMYK && bitsPerComponent == 8) { - tmpImage = ImageUtility.convertCmykToRgb(wr, decode); - } else if ((colourSpace instanceof DeviceGray) - && bitsPerComponent == 8) { - tmpImage = ImageUtility.makeGrayBufferedImage(wr); - } else if (colourSpace instanceof Separation) { - if (colourSpace instanceof Separation && - ((Separation) colourSpace).isNamedColor()) { - tmpImage = ImageUtility.convertGrayToRgb(wr, decode); -// tmpImage = ImageUtility.makeGrayBufferedImage(wr); - } else { - tmpImage = ImageUtility.convertSpaceToRgb(wr, colourSpace, decode); - } - } else if (colourSpace instanceof Indexed) { - // still some issue here with Chevron.pdf - tmpImage = ImageUtility.applyIndexColourModel(wr, colourSpace, bitsPerComponent); - } - } catch (IOException e) { - logger.log(Level.FINE, "Problem loading JPEG2000 image: ", e); - } - - return tmpImage; - } - - /** - * CCITT fax decode algorithm, decodes the stream into a valid image - * stream that can be used to create a BufferedImage. - * - * @param width of image - * @param height height of image. - * @return decoded stream bytes. - */ - private byte[] ccittFaxDecode(byte[] streamData, int width, int height) { - HashMap decodeParms = library.getDictionary(entries, DECODEPARMS_KEY); - float k = library.getFloat(decodeParms, K_KEY); - // default value is always false - boolean blackIs1 = getBlackIs1(library, decodeParms); - // double check for blackIs1 in the main dictionary. - if (!blackIs1 && CHECK_PARENT_BLACK_IS_1) { - blackIs1 = getBlackIs1(library, entries); - } - // get value of key if it is available. - boolean encodedByteAlign = false; - Object encodedByteAlignObject = library.getObject(decodeParms, ENCODEDBYTEALIGN_KEY); - if (encodedByteAlignObject instanceof Boolean) { - encodedByteAlign = (Boolean) encodedByteAlignObject; - } - int columns = library.getInt(decodeParms, COLUMNS_KEY); - int rows = library.getInt(decodeParms, ROWS_KEY); - - if (columns == 0) { - columns = width; - } - if (rows == 0) { - rows = height; - } - int size = rows * ((columns + 7) >> 3); - byte[] decodedStreamData = new byte[size]; - CCITTFaxDecoder decoder = new CCITTFaxDecoder(1, columns, rows); - decoder.setAlign(encodedByteAlign); - // pick three three possible fax encoding. - try { - if (k == 0) { - decoder.decodeT41D(decodedStreamData, streamData, 0, rows); - } else if (k > 0) { - decoder.decodeT42D(decodedStreamData, streamData, 0, rows); - } else if (k < 0) { - decoder.decodeT6(decodedStreamData, streamData, 0, rows); - } - } catch (Exception e) { - logger.warning("Error decoding CCITTFax image k: " + k); - // IText 5.03 doesn't correctly assign a k value for the deocde, - // as result we can try one more time using the T6. - decoder.decodeT6(decodedStreamData, streamData, 0, rows); - } - // check the black is value flag, no one likes inverted colours. - if (!blackIs1) { - // toggle the byte data invert colour, not bit operand. - for (int i = 0; i < decodedStreamData.length; i++) { - decodedStreamData[i] = (byte) ~decodedStreamData[i]; - } - } - return decodedStreamData; - } - - /** - * Parses the image stream and creates a Java Images object based on the - * the given stream and the supporting paramaters. - * - * @param width dimension of new image - * @param height dimension of new image - * @param colorSpace colour space of image - * @param imageMask true if the image has a imageMask, false otherwise - * @param bitsPerColour number of bits used in a colour - * @param decode Decode attribute values from PObject - * @return valid java image from the PDF stream - */ - private BufferedImage parseImage( - int width, - int height, - PColorSpace colorSpace, - boolean imageMask, - GraphicsState graphicsState, - int bitsPerColour, - float[] decode, - byte[] baCCITTFaxData) { - - // store for manipulating bits in image - int[] imageBits = new int[width]; - - // RGB value for colour used as fill for image - int fillRGB = 1; - if (graphicsState != null) { - fillRGB = graphicsState.getFillColor().getRGB(); - } - - // Number of colour components in image, should be 3 for RGB or 4 - // for ARGB. - int colorSpaceCompCount = colorSpace.getNumComponents(); - boolean isDeviceRGB = colorSpace instanceof DeviceRGB; - boolean isDeviceGray = colorSpace instanceof DeviceGray; - - // Max value used to represent a colour, usually 255, min is 0 - int maxColourValue = ((1 << bitsPerColour) - 1); - - int f[] = new int[colorSpaceCompCount]; - float ff[] = new float[colorSpaceCompCount]; - - // image mask from - float imageMaskValue = decode[0]; - - // Create the memory hole where where the buffered image will be written - // too, bit by painful bit. - BufferedImage bim = ImageUtility.createTranslucentCompatibleImage(width, height); - - // create the buffer and get the first series of bytes from the cached - // stream - BitStream in; - if (baCCITTFaxData != null) { - in = new BitStream(new ByteArrayInputStream(baCCITTFaxData)); - } else { - InputStream dataInput = getDecodedByteArrayInputStream(); - if (dataInput == null) - return null; - in = new BitStream(dataInput); - } - - try { - // Start encoding bit stream into an image, we work one pixel at - // a time, and grap the need bit information for the images - // colour space and bits per colour - for (int y = 0; y < height; y++) { - - for (int x = 0; x < width; x++) { - - // if image has mask apply it - if (imageMask) { - int bit = in.getBits(bitsPerColour); - bit = (bit == imageMaskValue) ? fillRGB : 0x00000000; - imageBits[x] = bit; - } - // other wise start colour bit parsing - else { - // set some default values - int red = 255; - int blue = 255; - int green = 255; - int alpha = 255; - - // indexed colour - if (colorSpaceCompCount == 1) { - // get value used for this bit - int bit = in.getBits(bitsPerColour); - // check decode array if a colour inversion is needed - if (decode != null) { - // if index 0 > index 1 then we have a need for ainversion - if (decode[0] > decode[1]) { - bit = (bit == maxColourValue) ? 0x00000000 : maxColourValue; - } - } - - if (isDeviceGray) { - if (bitsPerColour == 1) - bit = ImageUtility.GRAY_1_BIT_INDEX_TO_RGB[bit]; - else if (bitsPerColour == 2) - bit = ImageUtility.GRAY_2_BIT_INDEX_TO_RGB[bit]; - else if (bitsPerColour == 4) - bit = ImageUtility.GRAY_4_BIT_INDEX_TO_RGB[bit]; - else if (bitsPerColour == 8) { - bit = ((bit << 24) | - (bit << 16) | - (bit << 8) | - bit); - } - imageBits[x] = bit; - } else { - f[0] = bit; - colorSpace.normaliseComponentsToFloats(f, ff, maxColourValue); - - Color color = colorSpace.getColor(ff); - imageBits[x] = color.getRGB(); - } - } - // normal RGB colour - else if (colorSpaceCompCount == 3) { - // We can have an ICCBased color space that has 3 components, - // but where we can't assume it's RGB. - // But, when it is DeviceRGB, we don't want the performance hit - // of converting the pixels via the PColorSpace, so we'll - // break this into the two cases - if (isDeviceRGB) { - red = in.getBits(bitsPerColour); - green = in.getBits(bitsPerColour); - blue = in.getBits(bitsPerColour); - // combine the colour together - imageBits[x] = (alpha << 24) | (red << 16) | - (green << 8) | blue; - } else { - for (int i = 0; i < colorSpaceCompCount; i++) { - f[i] = in.getBits(bitsPerColour); - } - PColorSpace.reverseInPlace(f); - colorSpace.normaliseComponentsToFloats(f, ff, maxColourValue); - Color color = colorSpace.getColor(ff); - imageBits[x] = color.getRGB(); - } - } - // normal aRGB colour, this could use some more - // work for optimizing. - else if (colorSpaceCompCount == 4 || colorSpace instanceof DeviceN) { - for (int i = 0; i < colorSpaceCompCount; i++) { - f[i] = in.getBits(bitsPerColour); - // apply decode - if (decode[0] > decode[1]) { - f[i] = maxColourValue - f[i]; - } - } - PColorSpace.reverseInPlace(f); - colorSpace.normaliseComponentsToFloats(f, ff, maxColourValue); - Color color = colorSpace.getColor(ff); - imageBits[x] = color.getRGB(); - } - // else just set pixel with the default values - else { - // compine the colour together - imageBits[x] = (alpha << 24) | (red << 16) | - (green << 8) | blue; - } - } - } - // Assign the new bits for this pixel - bim.setRGB(0, y, width, 1, imageBits, 0, 1); - } - // final clean up. - in.close(); - } catch (IOException e) { - logger.log(Level.FINE, "Error parsing image.", e); - } - - return bim; - } - - /** - * If BlackIs1 was not specified, then return null, instead of the - * default value of false, so we can tell if it was given or not - */ - public boolean getBlackIs1(Library library, HashMap decodeParmsDictionary) { - Object blackIs1Obj = library.getObject(decodeParmsDictionary, BLACKIS1_KEY); - if (blackIs1Obj != null) { - if (blackIs1Obj instanceof Boolean) { - return (Boolean) blackIs1Obj; - } else if (blackIs1Obj instanceof String) { - String blackIs1String = (String) blackIs1Obj; - if (blackIs1String.equalsIgnoreCase("true")) - return true; - else if (blackIs1String.equalsIgnoreCase("t")) - return true; - else if (blackIs1String.equals("1")) - return true; - else if (blackIs1String.equalsIgnoreCase("false")) - return false; - else if (blackIs1String.equalsIgnoreCase("f")) - return false; - else if (blackIs1String.equals("0")) - return false; - } - } - return false; - } - - private boolean containsFilter(String[] searchFilterNames) { - List filterNames = getFilterNames(); - if (filterNames == null) - return false; - for (Object filterName1 : filterNames) { - String filterName = filterName1.toString(); - for (String search : searchFilterNames) { - if (search.equals(filterName)) { - return true; - } - } - } - return false; - } - - /** - * Does the image have an ImageMask. - */ - public boolean isImageMask() { - return library.getBoolean(entries, IMAGEMASK_KEY); - } - - private boolean shouldUseCCITTFaxDecode() { - return containsFilter(CCITTFAX_DECODE_FILTERS); - } - - private boolean shouldUseDCTDecode() { - return containsFilter(DCT_DECODE_FILTERS); - } - - private boolean shouldUseJBIG2Decode() { - return containsFilter(JBIG2_DECODE_FILTERS); - } - - private boolean shouldUseJPXDecode() { - return containsFilter(JPX_DECODE_FILTERS); - } - - /** - * Used to enable/disable the loading of CCITTFax images using JAI library. - * This method can be used in place of the system property - * org.icepdf.core.ccittfax.jai . - * - * @param enable eanb - */ - public static void forceJaiCcittFax(boolean enable) { - forceJaiccittfax = enable; - } - - public PColorSpace getColourSpace() { - synchronized (colorSpaceAssignmentLock) { - return colourSpace; - } - } - - /** - * Return a string description of the object. Primarily used for debugging. - */ - public String toString() { - StringBuilder sb = new StringBuilder(64); - sb.append("Image stream= "); - sb.append(entries); - if (getPObjectReference() != null) { - sb.append(" "); - sb.append(getPObjectReference()); - } - return sb.toString(); - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ImageUtility.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ImageUtility.java deleted file mode 100644 index 03b87424c5..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ImageUtility.java +++ /dev/null @@ -1,1545 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.graphics.*; -import org.icepdf.core.pobjects.graphics.RasterOps.*; -import org.icepdf.core.util.Defs; - -import javax.imageio.ImageIO; -import javax.imageio.stream.ImageInputStream; -import javax.swing.*; -import java.awt.*; -import java.awt.color.ColorSpace; -import java.awt.geom.AffineTransform; -import java.awt.image.*; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Utility methods for applying various colour models and masks to - * image data. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class ImageUtility { - - private static final Logger logger = - Logger.getLogger(ImageUtility.class.toString()); - - protected static final int[] GRAY_1_BIT_INDEX_TO_RGB_REVERSED = new int[]{ - 0xFFFFFFFF, - 0xFF000000 - }; - protected static final int[] GRAY_1_BIT_INDEX_TO_RGB = new int[]{ - 0xFF000000, - 0xFFFFFFFF - }; - protected static final int[] GRAY_2_BIT_INDEX_TO_RGB = new int[]{ - 0xFF000000, - 0xFF555555, - 0xFFAAAAAA, - 0xFFFFFFFF - }; // 0. 1 2 3 4 5. 6 7 8 9 A. B C D E F. 0/3, 1/3, 2/3, 3/3 - protected static final int[] GRAY_4_BIT_INDEX_TO_RGB = new int[]{ - 0xFF000000, - 0xFF111111, - 0xFF222222, - 0xFF333333, - 0xFF444444, - 0xFF555555, - 0xFF666666, - 0xFF777777, - 0xFF888888, - 0xFF999999, - 0xFFAAAAAA, - 0xFFBBBBBB, - 0xFFCCCCCC, - 0xFFDDDDDD, - 0xFFEEEEEE, - 0xFFFFFFFF - }; - protected static final int JPEG_ENC_UNKNOWN_PROBABLY_YCbCr = 0; - protected static final int JPEG_ENC_RGB = 1; - protected static final int JPEG_ENC_CMYK = 2; - protected static final int JPEG_ENC_YCbCr = 3; - protected static final int JPEG_ENC_YCCK = 4; - protected static final int JPEG_ENC_GRAY = 5; - - private static boolean scaleQuality; - - private static GraphicsConfiguration configuration = null; - - static { - try { - configuration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); - } catch (Throwable e) { - // just eat it as we likely have a headless exception and need to fall back to - // creating our own buffers. - } - - // decide if large images will be scaled - scaleQuality = - Defs.booleanProperty("org.icepdf.core.imageMaskScale.quality", - true); - } - - private static ImageUtility imageUtility; - - private ImageUtility() { - - } - - /** - * Creates a new bufferd image using a GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice() - * instance. If not available (headless) we full back to raw buffer creation. - * - * @param width width of new image. - * @param height height of new image. - * @return returns an INT_RGB images. - */ - public static BufferedImage createCompatibleImage(int width, int height) { - if (configuration != null) { - return configuration.createCompatibleImage(width, height); - } else { - return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - } - } - - /** - * Creates a new bufferd image using a GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice() - * instance. If not available (headless) we full back to raw buffer creation. - * - * @param width width of new image. - * @param height height of new image. - * @return - */ - public static BufferedImage createTranslucentCompatibleImage(int width, int height) { - if (configuration != null) { - if (logger.isLoggable(Level.FINER)) { - logger.finer("Creating translucent image buffer " + width + "x" + height); - } - return configuration.createCompatibleImage(width, height, Transparency.TRANSLUCENT); - } else { - return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - } - } - - public static ImageUtility getInstance() { - if (imageUtility == null) { - imageUtility = new ImageUtility(); - } - return imageUtility; - } - - protected static BufferedImage alterBufferedImageAlpha(BufferedImage bi, int[] maskMinRGB, int[] maskMaxRGB) { - - // check for alpha, if not we need to create a copy - if (!ImageUtility.hasAlpha(bi)) { - bi = createBufferedImage(bi); - } - - int width = bi.getWidth(); - int height = bi.getHeight(); - - int maskMinRed = 0xFF; - int maskMinGreen = 0xFF; - int maskMinBlue = 0xFF; - int maskMaxRed = 0x00; - int maskMaxGreen = 0x00; - int maskMaxBlue = 0x00; - if (maskMinRGB != null && maskMaxRGB != null) { - maskMinRed = maskMinRGB[0]; - maskMinGreen = maskMinRGB[1]; - maskMinBlue = maskMinRGB[2]; - maskMaxRed = maskMaxRGB[0]; - maskMaxGreen = maskMaxRGB[1]; - maskMaxBlue = maskMaxRGB[2]; - } - - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - int alpha = 0xFF; - int argb = bi.getRGB(x, y); - int red = ((argb >> 16) & 0xFF); - int green = ((argb >> 8) & 0xFF); - int blue = (argb & 0xFF); - if (blue >= maskMinBlue && blue <= maskMaxBlue && - green >= maskMinGreen && green <= maskMaxGreen && - red >= maskMinRed && red <= maskMaxRed) { - alpha = 0x00; - } - if (alpha != 0xFF) { - argb = bi.getRGB(x, y); - argb &= 0x00FFFFFF; - argb |= ((alpha << 24) & 0xFF000000); - bi.setRGB(x, y, argb); - } - } - } - return bi; - } - - public static void writeImage(final BufferedImage bufferedImage, final String fileName, - String baseOutputPath) { - try { - ImageIO.write(bufferedImage, "PNG", - new File(baseOutputPath + fileName + ".png")); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void displayImage(final BufferedImage bufferedImage, final String title) { - - if (bufferedImage == null) { - return; - } - - SwingUtilities.invokeLater(new Runnable() { - public void run() { - final JFrame f = new JFrame("Image - " + title); - f.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); - final int width = (int) (bufferedImage.getWidth() * 1.2); - final int height = (int) (bufferedImage.getHeight() * 1.2); - - JComponent image = new JComponent() { - @Override - public void paint(Graphics g_) { - super.paint(g_); - g_.setColor(Color.green); - g_.fillRect(0, 0, 10000, 10000); - g_.drawImage(bufferedImage, 0, 0, f); - g_.setColor(Color.red); - g_.drawRect(0, 0, bufferedImage.getWidth() - 2, bufferedImage.getHeight() - 2); - } - }; - image.setPreferredSize(new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight())); - image.setSize(new Dimension(width, height)); - - JPanel test = new JPanel(); - test.setPreferredSize(new Dimension(width, height)); - JScrollPane tmp = new JScrollPane(image); - tmp.revalidate(); - f.setSize(new Dimension(width, height)); - f.getContentPane().add(tmp); - f.validate(); - f.setVisible(true); - } - }); - - - } - - /** - * Utility to build an RGBA buffered image using the specified raster and - * a Transparency.OPAQUE transparency model. - * - * @param wr writable raster of image. - * @return constructed image. - */ - protected static BufferedImage makeRGBABufferedImage(WritableRaster wr) { - return makeRGBABufferedImage(wr, Transparency.OPAQUE); - } - - /** - * Utility to build an RGBA buffered image using the specified raster and - * transparency type. - * - * @param wr writable raster of image. - * @param transparency any valid Transparency interface type. Bitmask, - * opaque and translucent. - * @return constructed image. - */ - protected static BufferedImage makeRGBABufferedImage(WritableRaster wr, - final int transparency) { - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - int[] bits = new int[4]; - for (int i = 0; i < bits.length; i++) { - bits[i] = 8; - } - ColorModel cm = new ComponentColorModel( - cs, bits, true, false, - transparency, - wr.getTransferType()); - return new BufferedImage(cm, wr, false, null); - } - - protected static BufferedImage makeBufferedImage(Raster raster) { - - // create a generic colour model and reuse the wraster, intent - // is that this should save quite bit of memory - DirectColorModel colorModel = new DirectColorModel(24, - 0x00ff0000, // Red - 0x0000ff00, // Green - 0x000000ff, // Blue - 0x0 // Alpha - ); - raster = colorModel.createCompatibleWritableRaster(raster.getWidth(), - raster.getHeight()); - return new BufferedImage(colorModel, (WritableRaster) raster, false, null); - -// return new BufferedImage(raster.getWidth(), raster.getHeight(), BufferedImage.TYPE_INT_RGB); - } - - - protected static BufferedImage makeRGBBufferedImage(WritableRaster wr) { - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - int[] bits = new int[3]; - for (int i = 0; i < bits.length; i++) - bits[i] = 8; - ColorModel cm = new ComponentColorModel( - cs, bits, false, false, - ColorModel.OPAQUE, - wr.getTransferType()); - return new BufferedImage(cm, wr, false, null); - } - - protected static BufferedImage makeGrayBufferedImage(WritableRaster wr) { - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); - int[] bits = new int[1]; - for (int i = 0; i < bits.length; i++) - bits[i] = 8; - ColorModel cm = new ComponentColorModel( - cs, bits, false, false, - ColorModel.OPAQUE, - wr.getTransferType()); - return new BufferedImage(cm, wr, false, null); - } - - // This method returns a buffered image with the contents of an image from - // java almanac - protected static BufferedImage makeRGBABufferedImageFromImage(Image image) { - - if (image instanceof BufferedImage) { - return (BufferedImage) image; - } - // This code ensures that all the pixels in the image are loaded - image = new ImageIcon(image).getImage(); - // Determine if the image has transparent pixels; for this method's - // implementation, see Determining If an Image Has Transparent Pixels - boolean hasAlpha = hasAlpha(image); - // Create a buffered image with a format that's compatible with the screen - BufferedImage bImage = null; - try { - // graphics environment calls can through headless exceptions so - // proceed with caution. - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice gs = ge.getDefaultScreenDevice(); - GraphicsConfiguration gc = gs.getDefaultConfiguration(); - // Determine the type of transparency of the new buffered image - int transparency = Transparency.OPAQUE; - if (hasAlpha) { - transparency = Transparency.BITMASK; - } - // Create the buffered image - int width = image.getWidth(null); - int height = image.getHeight(null); - if (width == -1 || height == -1) { - return null; - } - bImage = gc.createCompatibleImage( - image.getWidth(null), image.getHeight(null), transparency); - } catch (HeadlessException e) { - // The system does not have a screen - } - if (bImage == null) { - // Create a buffered image using the default color model - int width = image.getWidth(null); - int height = image.getHeight(null); - if (width == -1 || height == -1) { - return null; - } - if (hasAlpha) { - bImage = ImageUtility.createTranslucentCompatibleImage(width, height); - } else { - bImage = ImageUtility.createCompatibleImage(width, height); - } - } - // Copy image to buffered image - Graphics g = bImage.createGraphics(); - // Paint the image onto the buffered image - g.drawImage(image, 0, 0, null); - g.dispose(); - image.flush(); - return bImage; - } - - // returns true if the specified image has transparent pixels, from - // java almanac - - public static boolean hasAlpha(Image image) { - // If buffered image, the color model is readily available - if (image instanceof BufferedImage) { - BufferedImage bufferedImage = (BufferedImage) image; - return bufferedImage.getColorModel().hasAlpha(); - } - // Use a pixel grabber to retrieve the image's color model; - // grabbing a single pixel is usually sufficient - PixelGrabber pixelGrabber = new PixelGrabber(image, 0, 0, 1, 1, false); - try { - pixelGrabber.grabPixels(); - } catch (InterruptedException e) { - // fail quietly - } - // Get the image's color model - ColorModel cm = pixelGrabber.getColorModel(); - return cm == null || cm.hasAlpha(); - } - - /** - * Apply the Decode Array domain for each colour component. Assumes output - * range is 0-1f for each value in out. - * - * @param pixels colour to process by decode - * @param decode decode array for colour space - * @param out return value - * always (2bitsPerComponent - 1). - */ - protected static void getNormalizedComponents( - byte[] pixels, - float[] decode, - float[] out) { - // interpolate each colour component for the given decode domain. - for (int i = 0; i < pixels.length; i++) { - out[i] = decode[i * 2] + (pixels[i] & 0xff) * decode[(i * 2) + 1]; - } - } - - protected static WritableRaster alterRasterRGBA(WritableRaster wr, BufferedImage smaskImage, BufferedImage maskImage, int[] maskMinRGB, int[] maskMaxRGB) { - Raster smaskRaster = null; - int smaskWidth = 0; - int smaskHeight = 0; - if (smaskImage != null) { - smaskRaster = smaskImage.getRaster(); - smaskWidth = smaskRaster.getWidth(); - smaskHeight = smaskRaster.getHeight(); - } - - Raster maskRaster = null; - int maskWidth = 0; - int maskHeight = 0; - if (maskImage != null) { - maskRaster = maskImage.getRaster(); - maskWidth = maskRaster.getWidth(); - maskHeight = maskRaster.getHeight(); - } - - int maskMinRed = 0xFF; - int maskMinGreen = 0xFF; - int maskMinBlue = 0xFF; - int maskMaxRed = 0x00; - int maskMaxGreen = 0x00; - int maskMaxBlue = 0x00; - if (maskMinRGB != null && maskMaxRGB != null) { - maskMinRed = maskMinRGB[0]; - maskMinGreen = maskMinRGB[1]; - maskMinBlue = maskMinRGB[2]; - maskMaxRed = maskMaxRGB[0]; - maskMaxGreen = maskMaxRGB[1]; - maskMaxBlue = maskMaxRGB[2]; - } - - if (smaskRaster == null && maskRaster == null && (maskMinRGB == null || maskMaxRGB == null)) - return null; - - int[] rgbaValues = new int[4]; - int width = wr.getWidth(); - int height = wr.getHeight(); - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - wr.getPixel(x, y, rgbaValues); - int red = rgbaValues[0]; - int green = rgbaValues[1]; - int blue = rgbaValues[2]; - - int alpha = 0xFF; - if (y < smaskHeight && x < smaskWidth && smaskRaster != null) { - // Alpha equals greyscale value of smask - alpha = (smaskImage.getRGB(x, y)) & 0xFF;//(smaskRaster.getSample(x, y, 0) & 0xFF); - } else if (y < maskHeight && x < maskWidth && maskRaster != null) { - // When making an ImageMask, the alpha channnel is setup so that - // it both works correctly for the ImageMask being painted, - // and also for when it's used here, to determine the alpha - // of an image that it's masking - alpha = (maskImage.getRGB(x, y) >>> 24) & 0xFF; // Extract Alpha from ARGB - } else if (blue >= maskMinBlue && blue <= maskMaxBlue && - green >= maskMinGreen && green <= maskMaxGreen && - red >= maskMinRed && red <= maskMaxRed) { - alpha = 0x00; - } - if (alpha != 0xFF) { - rgbaValues[3] = alpha; - wr.setPixel(x, y, rgbaValues); - } - } - } - return wr; - } - - - /** - * (see 8.9.6.3, "Explicit Masking") - * Explicit Masking algorithm, as of PDF 1.3. The entry in an image dictionary - * may be an image mask, as described under "Stencil Masking", which serves as - * an explicit mask for the primary or base image. The base image and the - * image mask need not have the same resolution (width, height), but since - * all images are defined on the unit square in user space, their boundaries on the - * page will conincide; that is, they will overlay each other. - *

- * The image mask indicates indicates which places on the page are to be painted - * and which are to be masked out (left unchanged). Unmasked areas are painted - * with the corresponding portions of the base image; masked areas are not. - * - * @param baseImage base image in which the mask weill be applied to - * @param maskImage image mask to be applied to base image. - */ - public static BufferedImage applyExplicitMask(BufferedImage baseImage, BufferedImage maskImage) { - // check to see if we need to scale the mask to match the size of the - // base image. - int baseWidth; - int baseHeight; - - // check to make sure the mask and the image are the same size. - BufferedImage[] images = scaleImagesToSameSize(baseImage, maskImage); - baseImage = images[0]; - maskImage = images[1]; - - // apply the mask by simply painting white to the base image where - // the mask specified no colour. - baseWidth = baseImage.getWidth(); - baseHeight = baseImage.getHeight(); - - boolean hasAlpha = ImageUtility.hasAlpha(baseImage); - BufferedImage argbImage; - if (hasAlpha) { - argbImage = baseImage; - } else { - // aways create a new buffer as we need leave the pevioius image un change for some type of masks. - argbImage = ImageUtility.createTranslucentCompatibleImage(baseWidth, baseHeight); - } - int[] srcBand = new int[baseWidth]; - int[] maskBnd = new int[baseWidth]; - // iterate over each band to apply the mask - for (int i = 0; i < baseHeight; i++) { - baseImage.getRGB(0, i, baseWidth, 1, srcBand, 0, baseWidth); - maskImage.getRGB(0, i, baseWidth, 1, maskBnd, 0, baseWidth); - // apply the soft mask blending - for (int j = 0; j < baseWidth; j++) { - if (maskBnd[j] == 0 || maskBnd[j] == 0xffffff) { - // set the pixel as transparent - maskBnd[j] = 0xff; - } else { - maskBnd[j] = srcBand[j]; - } - } - argbImage.setRGB(0, i, baseWidth, 1, maskBnd, 0, baseWidth); - } - baseImage.flush(); - baseImage = argbImage; - - return baseImage; - } - - /** - * Blending mode colour transparency test. - * - * @param baseImage - * @param blendingMode - * @param blendColor - * @return - */ - public static BufferedImage applyBlendingMode(BufferedImage baseImage, Name blendingMode, Color blendColor) { - - // apply the mask by simply painting white to the base image where - // the mask specified no colour. - int baseWidth = baseImage.getWidth(); - int baseHeight = baseImage.getHeight(); - - boolean hasAlpha = ImageUtility.hasAlpha(baseImage); - BufferedImage argbImage; - if (hasAlpha) { - argbImage = baseImage; - } else { - // aways create a new buffer as we need leave the pevioius image un change for some type of masks. - argbImage = ImageUtility.createTranslucentCompatibleImage(baseWidth, baseHeight); - } - int[] srcBand = new int[baseWidth]; - int[] blendBand = new int[baseWidth]; - int blendColorValue = blendColor.getRGB(); - // iterate over each band to apply the mask - for (int i = 0; i < baseHeight; i++) { - baseImage.getRGB(0, i, baseWidth, 1, srcBand, 0, baseWidth); - // apply the soft mask blending - for (int j = 0; j < baseWidth; j++) { - - if (srcBand[j] == blendColorValue || srcBand[j] == 0xffffff || srcBand[j] == 0xffff) { - // set the pixel as transparent - blendBand[j] = 0xff; - } else { - blendBand[j] = srcBand[j]; - } - } - argbImage.setRGB(0, i, baseWidth, 1, blendBand, 0, baseWidth); - } - baseImage.flush(); - baseImage = argbImage; - - return baseImage; - } - - /** - * (see 11.6.5.3, "Soft-Mask Images") - * A subsidiary image XObject defining a soft-mask image that shall be used - * as a source of mask shape or mask opacity values in the transparent imaging - * model. The alpha source parameter in the graphics state determines whether - * the mask values shall be interpreted as shape or opacity. - *

- * If present, this entry shall override the current soft mask in the graphics - * state, as well as the image’s Mask entry, if any. However, the other - * transparency-related graphics state parameters—blend mode and alpha - * constant—shall remain in effect. If SMask is absent, the image shall - * have no associated soft mask (although the current soft mask in the - * graphics state may still apply). - * - * @param baseImage base image in which the mask weill be applied to - */ - public static BufferedImage applyExplicitSMask(BufferedImage baseImage, BufferedImage sMaskImage) { - - // check to make sure the mask and the image are the same size. - BufferedImage[] images = scaleImagesToSameSize(baseImage, sMaskImage); - baseImage = images[0]; - sMaskImage = images[1]; - // apply the mask by simply painting white to the base image where - // the mask specified no colour. - int baseWidth = baseImage.getWidth(); - int baseHeight = baseImage.getHeight(); - - boolean hasAlpha = ImageUtility.hasAlpha(baseImage); - BufferedImage argbImage; - if (hasAlpha) { - argbImage = baseImage; - } else { - // aways create a new buffer as we need leave the pevioius image un change for some type of masks. - argbImage = ImageUtility.createTranslucentCompatibleImage(baseWidth, baseHeight); - } - int[] srcBand = new int[baseWidth]; - int[] sMaskBand = new int[baseWidth]; - // iterate over each band to apply the mask - for (int i = 0; i < baseHeight; i++) { - baseImage.getRGB(0, i, baseWidth, 1, srcBand, 0, baseWidth); - sMaskImage.getRGB(0, i, baseWidth, 1, sMaskBand, 0, baseWidth); - // apply the soft mask blending - for (int j = 0; j < baseWidth; j++) { - // take any one of the primaries and apply src image alpha. - int red = (sMaskBand[j] >> 16) & 0x000000FF; - int alpha = (srcBand[j] >> 24) & 0x000000FF; - int sa = ((int) (red * (alpha / 255.0f))) << 24; - // apply the smask value as the alpha value - srcBand[j] = sa - | (srcBand[j] & ~0xff000000); - } - argbImage.setRGB(0, i, baseWidth, 1, srcBand, 0, baseWidth); - } - baseImage.flush(); - baseImage = argbImage; - - return baseImage; - } - - public static BufferedImage applyExplicitLuminosity(BufferedImage baseImage, BufferedImage sMaskImage) { - - // check to make sure the mask and the image are the same size. - BufferedImage[] images = scaleImagesToSameSize(baseImage, sMaskImage); - baseImage = images[0]; - sMaskImage = images[1]; - // apply the mask by simply painting white to the base image where - // the mask specified no colour. - int baseWidth = baseImage.getWidth(); - int baseHeight = baseImage.getHeight(); - - boolean hasAlpha = ImageUtility.hasAlpha(baseImage); - BufferedImage argbImage; - if (hasAlpha) { - argbImage = baseImage; - } else { - // aways create a new buffer as we need leave the pevioius image un change for some type of masks. - argbImage = ImageUtility.createTranslucentCompatibleImage(baseWidth, baseHeight); - } - - int[] srcBand = new int[baseWidth]; - int[] sMaskBand = new int[baseWidth]; - // iterate over each band to apply the mask - for (int i = 0; i < baseHeight; i++) { - baseImage.getRGB(0, i, baseWidth, 1, srcBand, 0, baseWidth); - sMaskImage.getRGB(0, i, baseWidth, 1, sMaskBand, 0, baseWidth); - for (int j = 0; j < baseWidth; j++) { - int red = (srcBand[j] >> 16) & 0x000000FF; - int green = (srcBand[j] >> 8) & 0x000000FF; - int blue = (srcBand[j]) & 0x000000FF; - // colour is used as a degree of masking. - int alpha = (sMaskBand[j] >> 16) & 0x000000FF; - int trans = (sMaskBand[j] >> 24) & 0x000000FF; - - int redOut = Math.min(255, red - alpha); - int greenOut = Math.min(255, green - alpha); - int blueOut = Math.min(255, blue - alpha); -// trans = trans - alpha;, - - // todo still broken, needs some more examples/ - srcBand[j] = trans << 24 - | Math.max(0, redOut) << 16 - | Math.max(0, greenOut) << 8 - | Math.max(0, blueOut); -// if ((red >= 0 || green >= 0 || blue >= 0) && alpha != 0) { -// srcBand[j] = (Math.min(mAlpha, alpha) )<< 24 -//// srcBand[j] = mAlpha << 24 -// | (redOut & 0xff) << 16 -// | (greenOut & 0xff) << 8 -// | (blueOut & 0xff); -// } - } - argbImage.setRGB(0, i, baseWidth, 1, srcBand, 0, baseWidth); - } - baseImage.flush(); - baseImage = argbImage; - - return baseImage; - } - - public static BufferedImage applyExplicitOutline(BufferedImage baseImage, BufferedImage sMaskImage) { - - // check to make sure the mask and the image are the same size. - BufferedImage[] images = scaleImagesToSameSize(baseImage, sMaskImage); - baseImage = images[0]; - sMaskImage = images[1]; - // apply the mask by simply painting white to the base image where - // the mask specified no colour. - int baseWidth = baseImage.getWidth(); - int baseHeight = baseImage.getHeight(); - - boolean hasAlpha = ImageUtility.hasAlpha(baseImage); - BufferedImage argbImage; - if (hasAlpha) { - argbImage = baseImage; - } else { - // aways create a new buffer as we need leave the pevioius image un change for some type of masks. - argbImage = ImageUtility.createTranslucentCompatibleImage(baseWidth, baseHeight); - } - - int[] srcBand = new int[baseWidth]; - int[] sMaskBand = new int[baseWidth]; - // iterate over each band to apply the outline, where the outline is any pixel with alpha. - for (int i = 0; i < baseHeight; i++) { - baseImage.getRGB(0, i, baseWidth, 1, srcBand, 0, baseWidth); - sMaskImage.getRGB(0, i, baseWidth, 1, sMaskBand, 0, baseWidth); - for (int j = 0; j < baseWidth; j++) { - // take any one of the primaries and apply src image alpha. - int alpha = (sMaskBand[j] >> 24) & 0x000000FF; - int sa = alpha << 24; - // apply the smask value as the alpha value - if (sMaskBand[j] == 0) - srcBand[j] = sa - | (srcBand[j] & ~0xff000000); - } - argbImage.setRGB(0, i, baseWidth, 1, srcBand, 0, baseWidth); - } - baseImage.flush(); - baseImage = argbImage; - - return baseImage; - } - - /** - * Treats the base image as as mask data applying the specified fill colour - * to the flagged bytes and a transparency value otherwise. This method - * creates a new BufferedImage with a transparency model so it will cause - * a memory spike. - * - * @param baseImage masking image. - * @param fill fill value to apply to mask. - * @return masked image encoded with the fill colour and transparency. - */ - protected static BufferedImage applyExplicitMask(BufferedImage baseImage, Color fill) { - // create an - int baseWidth = baseImage.getWidth(); - int baseHeight = baseImage.getHeight(); - - BufferedImage imageMask; - if (hasAlpha(baseImage)) { - imageMask = baseImage; - } else { - imageMask = ImageUtility.createTranslucentCompatibleImage(baseWidth, baseHeight); - } - // apply the mask by simply painting white to the base image where - // the mask specified no colour. - int[] srcBand = new int[baseWidth]; - int[] maskBnd = new int[baseWidth]; - int fillRgb = fill.getRGB(); - // iterate over each band to apply the mask - for (int i = 0; i < baseHeight; i++) { - baseImage.getRGB(0, i, baseWidth, 1, srcBand, 0, baseWidth); - imageMask.getRGB(0, i, baseWidth, 1, maskBnd, 0, baseWidth); - // apply the soft mask blending - for (int j = 0; j < baseWidth; j++) { - if (!(srcBand[j] == -1 || srcBand[j] == 0xffffff)) { - maskBnd[j] = fillRgb; - } - } - imageMask.setRGB(0, i, baseWidth, 1, maskBnd, 0, baseWidth); - } - // clean up the old image. - baseImage.flush(); - // return the mask. - return imageMask; - } - - /** - * Temporarily pulled out the index colur model application for images - * from the raw image decode. This method is only called from JPEG2000 - * code for now but will be consolidate as we move to to 5.0 - */ - protected static BufferedImage applyIndexColourModel( - WritableRaster wr, PColorSpace colourSpace, int bitsPerComponent) { - BufferedImage img = null; - try { - colourSpace.init(); - // build out the colour table. - Color[] colors = ((Indexed) colourSpace).accessColorTable(); - int colorsLength = (colors == null) ? 0 : colors.length; - int[] cmap = new int[256]; - for (int i = 0; i < colorsLength; i++) { - cmap[i] = colors[i].getRGB(); - } - for (int i = colorsLength; i < cmap.length; i++) { - cmap[i] = 0xFF000000; - } - // build a new buffer with indexed colour model. - DataBuffer db = wr.getDataBuffer(); - // SampleModel sm = new PixelInterleavedSampleModel(db.getDataType(), width, height, 1, width, new int[]{0}); - // WritableRaster wr = Raster.createWritableRaster(sm, db, new Point(0, 0)); - ColorModel cm = new IndexColorModel(bitsPerComponent, cmap.length, cmap, 0, true, -1, db.getDataType()); - img = new BufferedImage(cm, wr, false, null); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Indexed colour model initialization interrupted."); - } - return img; - } - - protected static BufferedImage proJbig2Decode(ImageInputStream imageInputStream, - HashMap decodeParms, - Stream globalsStream) - throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, IOException, ClassNotFoundException, InstantiationException { - BufferedImage tmpImage; - - try { - // ICEpdf-pro has a commercial license of the levigo library but the OS library can use it to if the project - // can comply with levigo's open source licence. - Class levigoJBIG2ImageReaderClass = Class.forName("com.levigo.jbig2.JBIG2ImageReader"); - Class jbig2ImageReaderSpiClass = Class.forName("com.levigo.jbig2.JBIG2ImageReaderSpi"); - Class jbig2GlobalsClass = Class.forName("com.levigo.jbig2.JBIG2Globals"); - Object jbig2ImageReaderSpi = jbig2ImageReaderSpiClass.newInstance(); - Constructor levigoJbig2DecoderClassConstructor = - levigoJBIG2ImageReaderClass.getDeclaredConstructor(javax.imageio.spi.ImageReaderSpi.class); - Object levigoJbig2Reader = levigoJbig2DecoderClassConstructor.newInstance(jbig2ImageReaderSpi); - // set the input - Class partypes[] = new Class[1]; - partypes[0] = Object.class; - Object arglist[] = new Object[1]; - arglist[0] = imageInputStream; - Method setInput = - levigoJBIG2ImageReaderClass.getMethod("setInput", partypes); - setInput.invoke(levigoJbig2Reader, arglist); - // apply deocde params if any. - if (decodeParms != null) { - if (globalsStream != null) { - byte[] globals = globalsStream.getDecodedStreamBytes(0); - if (globals != null && globals.length > 0) { - partypes = new Class[1]; - partypes[0] = ImageInputStream.class; - arglist = new Object[1]; - arglist[0] = ImageIO.createImageInputStream(new ByteArrayInputStream(globals)); - Method processGlobals = - levigoJBIG2ImageReaderClass.getMethod("processGlobals", partypes); - Object globalSegments = processGlobals.invoke(levigoJbig2Reader, arglist); - if (globalSegments != null) { - // invoked encoder.setGlobalData(globals); - partypes = new Class[1]; - partypes[0] = jbig2GlobalsClass; - arglist = new Object[1]; - arglist[0] = globalSegments; - // pass the segment data back into the decoder. - Method setGlobalData = - levigoJBIG2ImageReaderClass.getMethod("setGlobals", partypes); - setGlobalData.invoke(levigoJbig2Reader, arglist); - } - } - } - } - partypes = new Class[1]; - partypes[0] = int.class; - arglist = new Object[1]; - arglist[0] = 0; - Method read = - levigoJBIG2ImageReaderClass.getMethod("read", partypes); - tmpImage = (BufferedImage) read.invoke(levigoJbig2Reader, arglist); - // call dispose on the reader - Method dispose = - levigoJBIG2ImageReaderClass.getMethod("dispose", (Class[]) null); - dispose.invoke(levigoJbig2Reader); - } finally { - // dispose the stream - if (imageInputStream != null) { - imageInputStream.close(); - } - } - return tmpImage; - } - - protected static BufferedImage jbig2Decode(byte[] data, - HashMap decodeParms, - Stream globalsStream) { - BufferedImage tmpImage = null; - try { - Class jbig2DecoderClass = Class.forName("org.jpedal.jbig2.JBIG2Decoder"); - // create instance of decoder - Constructor jbig2DecoderClassConstructor = - jbig2DecoderClass.getDeclaredConstructor(); - Object jbig2Decoder = jbig2DecoderClassConstructor.newInstance(); - // get the decode params form the stream - if (decodeParms != null) { - if (globalsStream != null) { - byte[] globals = globalsStream.getDecodedStreamBytes(0); - if (globals != null && globals.length > 0) { - // invoked ecoder.setGlobalData(globals); - Class partypes[] = new Class[1]; - partypes[0] = byte[].class; - Object arglist[] = new Object[1]; - arglist[0] = globals; - Method setGlobalData = - jbig2DecoderClass.getMethod("setGlobalData", partypes); - setGlobalData.invoke(jbig2Decoder, arglist); - } - } - } - // decode the data stream, decoder.decodeJBIG2(data); - - Class argTypes[] = new Class[]{byte[].class}; - Object arglist[] = new Object[]{data}; - Method decodeJBIG2 = jbig2DecoderClass.getMethod("decodeJBIG2", argTypes); - decodeJBIG2.invoke(jbig2Decoder, arglist); - - // From decoding, memory usage increases more than (width*height/8), - // due to intermediate JBIG2Bitmap objects, used to build the final - // one, still hanging around. Cleanup intermediate data-structures. - // decoder.cleanupPostDecode(); - Method cleanupPostDecode = jbig2DecoderClass.getMethod("cleanupPostDecode"); - cleanupPostDecode.invoke(jbig2Decoder); - - // final try an fetch the image. tmpImage = decoder.getPageAsBufferedImage(0); - argTypes = new Class[]{Integer.TYPE}; - arglist = new Object[]{0}; - Method getPageAsBufferedImage = jbig2DecoderClass.getMethod("getPageAsBufferedImage", argTypes); - tmpImage = (BufferedImage) getPageAsBufferedImage.invoke(jbig2Decoder, arglist); - } catch (Exception e) { - logger.log(Level.WARNING, "Problem loading JBIG2 image: ", e); - } - return tmpImage; - } - - protected static int getJPEGEncoding(byte[] data, int dataLength) { - int jpegEncoding = JPEG_ENC_UNKNOWN_PROBABLY_YCbCr; - - boolean foundAPP14 = false; - byte compsTypeFromAPP14 = 0; - boolean foundSOF = false; - int numCompsFromSOF = 0; - boolean foundSOS = false; - int numCompsFromSOS = 0; - - int index = 0; - while (true) { - if (index >= dataLength) - break; - if (data[index] != ((byte) 0xFF)) - break; - if (foundAPP14 && foundSOF) - break; - byte segmentType = data[index + 1]; - index += 2; - if (segmentType == ((byte) 0xD8)) { - //System.out.println("Found SOI (0xD8)"); - continue; - } - - //System.out.println("Segment: " + Integer.toHexString( ((int)segmentType)&0xFF )); - int length = (((data[index] << 8)) & 0xFF00) + (((int) data[index + 1]) & 0xFF); - //System.out.println(" Length: " + length + " Index: " + index); - - // APP14 (Might be Adobe file) - if (segmentType == ((byte) 0xEE)) { - //System.out.println("Found APP14 (0xEE)"); - if (length >= 14) { - foundAPP14 = true; - compsTypeFromAPP14 = data[index + 13]; - //System.out.println("APP14 format: " + compsTypeFromAPP14); - } - } else if (segmentType == ((byte) 0xC0)) { - foundSOF = true; - //System.out.println("Found SOF (0xC0) Start Of Frame"); - //int bitsPerSample = ( ((int)data[index+2]) & 0xFF ); - //int imageHeight = ( ((int)(data[index+3] << 8)) & 0xFF00 ) + ( ((int)data[index+4]) & 0xFF ); - //int imageWidth = ( ((int)(data[index+5] << 8)) & 0xFF00 ) + ( ((int)data[index+6]) & 0xFF ); - numCompsFromSOF = (((int) data[index + 7]) & 0xFF); - //System.out.println(" bitsPerSample: " + bitsPerSample + ", imageWidth: " + imageWidth + ", imageHeight: " + imageHeight + ", numComps: " + numCompsFromSOF); - //int[] compIds = new int[numCompsFromSOF]; - //for(int i = 0; i < numCompsFromSOF; i++) { - // compIds[i] = ( ((int)data[index+8+(i*3)]) & 0xff ); - // System.out.println(" compId: " + compIds[i]); - //} - } else if (segmentType == ((byte) 0xDA)) { - foundSOS = true; - //System.out.println("Found SOS (0xDA) Start Of Scan"); - numCompsFromSOS = (((int) data[index + 2]) & 0xFF); - //int[] compIds = new int[numCompsFromSOS]; - //for(int i = 0; i < numCompsFromSOS; i++) { - // compIds[i] = ( ((int)data[index+3+(i*2)]) & 0xff ); - // System.out.println(" compId: " + compIds[i]); - //} - } - - //System.out.println(" Data: " + org.icepdf.core.util.Utils.convertByteArrayToHexString( data, index+2, Math.min(length-2,dataLength-index-2), true, 20, '\n' )); - index += length; - } - - if (foundAPP14 && foundSOF) { - if (compsTypeFromAPP14 == 0) { // 0 seems to indicate no conversion - if (numCompsFromSOF == 1) - jpegEncoding = JPEG_ENC_GRAY; - if (numCompsFromSOF == 3) // Most assume RGB. DesignJava_times_roman_substitution.PDF supports this. - jpegEncoding = JPEG_ENC_RGB; - else if (numCompsFromSOF == 4) // CMYK - jpegEncoding = JPEG_ENC_CMYK; - } else if (compsTypeFromAPP14 == 1) { // YCbCr - jpegEncoding = JPEG_ENC_YCbCr; - } else if (compsTypeFromAPP14 == 2) { // YCCK - jpegEncoding = JPEG_ENC_YCCK; - } - } else if (foundSOS) { - if (numCompsFromSOS == 1) - jpegEncoding = JPEG_ENC_GRAY; // Y - } - return jpegEncoding; - } - - public static BufferedImage applyGrayDecode(BufferedImage rgbImage, int bitsPerComponent, float[] decode) { - WritableRaster wr = rgbImage.getRaster(); - int[] cmap = null; - if (bitsPerComponent == 1) { - boolean defaultDecode = 0.0f == decode[0]; - cmap = defaultDecode ? GRAY_1_BIT_INDEX_TO_RGB : GRAY_1_BIT_INDEX_TO_RGB_REVERSED; - } else if (bitsPerComponent == 2) { - cmap = GRAY_2_BIT_INDEX_TO_RGB; - } else if (bitsPerComponent == 4) { - cmap = GRAY_4_BIT_INDEX_TO_RGB; - } - ColorModel cm = new IndexColorModel(bitsPerComponent, cmap.length, cmap, 0, false, -1, wr.getDataBuffer().getDataType()); - rgbImage = new BufferedImage(cm, wr, false, null); - return rgbImage; - } - - public static BufferedImage convertSpaceToRgb( - Raster colourRaster, PColorSpace colorSpace, - float[] decode) { - BufferedImage rgbImage = makeBufferedImage(colourRaster); - WritableRaster rgbRaster = rgbImage.getRaster(); - // apply the decode filter - DecodeRasterOp decodeRasterOp = new DecodeRasterOp(decode, null); - decodeRasterOp.filter(colourRaster, (WritableRaster) colourRaster); - // apply colour space - PColorSpaceRasterOp pColorSpaceRasterOp = new PColorSpaceRasterOp(colorSpace, null); - pColorSpaceRasterOp.filter(colourRaster, rgbRaster); - return rgbImage; - } - - public static BufferedImage convertGrayToRgb(Raster grayRaster, - float[] decode) { - - // apply the decode filter - DecodeRasterOp decodeRasterOp = new DecodeRasterOp(decode, null); - decodeRasterOp.filter(grayRaster, (WritableRaster) grayRaster); - // convert from gray. - GrayRasterOp grayRasterOp = new GrayRasterOp(decode, null); - grayRasterOp.filter(grayRaster, (WritableRaster) grayRaster); - return ImageUtility.makeGrayBufferedImage((WritableRaster) grayRaster); - } - - /** - * Utility method to convert an CMYK based raster to RGB. The can be - * configured to use to different approaches. The first and more accurate - * method uses a ICC color profile specified by the DeviceCMYK.java class. - * This method can be turned off using the system property - * org.icepdf.core.cmyk.disableICCProfile=true at which point an less - * precise method is used to calculate the resultan RGB color. - * - * @param cmykRaster CMYK base raster to convert to RGB. - * @return Buffered image representation of raster. - */ - public static BufferedImage convertCmykToRgb(Raster cmykRaster, - float[] decode) { - BufferedImage rgbImage = makeBufferedImage(cmykRaster); - - if (!DeviceCMYK.isDisableICCCmykColorSpace()) { - WritableRaster rgbRaster = rgbImage.getRaster(); - ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace(); - // apply the decode filter - DecodeRasterOp decodeRasterOp = new DecodeRasterOp(decode, null); - decodeRasterOp.filter(cmykRaster, (WritableRaster) cmykRaster); - // convert it to rgb - ColorConvertOp cmykToRgb = new ColorConvertOp(DeviceCMYK.getIccCmykColorSpace(), rgbCS, null); - cmykToRgb.filter(cmykRaster, rgbRaster); - return rgbImage; - } else { - WritableRaster rgbRaster = rgbImage.getRaster(); - - // apply the decode filter - DecodeRasterOp decodeRasterOp = new DecodeRasterOp(decode, null); - decodeRasterOp.filter(cmykRaster, (WritableRaster) cmykRaster); - // apply the Old non ICC color conversion code - // convert it to rgb - CMYKRasterOp cmykRasterOp = new CMYKRasterOp(null); - cmykRasterOp.filter(cmykRaster, rgbRaster); - return rgbImage; - } - } - - public static BufferedImage convertYCbCrToRGB(Raster yCbCrRaster, - float[] decode) { - - BufferedImage rgbImage = makeBufferedImage(yCbCrRaster); - WritableRaster rgbRaster = rgbImage.getRaster(); - // apply the decode filter - DecodeRasterOp decodeRasterOp = new DecodeRasterOp(decode, null); - decodeRasterOp.filter(yCbCrRaster, (WritableRaster) yCbCrRaster); - // convert to rgb - RasterOp rasterOp; - rasterOp = new YCbCrRasterOp(null); - rasterOp.filter(yCbCrRaster, rgbRaster); - return rgbImage; - } - - public static BufferedImage convertYCCKToRgb(Raster ycckRaster, - float[] decode) { - BufferedImage rgbImage = makeBufferedImage(ycckRaster); - - if (!DeviceCMYK.isDisableICCCmykColorSpace()) { - WritableRaster rgbRaster = rgbImage.getRaster(); - ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace(); - // apply the decode filter - DecodeRasterOp decodeRasterOp = new DecodeRasterOp(decode, null); - decodeRasterOp.filter(ycckRaster, (WritableRaster) ycckRaster); - // apply the YCCK to CMYK - YCCKRasterOp ycckRasterOp = new YCCKRasterOp(null); - ycckRasterOp.filter(ycckRaster, (WritableRaster) ycckRaster); - // convert it to rgb - ColorConvertOp cmykToRgb = new ColorConvertOp(DeviceCMYK.getIccCmykColorSpace(), rgbCS, null); - cmykToRgb.filter(ycckRaster, rgbRaster); - return rgbImage; - } else { - WritableRaster rgbRaster = rgbImage.getRaster(); - - // apply the decode filter - DecodeRasterOp decodeRasterOp = new DecodeRasterOp(decode, null); - decodeRasterOp.filter(ycckRaster, (WritableRaster) ycckRaster); - // apply the YCCK to CMYK - YCCKRasterOp ycckRasterOp = new YCCKRasterOp(null); - ycckRasterOp.filter(ycckRaster, (WritableRaster) ycckRaster); - // apply the Old non ICC color conversion code - // convert it to rgb - CMYKRasterOp cmykRasterOp = new CMYKRasterOp(null); - cmykRasterOp.filter(ycckRaster, rgbRaster); - return rgbImage; - } - } - - protected static BufferedImage makeImageWithRasterFromBytes( - PColorSpace colourSpace, - GraphicsState graphicsState, - int width, int height, - int colorSpaceCompCount, - int bitsPerComponent, - boolean imageMask, - float[] decode, - BufferedImage smaskImage, - BufferedImage maskImage, - int[] maskMinRGB, int[] maskMaxRGB, - int maskMinIndex, int maskMaxIndex, byte[] data, int dataLength) { - BufferedImage img = null; - - // check if the ICCBased colour has an alternative that - // we might support for decoding with a colorModel. - if (colourSpace instanceof ICCBased) { - ICCBased iccBased = (ICCBased) colourSpace; - if (iccBased.getAlternate() != null) { - // set the alternate as the current - colourSpace = iccBased.getAlternate(); - } - } - - if (colourSpace instanceof DeviceGray) { - if (imageMask && bitsPerComponent == 1) { - - //int data_length = data.length; - DataBuffer db = new DataBufferByte(data, dataLength); - WritableRaster wr = Raster.createPackedRaster(db, width, height, - bitsPerComponent, new Point(0, 0)); - - // From PDF 1.6 spec, concerning ImageMask and Decode array: - // it in different places different ways. - // [0 1] (the default for an image mask), a sample value of 0 marks - // the page with the current color, and a 1 leaves the previous - // contents unchanged. - // [1 0] Is the reverse - // In case alpha transparency doesn't work, it'll paint white opaquely - boolean defaultDecode = decode[0] == 0.0f; - //int a = Color.white.getRGB(); - int a = 0x00FFFFFF; // Clear if alpha supported, else white - Color fill = graphicsState.getFillColor(); - int[] cmap = new int[]{ - (defaultDecode ? fill.getRGB() : a), - (defaultDecode ? a : fill.getRGB()) - }; - int transparentIndex = (defaultDecode ? 1 : 0); - IndexColorModel icm = new IndexColorModel( - bitsPerComponent, // the number of bits each pixel occupies - cmap.length, // the size of the color component arrays - cmap, // the array of color components - 0, // the starting offset of the first color component - true, // indicates whether alpha values are contained in the cmap array - transparentIndex, // the index of the fully transparent pixel - db.getDataType()); // the data type of the array used to represent pixel values. The data type must be either DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT - img = new BufferedImage(icm, wr, false, null); - } else if (bitsPerComponent == 1 || bitsPerComponent == 2 || bitsPerComponent == 4) { - //int data_length = data.length; - DataBuffer db = new DataBufferByte(data, dataLength); - WritableRaster wr = Raster.createPackedRaster(db, width, height, bitsPerComponent, new Point(0, 0)); - int[] cmap = null; - if (bitsPerComponent == 1) { - boolean defaultDecode = 0.0f == decode[0]; - cmap = defaultDecode ? GRAY_1_BIT_INDEX_TO_RGB : GRAY_1_BIT_INDEX_TO_RGB_REVERSED; - } else if (bitsPerComponent == 2) - cmap = GRAY_2_BIT_INDEX_TO_RGB; - else if (bitsPerComponent == 4) - cmap = GRAY_4_BIT_INDEX_TO_RGB; - ColorModel cm = new IndexColorModel(bitsPerComponent, cmap.length, cmap, 0, false, -1, db.getDataType()); - img = new BufferedImage(cm, wr, false, null); - } else if (bitsPerComponent == 8) { - img = ImageUtility.createCompatibleImage(width, height); - // convert image data to rgb, seems to to give better colour tones. ? - int[] dataToRGB = ((DataBufferInt) img.getRaster().getDataBuffer()).getData(); - copyDecodedStreamBytesIntoGray(data, dataToRGB, decode); - } - } else if (colourSpace instanceof DeviceRGB) { - if (bitsPerComponent == 8) { - boolean usingAlpha = smaskImage != null || maskImage != null || ((maskMinRGB != null) && (maskMaxRGB != null)); - int type = usingAlpha ? BufferedImage.TYPE_INT_ARGB : - BufferedImage.TYPE_INT_RGB; - img = new BufferedImage(width, height, type); - // convert image data to rgb, a little out of order maybe? - int[] dataToRGB = ((DataBufferInt) img.getRaster().getDataBuffer()).getData(); - copyDecodedStreamBytesIntoRGB(data, dataToRGB); - // apply alpha data. - if (usingAlpha) { - img = ImageUtility.alterBufferedImageAlpha(img, maskMinRGB, maskMaxRGB); - } - } - } else if (colourSpace instanceof DeviceCMYK) { - // this is slow and doesn't do decode properly, push off parseImage() - // as its quick and we can do the generic decode and masking. - if (false && bitsPerComponent == 8) { - DataBuffer db = new DataBufferByte(data, dataLength); - int[] bandOffsets = new int[colorSpaceCompCount]; - for (int i = 0; i < colorSpaceCompCount; i++) { - bandOffsets[i] = i; - } - SampleModel sm = new PixelInterleavedSampleModel(db.getDataType(), width, height, colorSpaceCompCount, colorSpaceCompCount * width, bandOffsets); - WritableRaster wr = Raster.createWritableRaster(sm, db, new Point(0, 0)); - //WritableRaster wr = Raster.createInterleavedRaster( db, width, height, colorSpaceCompCount*width, colorSpaceCompCount, bandOffsets, new Point(0,0) ); - ColorSpace cs = DeviceCMYK.getIccCmykColorSpace(); - int[] bits = new int[colorSpaceCompCount]; - for (int i = 0; i < colorSpaceCompCount; i++) { - bits[i] = bitsPerComponent; - } - ColorModel cm = new ComponentColorModel(cs, bits, false, false, ColorModel.OPAQUE, db.getDataType()); - img = new BufferedImage(cm, wr, false, null); - } - } else if (colourSpace instanceof Indexed) { - if (bitsPerComponent == 1 || bitsPerComponent == 2 || bitsPerComponent == 4) { - try { - colourSpace.init(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - Color[] colors = ((Indexed) colourSpace).accessColorTable(); - int[] cmap = new int[(colors == null) ? 0 : colors.length]; - for (int i = 0; i < cmap.length; i++) { - cmap[i] = colors[i].getRGB(); - } - int cmapMaxLength = 1 << bitsPerComponent; - if (cmap.length > cmapMaxLength) { - int[] cmapTruncated = new int[cmapMaxLength]; - System.arraycopy(cmap, 0, cmapTruncated, 0, cmapMaxLength); - cmap = cmapTruncated; - } - boolean usingIndexedAlpha = maskMinIndex >= 0 && maskMaxIndex >= 0; - boolean usingAlpha = smaskImage != null || maskImage != null || - ((maskMinRGB != null) && (maskMaxRGB != null)); - if (usingAlpha) { - DataBuffer db = new DataBufferByte(data, dataLength); - WritableRaster wr = Raster.createPackedRaster(db, width, height, bitsPerComponent, new Point(0, 0)); - ColorModel cm = new IndexColorModel(bitsPerComponent, cmap.length, cmap, 0, true, -1, db.getDataType()); - img = new BufferedImage(cm, wr, false, null); - img = ImageUtility.alterBufferedImageAlpha(img, maskMinRGB, maskMaxRGB); - } else { - DataBuffer db = new DataBufferByte(data, dataLength); - WritableRaster wr = Raster.createPackedRaster(db, width, height, bitsPerComponent, new Point(0, 0)); - ColorModel cm = new IndexColorModel(bitsPerComponent, cmap.length, cmap, 0, false, -1, db.getDataType()); - img = new BufferedImage(cm, wr, false, null); - } - } else if (bitsPerComponent == 8) { - try { - colourSpace.init(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - Color[] colors = ((Indexed) colourSpace).accessColorTable(); - int colorsLength = (colors == null) ? 0 : colors.length; - int[] cmap = new int[256]; - for (int i = 0; i < colorsLength; i++) { - cmap[i] = colors[i].getRGB(); - } - for (int i = colorsLength; i < cmap.length; i++) { - cmap[i] = 0xFF000000; - } - boolean usingIndexedAlpha = maskMinIndex >= 0 && maskMaxIndex >= 0; - boolean usingAlpha = smaskImage != null || maskImage != null || ((maskMinRGB != null) && (maskMaxRGB != null)); - if (usingIndexedAlpha) { - for (int i = maskMinIndex; i <= maskMaxIndex; i++) { - cmap[i] = 0x00000000; - } - DataBuffer db = new DataBufferByte(data, dataLength); - SampleModel sm = new PixelInterleavedSampleModel(db.getDataType(), width, height, 1, width, new int[]{0}); - WritableRaster wr = Raster.createWritableRaster(sm, db, new Point(0, 0)); - ColorModel cm = new IndexColorModel(bitsPerComponent, cmap.length, cmap, 0, true, -1, db.getDataType()); - img = new BufferedImage(cm, wr, false, null); - } else if (usingAlpha) { - int[] rgbaData = new int[width * height]; - // use rgbaData length as an inline image may have a couple extra bytes at the end. - for (int index = 0, max = rgbaData.length; index < max; index++) { - int cmapIndex = (data[index] & 0xFF); - rgbaData[index] = cmap[cmapIndex]; - } - DataBuffer db = new DataBufferInt(rgbaData, rgbaData.length); - int[] masks = new int[]{0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000}; - //SampleModel sm = new SinglePixelPackedSampleModel( - // db.getDataType(), width, height, masks ); - WritableRaster wr = Raster.createPackedRaster(db, width, height, width, masks, new Point(0, 0)); - ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); - ColorModel cm = new DirectColorModel(cs, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000, false, db.getDataType()); - img = new BufferedImage(cm, wr, false, null); - } else { - DataBuffer db = new DataBufferByte(data, dataLength); - SampleModel sm = new PixelInterleavedSampleModel(db.getDataType(), width, height, 1, width, new int[]{0}); - WritableRaster wr = Raster.createWritableRaster(sm, db, new Point(0, 0)); - ColorModel cm = new IndexColorModel(bitsPerComponent, cmap.length, cmap, 0, false, -1, db.getDataType()); - img = new BufferedImage(cm, wr, false, null); - } - } - } else if (colourSpace instanceof Separation || colourSpace instanceof CalGray) { - if (colourSpace instanceof CalGray || ((Separation) colourSpace).isNamedColor()) { - DataBuffer db = new DataBufferByte(data, dataLength); - WritableRaster wr = Raster.createPackedRaster(db, width, height, bitsPerComponent, new Point(0, 0)); - int[] cmap = null; - if (bitsPerComponent == 1) { - cmap = GRAY_1_BIT_INDEX_TO_RGB; - } else if (bitsPerComponent == 2) { - cmap = GRAY_2_BIT_INDEX_TO_RGB; - } else if (bitsPerComponent == 4) { - cmap = GRAY_4_BIT_INDEX_TO_RGB; - } else if (bitsPerComponent == 8) { - return null; - } - ColorModel cm = new IndexColorModel(bitsPerComponent, cmap.length, cmap, 0, false, -1, db.getDataType()); - img = new BufferedImage(cm, wr, false, null); - } - } - // todo add further raw decode types to help speed up image decode - return img; - } - - private static void copyDecodedStreamBytesIntoRGB(byte[] data, int[] pixels) { - byte[] rgb = new byte[3]; - try { - InputStream input = new ByteArrayInputStream(data); - for (int pixelIndex = 0; pixelIndex < pixels.length; pixelIndex++) { - int argb = 0xFF000000; - final int toRead = 3; - int haveRead = 0; - while (haveRead < toRead) { - int currRead = input.read(rgb, haveRead, toRead - haveRead); - if (currRead < 0) - break; - haveRead += currRead; - } - if (haveRead >= 1) - argb |= ((((int) rgb[0]) << 16) & 0x00FF0000); - if (haveRead >= 2) - argb |= ((((int) rgb[1]) << 8) & 0x0000FF00); - if (haveRead >= 3) - argb |= (((int) rgb[2]) & 0x000000FF); - pixels[pixelIndex] = argb; - } - input.close(); - } catch (IOException e) { - logger.log(Level.FINE, "Problem copying decoding stream bytes: ", e); - } - } - - private static void copyDecodedStreamBytesIntoGray(byte[] data, int[] pixels, float[] decode) { - byte[] rgb = new byte[1]; - boolean defaultDecode = 0.0f == decode[0]; - int Y; - try { - InputStream input = new ByteArrayInputStream(data); - for (int pixelIndex = 0; pixelIndex < pixels.length; pixelIndex++) { - int argb = 0xFF000000; - final int toRead = 1; - int haveRead = 0; - while (haveRead < toRead) { - int currRead = input.read(rgb, haveRead, toRead - haveRead); - if (currRead < 0) - break; - haveRead += currRead; - } - Y = (int) rgb[0] & 0xff; - Y = defaultDecode ? Y : 255 - Y; - argb |= (Y << 16) & 0x00FF0000; - argb |= (Y << 8) & 0x0000FF00; - argb |= (Y & 0x000000FF); - pixels[pixelIndex] = argb; - } - input.close(); - } catch (IOException e) { - logger.log(Level.FINE, "Problem copying decoding stream bytes: ", e); - } - } - - // default version of createBufferedImage - public static BufferedImage createBufferedImage(Image imageIn) { - return createBufferedImage(imageIn, BufferedImage.TYPE_INT_ARGB); - } - - public static BufferedImage createBufferedImage(Image imageIn, - int imageType) { - BufferedImage bufferedImageOut = new BufferedImage(imageIn - .getWidth(null), imageIn.getHeight(null), imageType); - Graphics g = bufferedImageOut.getGraphics(); - g.drawImage(imageIn, 0, 0, null); - imageIn.flush(); - return bufferedImageOut; - } - - /** - * Utility method to scale the two provided images. There are two modes based - * on the system property "". The d - * - * @param baseImage base image that mask will be applied to - * @param maskImage mask image that will be applied to base image. - * @return array of altered baseImage and maskImage, should be same size on - * return. - */ - public static BufferedImage[] scaleImagesToSameSize(BufferedImage baseImage, - BufferedImage maskImage) { - if (scaleQuality) { - int width = baseImage.getWidth(); - int height = baseImage.getHeight(); - - WritableRaster maskRaster = maskImage.getRaster(); - int maskWidth = maskRaster.getWidth(); - int maskHeight = maskRaster.getHeight(); - // scale the image to match the image mask. - if (width < maskWidth || height < maskHeight) { - // calculate scale factors. - double scaleX = maskWidth / (double) width; - double scaleY = maskHeight / (double) height; - // scale the mask to match the base image. - AffineTransform tx = new AffineTransform(); - tx.scale(scaleX, scaleY); - AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - BufferedImage bim = op.filter(baseImage, null); - baseImage.flush(); - baseImage = bim; - } else if (width > maskWidth || height > maskHeight) { - // calculate scale factors. - double scaleX = width / (double) maskWidth; - double scaleY = height / (double) maskHeight; - // scale the mask to match the base image. - AffineTransform tx = new AffineTransform(); - tx.scale(scaleX, scaleY); - AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - BufferedImage bim = op.filter(maskImage, null); - maskImage.flush(); - maskImage = bim; - } - return new BufferedImage[]{baseImage, maskImage}; - } else { - int width = baseImage.getWidth(); - int height = baseImage.getHeight(); - - WritableRaster maskRaster = maskImage.getRaster(); - int maskWidth = maskRaster.getWidth(); - int maskHeight = maskRaster.getHeight(); - // scale the mask to match the smaller image. - if (width < maskWidth || height < maskHeight) { - // calculate scale factors. -// BufferedImage bim = (BufferedImage) -// ImageUtility.getTrilinearScaledInstance(maskImage, width, height); - double scaleX = width / (double) maskWidth; - double scaleY = height / (double) maskHeight; - // scale the mask to match the base image. - AffineTransform tx = new AffineTransform(); - tx.scale(scaleX, scaleY); - AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - BufferedImage bim = op.filter(maskImage, null); - maskImage.flush(); - maskImage = bim; - } - return new BufferedImage[]{baseImage, maskImage}; - } - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/LiteralStringObject.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/LiteralStringObject.java deleted file mode 100644 index 5b7b2d0c3c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/LiteralStringObject.java +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.fonts.Font; -import org.icepdf.core.pobjects.fonts.FontFile; -import org.icepdf.core.pobjects.fonts.ofont.OFont; -import org.icepdf.core.pobjects.security.SecurityManager; -import org.icepdf.core.util.Utils; - -/** - *

This class represents a PDF Literal String Object. Literal String - * objects are written as a sequence of literal characters enclosed in - * parentheses ().

- * - * @since 2.0 - */ -public class LiteralStringObject implements StringObject { - - // core data used to represent the literal string information - private StringBuilder stringData; - - private static char[] hexChar = {'0', '1', '2', '3', '4', '5', '6', - '7', '8', '9', 'a', 'b', 'c', 'd', - 'e', 'f'}; - // Reference is need for standard encryption - Reference reference; - - /** - *

Creates a new literal string object so that it represents the same - * sequence of bytes as in the bytes argument. In other words, the - * initial content of the literal string is the characters represented - * by the byte data.

- * - * @param bytes array of bytes which will be interpreted as literal - * character data. - */ - public LiteralStringObject(byte[] bytes) { - this(new StringBuilder(bytes.length).append(new String(bytes))); - } - - public LiteralStringObject(StringBuilder chars, boolean dif) { - stringData = chars; - } - - /** - *

Creates a new literal string object so that it represents the same - * sequence of character data specifed by the argument.

- * - * @param string the initial contents of the literal string object - */ - public LiteralStringObject(String string) { - // append string data - // escape the string for any special characters. - // \( - left parenthesis - // \) - right parenthesis - // \\ - backslash - stringData = new StringBuilder(string.replaceAll("(?=[()\\\\])", "\\\\")); - } - - /** - *

Creates a new literal string object so that it represents the same - * sequence of character data specified by the arguments. The string - * value is assumed to be unencrypted and will be encrypted. The - * method #LiteralStringObject(String string) should be used if the string - * is all ready encrypted. This method is used for creating new - * LiteralStringObject's that are created post document parse, like annotation - * property values.

- * - * @param string the initial contents of the literal string object, - * unencrypted. - * @param reference of parent PObject - * @param securityManager security manager used ot encrypt the string. - */ - public LiteralStringObject(String string, Reference reference, - SecurityManager securityManager) { - // append string data - this.reference = reference; - // convert string to octal encoded. - string = Utils.convertStringToOctal(string); - // decrypt the string. - stringData = new StringBuilder( - encryption(string, false, securityManager)); - } - - /** - *

Creates a new literal string object so that it represents the same - * sequence of character data specifed by the argument. The first and last - * characters of the StringBuffer are removed. This constructor should - * only be used in the context of the parser which has leading and ending - * parentheses which are removed by this method.

- * - * @param stringBuffer the initial contents of the literal string object - */ - public LiteralStringObject(StringBuilder stringBuffer) { - // remove parentheses, passed in by parser - stringBuffer.deleteCharAt(0); - stringBuffer.deleteCharAt(stringBuffer.length() - 1); - // append string data - stringData = new StringBuilder(stringBuffer.length()); - stringData.append(stringBuffer.toString()); - } - - /** - * Gets the integer value of the hexidecimal data specified by the start and - * offset parameters. - * - * @param start the begining index, inclusive - * @param offset the length of bytes to process - * @return unsigned integer value of the specifed data range - */ - public int getUnsignedInt(int start, int offset) { - if (start < 0 || stringData.length() < (start + offset)) - return stringData.charAt(0); - - if (offset == 1) { - return stringData.charAt(start); - } - if (offset == 2) { - return ((stringData.charAt(start) & 0xFF) << 8) | - ((stringData.charAt(start + 1)) & 0xFF); - } else if (offset == 4) { - return ((stringData.charAt(start) & 0xFF) << 24) | - ((stringData.charAt(start + 1) & 0xFF) << 16) | - ((stringData.charAt(start + 2) & 0xFF) << 8) | - ((stringData.charAt(start + 3)) & 0xFF); - } else { - return 0; - } - } - - /** - *

Returns a string representation of the object.

- * - * @return a string representing the object. - */ - public String toString() { - return stringData.toString(); - } - - /** - *

Gets a hexadecimal String representation of this object's data, which - * is converted to hexadecimal form.

- * - * @return a String representation of the objects data. - */ - public String getHexString() { - return stringToHex(stringData).toString(); - } - - /** - *

Gets a hexadecimal StringBuffer representation of this object's data, - * which is converted to hexadecimal form.

- * - * @return a StringBufffer representation of the object's data in hexadecimal - * notation. - */ - public StringBuilder getHexStringBuffer() { - return stringToHex(stringData); - } - - /** - *

Gets a literal StringBuffer representation of this object's data - * which is in fact, the raw data contained in this object.

- * - * @return a StringBuffer representation of the object's data. - */ - public StringBuilder getLiteralStringBuffer() { - return stringData; - } - - /** - *

Gets a literal String representation of this object's data, - * which is in fact, the raw data contained in this object.

- * - * @return a String representation of the object's data. - */ - public String getLiteralString() { - return stringData.toString(); - } - - /** - *

Gets a literal String representation of this object's data using the - * specifed font and format. The font is used to verify that the - * specific character codes can be rendered; if they cannot they may be - * removed or combined with the next character code to get a displayable - * character code. - * - * @param fontFormat the type of pdf font which will be used to display - * the text. Valid values are CID_FORMAT and SIMPLE_FORMAT for Adobe - * Composite and Simple font types respectively - * @param font font used to render the the literal string data. - * @return StringBuffer which contains all renderable characters for the - * given font. - */ - public StringBuilder getLiteralStringBuffer(final int fontFormat, FontFile font) { - - if (fontFormat == Font.SIMPLE_FORMAT - || (font.getByteEncoding() == FontFile.ByteEncoding.ONE_BYTE && !(font instanceof OFont))) { - return stringData; - } else if (fontFormat == Font.CID_FORMAT) { - int length = getLength(); - int charValue; - StringBuilder tmp = new StringBuilder(length); - if (font.getByteEncoding() == FontFile.ByteEncoding.MIXED_BYTE) { - int charOffset = 1; - for (int i = 0; i < length; i += charOffset) { - // check range for possible 2 byte char. - charValue = getUnsignedInt(i, 1); - if (font.canDisplayEchar((char) charValue)) { - tmp.append((char) charValue); - } else { - int charValue2 = getUnsignedInt(i, 2); - if (font.canDisplayEchar((char) charValue2)) { - tmp.append((char) charValue2); - i += 1; - } - } - } - } else { - // we have default 2bytes. - int charOffset = 2; - for (int i = 0; i < length; i += charOffset) { - int charValue2 = getUnsignedInt(i, 2); - if (font.canDisplayEchar((char) charValue2)) { - tmp.append((char) charValue2); - } - } - } - return tmp; - } - return null; - } - - /** - * The length of the the underlying object's data. - * - * @return length of objcts data. - */ - public int getLength() { - return stringData.length(); - } - - /** - * Utility method for converting literal strings to hexadecimal. - * - * @param string StringBuffer in literal form - * @return StringBuffer in hexadecial form - */ - private StringBuilder stringToHex(StringBuilder string) { - StringBuilder hh = new StringBuilder(string.length() * 2); - int charCode; - for (int i = 0, max = string.length(); i < max; i++) { - charCode = string.charAt(i); - hh.append(hexChar[(charCode & 0xf0) >>> 4]); - hh.append(hexChar[charCode & 0x0f]); - } - return hh; - } - - /** - * Sets the parent PDF object's reference. - * - * @param reference parent object reference. - */ - public void setReference(Reference reference) { - this.reference = reference; - } - - /** - * Sets the parent PDF object's reference. - * - * @return returns the reference used for encryption. - */ - public Reference getReference() { - return reference; - } - - /** - * Gets the decrypted literal string value of the data using the key provided by the - * security manager. - * - * @param securityManager security manager associated with parent document. - */ - public String getDecryptedLiteralString(SecurityManager securityManager) { - return encryption(stringData.toString(), true, securityManager); - } - - /** - * Decrypts or encrypts a string. - * - * @param string string to encrypt or decrypt - * @param decrypt true to decrypt string, false otherwise; - * @param securityManager security manager for document. - * @return encrypted or decrypted string, depends on value of decrypt param. - */ - public String encryption(String string, boolean decrypt, - SecurityManager securityManager) { - // get the security manager instance - if (securityManager != null && reference != null) { - // get the key - byte[] key = securityManager.getDecryptionKey(); - - // convert string to bytes. - byte[] textBytes = - Utils.convertByteCharSequenceToByteArray(string); - - // Decrypt String - if (decrypt) { - textBytes = securityManager.decrypt(reference, - key, - textBytes); - } else { - textBytes = securityManager.encrypt(reference, - key, - textBytes); - } - - // convert back to a string - return Utils.convertByteArrayToByteString(textBytes); - } - return string; - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Name.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Name.java deleted file mode 100644 index afe6df913d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Name.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import java.util.logging.Logger; - -/** - *

A name class is an atomic symbol uniquely defined by a sequence of - * characters. Uniquely defined means that any two name objects made up of the - * same sequence of characters are identical. Atomic means - * that a name has no internal structure, although it is defined by a sequence - * of characters, those characters are not "elements" of the name.

- *

- *

A slash character (/) introduces a name. The slash is not part of the name - * itself, but a prefix indicating that the following sequence of characters - * constitutes a name. There can be no white-space characters between the slash - * and the first character in the name. The name may include any regular - * characters, but no delimiter or white-space characters. Uppercase and - * lowercase letters are considered distinct forexample, - * /A and /a are different names.

- *

- *

Names are similar to References in that objects in a PDF document can be - * accessed by their use. The Library class can result in any Name object and return - * the corresponding PDF object.

- * - * @since 1.1 - */ -public class Name { - - private static final Logger logger = - Logger.getLogger(Name.class.toString()); - - private static final int HEX_CHAR = 0X23; - - // String representing the name of the name - private String name; - - /** - * Create a new instance of a Name object. - * - * @param name the name value of the Name object - */ - public Name(String name) { - if (name != null) { - this.name = convertHexChars(new StringBuilder(name)); - } - } - - /** - * Create a new instance of a Name object. - * - * @param name the name value of the Name object - */ - public Name(StringBuilder name) { - - this.name = convertHexChars(name); - } - - /** - * Gets the name of the Name object. - * - * @return name of the object - */ - public String getName() { - return name; - } - - /** - * Gets the string value of the Name object. This is the same as getName() - * - * @return string representation of the name. - * @see #getName() - */ - public String toString() { - return name; - } - - /** - * Indicates whether some other Name object is "equal to" this one - * - * @param obj name object that this Name object is compared against - * @return true, if this object is the same as the obj argument; - * false, otherwise. - */ - public boolean equals(Object obj) { - if (obj instanceof Name) { - return equals((Name) obj); - } else { - return obj != null && name.equals(obj); - } - } - - /** - * Indicates whether some other Name object is "equal to" this one - * - * @param obj name object that this Name object is compared against - * @return true, if this object is the same as the obj argument; - * false, otherwise. - */ - public boolean equals(Name obj) { - return obj != null && name.equals(obj.getName()); - } - - /** - * Indicates whether some other String object is "equal to" this one - * - * @param obj string object that this Name object is compared against - * @return true, if this object is the same as the obj argument; - * false, otherwise. - */ - public boolean equals(String obj) { - return obj != null && name.equals(obj); - } - - /** - * Returns a hash code value for the Name object. This hash is based - * on the String representation of name of the Name object. - * - * @return a hash code value for this object. - */ - public int hashCode() { - return name.hashCode(); - } - - /** - * Utility Method converting Name object hext notation to ascii. For - * example #41 should be represented as 'A'. The hex format will always - * be #XX where XX is a 2 digit hex value. The spec says that # can't be - * used in a string but I guess we'll see. - * - * @param name PDF name object string to be checked for hex codes. - * @return full ascii encoded name string. - */ - private String convertHexChars(StringBuilder name) { - // we need to search for an instance of # and try and convert to hex - try { - for (int i = 0; i < name.length(); i++) { - if (name.charAt(i) == HEX_CHAR) { - // convert digits to hex. - String hex = name.substring(i + 1, i + 3); - name.delete(i, i + 3); - // convert digits to hex. - int charDd = Integer.parseInt(hex, 16); - if (charDd <= 127) { - name.insert(i, (char) charDd); - } else { - name.insert(i, convert(hex)); - } - } - } - } catch (Throwable e) { - logger.finer("Error parsing hexadecimal characters."); - // we are going to bail on any exception and just return the original - // string. - return name.toString(); - } - return name.toString(); - } - - /** - * Converts a hex string to formatted unicode string. - * - * @param hex 2-digit hex number. - * @return hex represented as unicode. - */ - private String convert(String hex) { - StringBuilder output = new StringBuilder(); - output.append("\\u"); // standard unicode format. - for (int j = 0, max = 4 - hex.length(); j < max; j++) { - output.append("0"); - } - output.append(hex.toLowerCase()); - return output.toString(); - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/NameNode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/NameNode.java deleted file mode 100644 index af6a498e32..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/NameNode.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * NameNode used in building a name tree. - * - * @since 4.0 - */ -public class NameNode extends Dictionary { - - public static final Name KIDS_KEY = new Name("Kids"); - public static final Name NAMES_KEY = new Name("Names"); - public static final Name LIMITS_KEY = new Name("Limits"); - - private static Object NOT_FOUND = new Object(); - private static Object NOT_FOUND_IS_LESSER = new Object(); - private static Object NOT_FOUND_IS_GREATER = new Object(); - - private boolean namesAreDecrypted; - // flat tree, names and values only. - private List namesAndValues; - // kids type of tree, need to build out the structure - private List kidsReferences; - private List kidsNodes; - private String lowerLimit; - private String upperLimit; - - /** - * @param l - * @param h - */ - @SuppressWarnings("unchecked") - public NameNode(Library l, HashMap h) { - super(l, h); - // root node can either be a Kids or Names - Object o = library.getObject(entries, KIDS_KEY); - if (o != null && o instanceof List) { - // we have a kids array which can be composed of an intermediary - // /limits/kids and or the leaf /limits/names - kidsReferences = (List) o; - int sz = kidsReferences.size(); - if (sz > 0) { - kidsNodes = new ArrayList(sz); - for (Object ref : kidsReferences) { - if (ref instanceof Reference) { - o = library.getObject((Reference) ref); - kidsNodes.add(new NameNode(library, (HashMap) o)); - } - } - - } - } - // if no kids[] then we must have a names array which is only one leaf. - else if (o == null) { - // process the names - namesAreDecrypted = false; - o = library.getObject(entries, NAMES_KEY); - if (o != null && o instanceof List) { - namesAndValues = (List) o; - } - } - // assign the upper and lower limits if any. - o = library.getObject(entries, LIMITS_KEY); - if (o != null && o instanceof List) { - List limits = (List) o; - if (limits.size() >= 2) { - lowerLimit = decryptIfText(limits.get(0)); - upperLimit = decryptIfText(limits.get(1)); - } - } - } - - public boolean isEmpty() { - return kidsNodes.size() == 0; - } - - public boolean hasLimits() { - return library.getObject(entries, LIMITS_KEY) != null; - } - - public List getNamesAndValues() { - return namesAndValues; - } - - public List getKidsReferences() { - return kidsReferences; - } - - public List getKidsNodes() { - return kidsNodes; - } - - public String getLowerLimit() { - return lowerLimit; - } - - public String getUpperLimit() { - return upperLimit; - } - - private void ensureNamesDecrypted() { - if (namesAreDecrypted) - return; - namesAreDecrypted = true; - // We need to look at each key and encrypt any Text objects which - // is every second object - for (int i = 0; i < namesAndValues.size(); i += 2) { - namesAndValues.set(i, - decryptIfText(namesAndValues.get(i))); - } - } - - /** - * Decyptes the node String object and returns a String value of the node - * which is used to find names in the name tree. We only do this once - * for the notes names vector. - * - * @param tmp object to decrypt. - * @return decrypted string. - */ - private String decryptIfText(Object tmp) { - if (tmp instanceof StringObject) { - StringObject nameText = (StringObject) tmp; - return nameText.getDecryptedLiteralString(library.getSecurityManager()); - } else if (tmp instanceof String) { - return (String) tmp; - } - return null; - } - - /** - * Search for the given name in the name tree. - * - * @param name name to search for - * @return retrieved object if any otherwise, null. - */ - Object searchName(String name) { - Object ret = search(name); - if (ret == NOT_FOUND || ret == NOT_FOUND_IS_LESSER || ret == NOT_FOUND_IS_GREATER) { - ret = null; - } - return ret; - } - - - private Object search(String name) { -//System.out.println("search() for: " + name + " lowerLimit: " + lowerLimit + " upperLimit: " + upperLimit + " " + name); - if (kidsReferences != null) { -//System.out.print("search() kids ... "); - if (lowerLimit != null) { - int cmp = lowerLimit.compareTo(name); - if (cmp > 0) { -//System.out.println("skLESSER"); - return NOT_FOUND_IS_LESSER; - } else if (cmp == 0) - return getNode(0).search(name); - } - if (upperLimit != null) { - int cmp = upperLimit.compareTo(name); - if (cmp < 0) { -//System.out.println("skGREATER"); - return NOT_FOUND_IS_GREATER; - } else if (cmp == 0) - return getNode(kidsReferences.size() - 1).search(name); - } -//System.out.println("skBETWEEN"); - - return binarySearchKids(0, kidsReferences.size() - 1, name); - } else if (namesAndValues != null) { -//System.out.print("search() names ... "); - int numNamesAndValues = namesAndValues.size(); - - if (lowerLimit != null) { - int cmp = lowerLimit.compareTo(name); - if (cmp > 0) { -//System.out.println("snLESSER"); - return NOT_FOUND_IS_LESSER; - } else if (cmp == 0) { - ensureNamesDecrypted(); - if (namesAndValues.get(0).equals(name)) { - Object ob = namesAndValues.get(1); - if (ob instanceof Reference) - ob = library.getObject((Reference) ob); - return ob; - } - } - } - if (upperLimit != null) { - int cmp = upperLimit.compareTo(name); - if (cmp < 0) { -//System.out.println("snGREATER"); - return NOT_FOUND_IS_GREATER; - } else if (cmp == 0) { - ensureNamesDecrypted(); - if (namesAndValues.get(numNamesAndValues - 2).equals(name)) { - Object ob = namesAndValues.get(numNamesAndValues - 1); - if (ob instanceof Reference) - ob = library.getObject((Reference) ob); - return ob; - } - } - } -//System.out.println("snBETWEEN"); - - ensureNamesDecrypted(); - Object ret = binarySearchNames(0, numNamesAndValues - 1, name); - if (ret == NOT_FOUND || ret == NOT_FOUND_IS_LESSER || ret == NOT_FOUND_IS_GREATER) - ret = null; - return ret; - } - return null; - } - - private Object binarySearchKids(int firstIndex, int lastIndex, String name) { - if (firstIndex > lastIndex) - return NOT_FOUND; - int pivot = firstIndex + ((lastIndex - firstIndex) / 2); - Object ret = getNode(pivot).search(name); -//System.out.print("binarySearchKids [ " + firstIndex + ", " + lastIndex + " ] pivot: " + pivot + " name: " + name + " ... "); - if (ret == NOT_FOUND_IS_LESSER) { -//System.out.println("kLESSER"); - return binarySearchKids(firstIndex, pivot - 1, name); - } else if (ret == NOT_FOUND_IS_GREATER) { -//System.out.println("kGREATER"); - return binarySearchKids(pivot + 1, lastIndex, name); - } else if (ret == NOT_FOUND) { -//System.out.println("kNOT FOUND"); - // This shouldn't happen, so is either a bug, or a miss coded PDF file - for (int i = firstIndex; i <= lastIndex; i++) { - if (i == pivot) - continue; - Object r = getNode(i).search(name); - if (r != NOT_FOUND && r != NOT_FOUND_IS_LESSER && r != NOT_FOUND_IS_GREATER) { - ret = r; - break; - } - } - } - return ret; - } - - private Object binarySearchNames(int firstIndex, int lastIndex, String name) { - if (firstIndex > lastIndex) - return NOT_FOUND; - int pivot = firstIndex + ((lastIndex - firstIndex) / 2); - pivot &= 0xFFFFFFFE; // Clear LSB to ensure even index -//System.out.print("binarySearchNames [ " + firstIndex + ", " + lastIndex + " ] pivot: " + pivot + " size: " + namesAndValues.size() + " compare " + name + " to " + namesAndValues.get(pivot).toString() + " ... "); - int cmp = namesAndValues.get(pivot).compareTo(name); - if (cmp == 0) { -//System.out.println("nEQUAL"); - Object ob = namesAndValues.get(pivot + 1); - if (ob instanceof Reference) - ob = library.getObject((Reference) ob); - return ob; - } else if (cmp > 0) { -//System.out.println("nLESSER"); - return binarySearchNames(firstIndex, pivot - 1, name); - } else if (cmp < 0) { -//System.out.println("nGREATER"); - return binarySearchNames(pivot + 2, lastIndex, name); - } - return NOT_FOUND; - } - - public NameNode getNode(int index) { - NameNode n = kidsNodes.get(index); - if (n == null) { - Reference r = (Reference) kidsReferences.get(index); - HashMap nh = (HashMap) library.getObject(r); - n = new NameNode(library, nh); - kidsNodes.set(index, n); - } - return n; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/NameTree.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/NameTree.java deleted file mode 100644 index daae5e4630..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/NameTree.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - *

The NameTree class is similar to the Dictionary class in that - * it associates keys and values, but it does this in a different way. The keys - * in a NameTree are strings and are ordered and the values of the associated - * keys may be an object of any type.

- *

- *

The NameTree class is primarily used to store named destinations - * accessible via the document's Catalog. This class is very simple with only - * one method which is responsible searching for the given key.

- * - * @since 1.0 - */ -public class NameTree extends Dictionary { - - // root node of the tree of names. - private NameNode root; - - /** - * Creates a new instance of a NameTree. - * - * @param l document library. - * @param h NameTree dictionary entries. - */ - public NameTree(Library l, HashMap h) { - super(l, h); - } - - /** - * Initiate the NameTree. - */ - public void init() { - if (inited) { - return; - } - root = new NameNode(library, entries); - inited = true; - } - - /** - * Depth fist traversal of the the tree returning a list of the name and - * reference values of the leafs in the tree. - * - * @return list of all name and corresponding references. - */ - public List getNamesAndValues() { - if (root != null) { - ArrayList namesAndValues = new ArrayList(); - // single root, just return the list. - if (root.getNamesAndValues() != null) { - namesAndValues.addAll(root.getNamesAndValues()); - return namesAndValues; - } - // depth first traversal to get the names leaves off the kits. - else if (root.getKidsNodes() != null) { - for (NameNode node : root.getKidsNodes()) { - namesAndValues.addAll(getNamesAndValues(node)); - } - return namesAndValues; - } - } - return null; - } - - /** - * Helper method to do the recursive dive to get all the names and values - * from the tree. - * - * @param nameNode Name node to check for names and nodes. - * @return found names and values for the given node. - */ - private List getNamesAndValues(NameNode nameNode) { - // leaf node. - if (nameNode.getNamesAndValues() != null) { - return nameNode.getNamesAndValues(); - } - // intermediary node. - else { - ArrayList namesAndValues = new ArrayList (); - for (NameNode node : nameNode.getKidsNodes()) { - namesAndValues.addAll(getNamesAndValues(node)); - } - return namesAndValues; - } - } - - /** - * Searches for the given key in the name tree. If the key is found, its - * associated object is returned. It is important to know the context in - * which a search is made as the name tree can hold objects of any type. - * - * @param key key to look up in name tree. - * @return the associated object value if found; null, otherwise. - */ - public Object searchName(String key) { - return root.searchName(key); - } - - public NameNode getRoot() { - return root; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/NamedDestinations.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/NamedDestinations.java deleted file mode 100644 index 9f6c65be47..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/NamedDestinations.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * Instead of being defined directly with the explicit syntax a destination may - * be referred to indirectly by means of a name object (PDF 1.1) or a byte - * string (PDF 1.2). This capability is especially useful when the destination - * is located in another PDF document. - *

- * In PDF 1.1, the correspondence between name objects and destinations shall be - * defined by the Dests entry in the document catalogue (see 7.7.2, “Document Catalogâ€). - * The value of this entry shall be a dictionary in which each key is a destination - * name and the corresponding value is either an array defining the destination - * - * @since 5.2.0 - */ -public class NamedDestinations extends Dictionary { - - public NamedDestinations(Library library, HashMap entries) { - super(library, entries); - } - - /** - * Gets a Destination object for the given Name. If now corresponding - * Destination value if found null is returned. - * - * @param name Name to looking up in NamedDestinations list. - * @return Destination for the given name, null otherwise. - */ - public Destination getDestination(Name name) { - Object tmp = entries.get(name); - if (tmp != null && tmp instanceof ArrayList) { - return new Destination(library, tmp); - } - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Names.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Names.java deleted file mode 100644 index ac6a2b8a00..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Names.java +++ /dev/null @@ -1,164 +0,0 @@ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * Some categories of objects in a PDF file can be referred to by name rather - * than by object reference. The correspondence between names and objects is - * established by the document’s name dictionary (PDF 1.2), located by means of - * the Names entry in the document’s catalog (see 7.7.2, "Document Catalog"). - * Each entry in this dictionary designates the root of a name tree (see 7.9.6, - * "Name Trees") defining names for a particular category of objects. - * - * @since 5.1.0 - */ -public class Names extends Dictionary { - - private static final Logger logger = - Logger.getLogger(Names.class.toString()); - - /** - * A name tree mapping name strings to destinations. - */ - public static final Name DEST_KEY = new Name("Dests"); - /** - * A name tree mapping name strings to annotation appearance streams. - */ - public static final Name ANNOTATION_APPEARANCE_KEY = new Name("AP"); - /** - * A name tree mapping name strings to document-level JavaScript actions. - */ - public static final Name JAVASCRIPT_KEY = new Name("JavaScript"); - /** - * A name tree mapping name strings to visible pages for use in interactive - * forms. - */ - public static final Name PAGES_KEY = new Name("Pages"); - /** - * A name tree mapping name strings to invisible (template) pages for use - * in interactive forms. - */ - public static final Name TEMPLATES_KEY = new Name("Templates"); - /** - * A name tree mapping digital identifiers to Web Capture content sets. - */ - public static final Name IDS_KEY = new Name("IDS"); - /** - * A name tree mapping name strings to file specifications for embedded - * file streams. - */ - public static final Name EMBEDDED_FILES_KEY = new Name("EmbeddedFiles"); - /** - * A name tree mapping name strings to alternate presentations. - */ - public static final Name ALTERNATE_PRESENTATIONS_KEY = new Name("AlternatePresentations"); - /** - * A name tree mapping name strings (which shall have Unicode encoding) to - * rendition objects. - */ - public static final Name RENDITIONS_KEY = new Name("Renditions"); - - private NameTree destsNameTree; - private NameTree javaScriptNameTree; - private NameTree pagesNameTree; - private NameTree templatesNameTree; - private NameTree idsNameTree; - private NameTree embeddedFilesNameTree; - private NameTree alternatePresentationsNameTree; - private NameTree renditionsNameTree; - private NameTree annotationAppearanceNameTree; - - public Names(Library l, HashMap h) { - super(l, h); - - if (!inited) { - // destinations - Object tmp = library.getObject(entries, DEST_KEY); - if (tmp != null && tmp instanceof HashMap) { - destsNameTree = new NameTree(library, (HashMap) tmp); - destsNameTree.init(); - } - // Javascript - tmp = library.getObject(entries, JAVASCRIPT_KEY); - if (tmp != null && tmp instanceof HashMap) { - javaScriptNameTree = new NameTree(library, (HashMap) tmp); - javaScriptNameTree.init(); - } - // Pages - tmp = library.getObject(entries, PAGES_KEY); - if (tmp != null && tmp instanceof HashMap) { - pagesNameTree = new NameTree(library, (HashMap) tmp); - pagesNameTree.init(); - } - // templates - tmp = library.getObject(entries, TEMPLATES_KEY); - if (tmp != null && tmp instanceof HashMap) { - templatesNameTree = new NameTree(library, (HashMap) tmp); - templatesNameTree.init(); - } - // ID's - tmp = library.getObject(entries, IDS_KEY); - if (tmp != null && tmp instanceof HashMap) { - idsNameTree = new NameTree(library, (HashMap) tmp); - idsNameTree.init(); - } - // embedded files - tmp = library.getObject(entries, EMBEDDED_FILES_KEY); - if (tmp != null && tmp instanceof HashMap) { - embeddedFilesNameTree = new NameTree(library, (HashMap) tmp); - embeddedFilesNameTree.init(); - } - // alternative presentation - tmp = library.getObject(entries, ALTERNATE_PRESENTATIONS_KEY); - if (tmp != null && tmp instanceof HashMap) { - alternatePresentationsNameTree = new NameTree(library, (HashMap) tmp); - alternatePresentationsNameTree.init(); - } - // renditions - tmp = library.getObject(entries, RENDITIONS_KEY); - if (tmp != null && tmp instanceof HashMap) { - renditionsNameTree = new NameTree(library, (HashMap) tmp); - renditionsNameTree.init(); - } - } - } - - public NameTree getDestsNameTree() { - return destsNameTree; - } - - public NameTree getAnnotationAppearanceNameTree() { - return annotationAppearanceNameTree; - } - - public NameTree getJavaScriptNameTree() { - return javaScriptNameTree; - } - - public NameTree getPagesNameTree() { - return pagesNameTree; - } - - public NameTree getTemplatesNameTree() { - return templatesNameTree; - } - - public NameTree getIdsNameTree() { - return idsNameTree; - } - - public NameTree getEmbeddedFilesNameTree() { - return embeddedFilesNameTree; - } - - public NameTree getAlternatePresentationsNameTree() { - return alternatePresentationsNameTree; - } - - public NameTree getRenditionsNameTree() { - return renditionsNameTree; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ObjectStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ObjectStream.java deleted file mode 100644 index 2932c73552..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ObjectStream.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.io.SeekableByteArrayInputStream; -import org.icepdf.core.io.SeekableInput; -import org.icepdf.core.io.SeekableInputConstrainedWrapper; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Parser; - -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - - -/** - * @author Mark Collette - * @since 2.0 - */ -public class ObjectStream extends Stream { - - private static final Logger logger = - Logger.getLogger(Form.class.toString()); - - public static final Name N_KEY = new Name("N"); - public static final Name FIRST_KEY = new Name("First"); - - private boolean init; - private SeekableInput decodedStream; - private int[] objectNumbers; - private long[] objectOffset; - - /** - * Create a new instance of a Stream. - * - * @param l library containing a hash of all document objects - * @param h HashMap of parameters specific to the Stream object. - * @param streamInputWrapper Accessor to stream byte data - */ - public ObjectStream(Library l, HashMap h, SeekableInputConstrainedWrapper streamInputWrapper) { - super(l, h, streamInputWrapper); - } - - public synchronized void init() { - if (init) - return; - init = true; - int numObjects = library.getInt(entries, N_KEY); - long firstObjectsOffset = library.getLong(entries, FIRST_KEY); - // get the stream data - decodedStream = new SeekableByteArrayInputStream(getDecodedStreamBytes(0)); -// decodedStream.beginThreadAccess(); - objectNumbers = new int[numObjects]; - objectOffset = new long[numObjects]; - try { - Parser parser = new Parser(decodedStream); - for (int i = 0; i < numObjects; i++) { - objectNumbers[i] = parser.getIntSurroundedByWhitespace(); - objectOffset[i] = parser.getLongSurroundedByWhitespace() + firstObjectsOffset; - } - } catch (Exception e) { - logger.log(Level.SEVERE, - "Error loading object stream instance: ", e); - } -// finally { -// decodedStream.endThreadAccess(); -// } - - } - - public Object loadObject(Library library, int objectIndex) { -//System.out.println("ObjectStream.loadObject() objectIndex: " + objectIndex); - init(); - if (objectNumbers == null || - objectOffset == null || - objectNumbers.length != objectOffset.length || - objectIndex < 0 || - objectIndex >= objectNumbers.length) { -//System.out.println("ObjectStream.loadObject() init failed"); - return null; - } - - try { - int objectNumber = objectNumbers[objectIndex]; - long position = objectOffset[objectIndex]; -//System.out.println("ObjectStream.loadObject() objectNumber: " + objectNumber + ", position: " + position); - decodedStream.beginThreadAccess(); - decodedStream.seekAbsolute(position); - Parser parser = new Parser(decodedStream, Parser.PARSE_MODE_OBJECT_STREAM); - // Parser.getObject() either does 1 of 3 things: - // 1. Gets a core object (Dictionary or Stream), adds it to Library - // by object Reference, returns PObject - // 2. Gets a non-core-object, leaves it on stack, returns null - // 3. Gets a non-core-object, returns it - Object ob = parser.getObject(library); - if (ob == null) { - Reference ref = new Reference(objectNumber, 0); - PObject pObject = parser.addPObject(library, ref); - ob = pObject.getObject(); - } else if (!(ob instanceof PObject)) { - Reference ref = new Reference(objectNumber, 0); - library.addObject(ob, ref); - } - // assign object reference, needed for encrypting and state saving - if (ob != null && ob instanceof Dictionary) { - ((Dictionary) ob).setPObjectReference( - new Reference(objectNumber, 0)); - } - -//System.out.println("ObjectStream.loadObject() ob: " + ob + ", ob.class: " + ob.getClass().getName()); - return ob; - } catch (Exception e) { - logger.log(Level.FINE, "Error loading PDF object.", e); - return null; - } finally { - decodedStream.endThreadAccess(); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContent.java deleted file mode 100644 index 9a8bbf078b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContent.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.util.*; - -/** - * The optional OCProperties entry in the document catalog - * (see 7.7.2, "Document Catalog") shall contain, when present, the optional - * content properties dictionary, which contains a list of all the optional - * content groups in the document, as well as information about the default - * and alternate configurations for optional content. This dictionary shall be - * present if the file contains any optional content; if it is missing, a - * conforming reader shall ignore any optional content structures in the document. - * - * @since 5.0 - */ -public class OptionalContent extends Dictionary { - - private Map groups; - - public static final Name OCGs_KEY = new Name("OCGs"); - public static final Name OC_KEY = new Name("OC"); - public static final Name D_KEY = new Name("D"); - public static final Name BASE_STATE_KEY = new Name("BaseState"); - public static final Name INTENT_KEY = new Name("Intent"); - public static final Name AS_KEY = new Name("AS"); - public static final Name ORDER_KEY = new Name("Order"); - public static final Name LIST_MODE_KEY = new Name("ListMode"); - public static final Name RBGROUPS_KEY = new Name("RBGroups"); - public static final Name LOCKED_KEY = new Name("Locked"); - public static final Name OFF_VALUE = new Name("OFF"); - public static final Name ON_vALUE = new Name("ON"); - public static final Name UNCHANGED_KEY = new Name("Unchanged"); - public static final Name VIEW_VALUE = new Name("View"); - public static final Name DESIGN_VALUE = new Name("Design"); - public static final Name NONE_OC_FLAG = new Name("marked"); - private Name baseState = ON_vALUE; - - /** - * A single intent name or an array containing any combination of names. it - * shall be used to determine which optional content groups’ states to consider - * and which to ignore in calculating the visibility of content - * (see 8.11.2.3, "Intent"). - *

- * PDF defines two intent names, View and Design. In addition, the name All - * shall indicate the set of all intents, including those not yet defined. - * Default value: View. The value shall be View for the document’s default configuration. - */ - private List intent = Arrays.asList(VIEW_VALUE); - - - /** - * An array specifying the order for presentation of optional content groups - * in a conforming reader’s user interface. The array elements may include - * the following objects: - *

- * Optional content group dictionaries, whose Name entry shall be displayed in - * the user interface by the conforming reader. - *

- * Arrays of optional content groups which may be displayed by a conforming - * reader in a tree or outline structure. Each nested array may optionally - * have as its first element a text string to be used as a non-selectable - * label in a conforming reader’s user interface. - *

- * Text labels in nested arrays shall be used to present collections of - * related optional content groups, and not to communicate actual nesting of - * content inside multiple layers of groups (see EXAMPLE 1 in 8.11.4.3, - * "Optional Content Configuration Dictionaries"). To reflect actual nesting - * of groups in the content, such as for layers with sublayers, nested arrays - * of groups without a text label shall be used (see EXAMPLE 2 in 8.11.4.3, - * "Optional Content Configuration Dictionaries"). - *

- * An empty array [] explicitly specifies that no groups shall be presented. - * In the default configuration dictionary, the default value shall be an empty - * array; in other configuration dictionaries, the default shall be the Order - * value from the default configuration dictionary. - *

- * Any groups not listed in this array shall not be presented in any user - * interface that uses the configuration. - */ - private List order; - - private List rbGroups; - - // object was created but the PDF doesn't actually have optional content definition and optional content - // properties may no longer be valid. - private boolean emptyDefinition; - - public OptionalContent(Library l, HashMap h) { - super(l, h); - groups = new HashMap(); - } - - @Override - @SuppressWarnings("unchecked") - public void init() { - if (inited) { - return; - } - // test of a valid definition. - if (entries == null || entries.size() == 0){ - emptyDefinition = true; - } - - // build out the optionContentGroups from the OCGs array, array should always - // be indirect references to the optionContentGroups. - Object ogcs = library.getObject(entries, OCGs_KEY); - if (ogcs instanceof List) { - List ogcList = (List) ogcs; - Reference ref; - Object ocgObj; - for (Object object : ogcList) { - if (object instanceof Reference) { - ref = (Reference) object; - ocgObj = library.getObject(ref); - if (ocgObj instanceof OptionalContentGroup) { - OptionalContentGroup ogc = (OptionalContentGroup) ocgObj; - groups.put(ref, ogc); - } - } - } - } - - // The default viewing optional content configuration dictionary. - Object dObj = library.getObject(entries, D_KEY); - if (dObj instanceof HashMap) { - HashMap configurationDictionary = (HashMap) dObj; - - // apply the base state ON|OFF|Unchanged - Object tmp = library.getName(configurationDictionary, BASE_STATE_KEY); - if (tmp != null && tmp instanceof Name) { - baseState = (Name) tmp; - } - - // If the BaseState entry is ON, then we only need to look at the OFF - // entries. - boolean isBaseOn = baseState.equals(ON_vALUE); - List toggle; - if (isBaseOn) { - toggle = library.getArray(configurationDictionary, OFF_VALUE); - } - // If the BaseState entry is OFF, then the ON entries are relevant. - else { - toggle = library.getArray(configurationDictionary, ON_vALUE); - } - // build out the - if (toggle != null) { - for (Object obj : toggle) { - OptionalContentGroup ocg = groups.get(obj); - if (ocg != null) { - if (isBaseOn) { - // remove the off entries - ocg.setVisible(false); - } else { - // otherwise we add the on entries. - ocg.setVisible(true); - } - } - } - } - // check for an intent entry - tmp = library.getName(configurationDictionary, INTENT_KEY); - if (tmp != null) { - if (tmp instanceof Name) { - intent = Arrays.asList(new Name[]{(Name) tmp}); - } else if (tmp instanceof List) { - intent = (List) tmp; - } - } - // ignore AS for now. - /** - * An array of usage application dictionaries (see Table 103) - * specifying which usage dictionary categories (see Table 102) - * shall be consulted by conforming readers to automatically set the - * states of optional content groups based on external factors, - * such as the current system language or viewing magnification, - * and when they shall be applied.Order - */ - - // get the ordering information used by the UI. resolve the ref - // - tmp = library.getObject(configurationDictionary, ORDER_KEY); - if (tmp != null && tmp instanceof List) { - List orderedOCs = (List) tmp; - if (orderedOCs.size() > 0) { - order = new ArrayList(orderedOCs.size()); - order = parseOrderArray(orderedOCs, null); - } - } - - // get the radio button group data for correct UI behavior . - tmp = library.getObject(configurationDictionary, RBGROUPS_KEY); - if (tmp != null && tmp instanceof List) { - List orderedOCs = (List) tmp; - if (orderedOCs.size() > 0) { - rbGroups = new ArrayList(orderedOCs.size()); - rbGroups = parseOrderArray(orderedOCs, null); - } - } - - // ignore Locked for now - } - inited = true; - } - - @SuppressWarnings("unchecked") - private List parseOrderArray(List rawOrder, OptionalContentGroup parent) { - List order = new ArrayList(5); - OptionalContentGroup group = null; - for (Object obj : rawOrder) { - if (obj instanceof Reference) { - Object refObject = getOCGs((Reference) obj); - if (refObject != null) { - group = (OptionalContentGroup) refObject; - if (parent != null && !parent.isVisible()) { - group.setVisible(false); - } - order.add(group); - } else { - obj = library.getObject((Reference) obj); - } - } - if (obj instanceof List) { - parent = group; - order.add(parseOrderArray((List) obj, parent)); - } else if (obj instanceof StringObject) { - order.add(Utils.convertStringObject(library, (StringObject) obj)); - } - } - return order; - } - - public boolean isVisible(Reference ocgRef) { - Object object = library.getObject(ocgRef); - if (object instanceof OptionalContentGroup) { - return isVisible((OptionalContentGroup) object); - } else if (object instanceof OptionalContentMembership) { - return isVisible((OptionalContentMembership) object); - } - return false; - } - - public boolean isVisible(OptionalContentGroup ocg) { - return groups.containsKey(ocg.getPObjectReference()); - } - - public boolean isVisible(OptionalContentMembership ocmd) { - ocmd.init(); - return ocmd.isVisible(); - } - - /** - * Test if an xForm object image or content is visible. - * - * @param object content to check visibility. - * @return optional content groups currently visibility state, returns - * true if no state can be found, better to show then to - * hide by default. - */ - public boolean isVisible(Object object) { - if (object instanceof Reference) { - return isVisible((Reference) object); - } else if (object instanceof OptionalContentGroup) { - return isVisible((OptionalContentGroup) object); - } else if (object instanceof OptionalContentMembership) { - return isVisible((OptionalContentMembership) object); - } - return true; - } - - public List getOrder() { - return order; - } - - public List getIntent() { - return intent; - } - - public int getGroupsSize() { - return groups.size(); - } - - public List getRbGroups() { - return rbGroups; - } - - public OptionalContentGroup getOCGs(Reference reference) { - return groups.get(reference); - } - - public boolean isEmptyDefinition() { - return emptyDefinition; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContentGroup.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContentGroup.java deleted file mode 100644 index 0382c87cb4..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContentGroup.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.util.HashMap; - -/** - * An optional content group is a dictionary representing a collection of graphics - * that can be made visible or invisible dynamically by users of conforming - * readers. The graphics belonging to such a group may reside anywhere in the - * document: they need not be consecutive in drawing order, nor even belong to - * the same content stream. - * - * @since 5.0 - */ -public class OptionalContentGroup extends Dictionary implements OptionalContents { - - public static final Name TYPE = new Name("OCG"); - public static final Name NAME_KEY = new Name("Name"); - public static final Name USAGE_KEY = new Name("Usage"); - - /** - * The name of the optional content group, suitable for presentation in a - * reader’s user interface. - */ - private String name; - - /** - * A usage dictionary describing the nature of the content controlled by the - * group. It may be used by features that automatically control the state of - * the group based on outside factors. See 8.11.4.4, "Usage and Usage - * Application Dictionaries" for more information - */ - private HashMap usage; - - /** - * Indicates if this content groups and its child shapes should be displayed. - * All OCG's are enabled by default. - */ - private boolean visible = true; - private boolean isOCG; - - public OptionalContentGroup(String name, boolean visible) { - super(null, null); - this.name = name; - this.visible = visible; - } - - public OptionalContentGroup(Library library, HashMap entries) { - super(library, entries); - // build from Parser - isOCG = true; - } - - public boolean isOCG() { - return isOCG; - } - - public String getName() { - if (name == null) { - name = Utils.convertStringObject(library, - (StringObject) library.getObject(entries, NAME_KEY)); - } - return name; - } - - public HashMap getUsage() { - if (usage == null) { - usage = library.getDictionary(entries, USAGE_KEY); - } - return usage; - } - - public boolean isVisible() { - return visible; - } - - public void setVisible(boolean visible) { - this.visible = visible; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContentMembership.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContentMembership.java deleted file mode 100644 index dac97e853a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContentMembership.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * As mentioned above, content may belong to a single optional content group and - * shall be visible when the group is ON and invisible when it is OFF. To express - * more complex visibility policies, content shall not declare itself to belong - * directly to an optional content group but rather to an optional content - * membership dictionary. - *

- * Note: currently no support for the visibility expression (VE) array. - * - * @since 5.0 - */ -public class OptionalContentMembership extends Dictionary implements OptionalContents { - - public static final Name TYPE = new Name("OCMD"); - - public static final Name OCGs_KEY = new Name("OCGs"); - public static final Name P_KEY = new Name("P"); - public static final Name VE_KEY = new Name("VE"); - public static final Name ALL_ON_KEY = new Name("AllOn"); - public static final Name ALL_OFF_KEY = new Name("AllOff"); - public static final Name ANY_ON_KEY = new Name("AnyOn"); - public static final Name ANY_OFF_KEY = new Name("AnyOff"); - - /** - * A name specifying the visibility policy for content belonging to this - * membership dictionary. Valid values shall be: - *

    - *
  • AllOn - visible only if all of the entries in OCGs are ON - *
  • AnyOn - visible if any of the entries in OCGs are ON - *
  • AnyOff - visible if any of the entries in OCGs are OFF - *
  • AllOff - visible only if all of the entries in OCGs are OFF - *
- * Default value: AnyOn - */ - private VisibilityPolicy policy; - - /** - * A dictionary or array of dictionaries specifying the optional content - * groups whose states shall determine the visibility of content controlled - * by this membership dictionary. - * Null values or references to deleted objects shall be ignored. If this - * entry is not present, is an empty array, or contains references only to - * null or deleted objects, the membership dictionary shall have no effect - * on the visibility of any content. - */ - private List ocgs = new ArrayList(); - - /** - * An array specifying a visibility expression, used to compute visibility - * of content based on a set of optional content groups - */ - private List visibilityExpression; - - public OptionalContentMembership(Library library, HashMap entries) { - super(library, entries); - } - - @Override - public void init() { - if (inited) { - return; - } - // build out the OCG entries. - Object ocgObj = library.getObject(entries, OCGs_KEY); - if (ocgObj instanceof OptionalContentGroup) { - ocgs.add((OptionalContentGroup) ocgObj); - } else if (ocgObj instanceof List) { - List ocgList = (List) ocgObj; - for (Object object : ocgList) { - Object ocg = library.getObject(object); - if (ocg instanceof OptionalContentGroup) { - ocgs.add((OptionalContentGroup) ocg); - } - } - } - policy = VisibilityPolicy.getPolicy(library.getName(entries, P_KEY)); - - inited = true; - } - - public boolean isOCG() { - return true; - } - - public VisibilityPolicy getPolicy() { - return policy; - } - - public List getOcgs() { - return ocgs; - } - - public boolean isVisible() { - return policy.isVisible(ocgs); - } - - public static enum VisibilityPolicy { - ALL_ON { - @Override - boolean isVisible(List ocgs) { - for (OptionalContentGroup ocg : ocgs) { - if (!ocg.isVisible()) { - return false; - } - } - return true; - } - }, - ANY_ON { - @Override - boolean isVisible(List ocgs) { - for (OptionalContentGroup ocg : ocgs) { - if (ocg.isVisible()) { - return true; - } - } - return false; - } - }, - ANY_OFF { - @Override - boolean isVisible(List ocgs) { - for (OptionalContentGroup ocg : ocgs) { - if (!ocg.isVisible()) { - return true; - } - } - return false; - } - }, - ALL_OFF { - @Override - boolean isVisible(List ocgs) { - for (OptionalContentGroup ocg : ocgs) { - if (ocg.isVisible()) { - return false; - } - } - return true; - } - }; - - public static VisibilityPolicy getPolicy(Name p) { - if (ALL_ON_KEY.equals(p)) { - return ALL_ON; - } else if (ALL_OFF_KEY.equals(p)) { - return ALL_OFF; - } else if (ANY_ON_KEY.equals(p)) { - return ANY_ON; - } else if (ANY_OFF_KEY.equals(p)) { - return ANY_OFF; - } else if (ANY_OFF_KEY.equals(p)) { - return ALL_OFF; - } else { - return ANY_ON; - } - } - - abstract boolean isVisible(List ocgs); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContents.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContents.java deleted file mode 100644 index 05adf81d77..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OptionalContents.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -/** - * Common visibility definition for renderable optional content. - * - * @since 5.0 - */ -public interface OptionalContents { - - public boolean isVisible(); - - public boolean isOCG(); - - public void init() throws InterruptedException; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OutlineItem.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OutlineItem.java deleted file mode 100644 index fbb7e4cece..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/OutlineItem.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.actions.Action; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - *

The OutlineItem represents the individual outline item within - * the hierarchy defined by an Outlines class. The outlines items - * are chained together through their Prev and Next entries. Each - * outline item has a title and a destination which can be accessed by the - * visual representation to create a function document outlines (sometimes - * called bookmarks).

- *

- *

This class is used mainly by the Outlines class to build the outline - * hierarchy. The root node of the outline hierarchy can be accessed through - * the Outlines class.

- * - * @see org.icepdf.ri.common.utility.outline.OutlineItemTreeNode - * @see org.icepdf.core.pobjects.Outlines - * @since 2.0 - */ -public class OutlineItem extends Dictionary { - - public static final Name A_KEY = new Name("A"); - public static final Name COUNT_KEY = new Name("Count"); - public static final Name TITLE_KEY = new Name("Title"); - public static final Name DEST_KEY = new Name("Dest"); - public static final Name FIRST_KEY = new Name("First"); - public static final Name LAST_KEY = new Name("Last"); - public static final Name NEXT_KEY = new Name("Next"); - public static final Name PREV_KEY = new Name("Prev"); - public static final Name PARENT_KEY = new Name("Parent"); - - // The text to be displayed on the screen for this item. - private String title; - - // The destination to be displayed when this item is activated - private Destination dest; - - // The action to be performed when this item is activated - private Action action; - - // The parent of this item in the outline hierarchy. The parent of a - // top-level item is the outline dictionary itself. - private Reference parent; - - // The previous item at this outline level. - private Reference prev; - - // The next item at this outline level. - private Reference next; - - // An outline item dictionary representing the first top-level item - // in the outline. - private Reference first; - - // An outline item dictionary representing the last top-level item - // in the outline. - private Reference last; - - // The total number of open items at all levels of the outline. This - // entry should be omitted if there are no open outline items. - private int count = -1; - - private boolean loadedSubItems; - - private List subItems; - - - /** - * Creates a new instance of an OutlineItem. - * - * @param l document library. - * @param h OutlineItem dictionary entries. - */ - public OutlineItem(Library l, HashMap h) { - super(l, h); - loadedSubItems = false; - subItems = new ArrayList(Math.max(Math.abs(getCount()), 16)); - } - - /** - * Indicates if the Outline item is empty. An outline item is empty if - * it has no title, destination and action dictionary entries. - * - * @return true, if the outline entry is empty; false, otherwise. - */ - public boolean isEmpty() { - return getTitle() == null && getDest() == null && getAction() == null; - } - - /** - * Gets the number of descendants that would appear under this outline item. - * - * @return descendant count. - */ - public int getSubItemCount() { - ensureSubItemsLoaded(); - if (subItems != null) - return subItems.size(); - else - return 0; - } - - /** - * Gets the child outline item specified by the index. All children of the - * outline items are ordered and numbered. - * - * @param index child index number of desired outline item. - * @return outline specified by index. - */ - public OutlineItem getSubItem(int index) { - ensureSubItemsLoaded(); - return subItems.get(index); - } - - /** - * Gets the action associated with this OutlineItem. - * - * @return the associated action; null, if there is no action. - */ - public Action getAction() { - // grab the action attribute - if (action == null) { - Object obj = library.getObject(entries, A_KEY); - if (obj instanceof HashMap) { - action = new org.icepdf.core.pobjects.actions.Action(library, (HashMap) obj); - } - } - return action; - } - - /** - * Gets a reference to an outline item dictionary representing the first - * top-level item in the outline. - * - * @return reference to first top-level item - */ - public Reference getFirst() { - if (first == null) { - Object attribute = entries.get(FIRST_KEY); - if (attribute instanceof Reference) { - first = (Reference) attribute; - } - } - return first; - } - - /** - * Gets a reference to an outline item dictionary representing the last - * top-level item in the outline. - * - * @return reference to last top-level item - */ - public Reference getLast() { - if (last == null) { - Object attribute = entries.get(LAST_KEY); - if (attribute instanceof Reference) { - last = (Reference) attribute; - } - } - return last; - } - - /** - * Gets the next outline item at this outline level. - * - * @return next item at this outline level. - */ - public Reference getNext() { - if (next == null) { - Object attribute = entries.get(NEXT_KEY); - if (attribute instanceof Reference) { - next = (Reference) attribute; - } - } - return next; - } - - /** - * Gets the previous outline item at this outline level. - * - * @return previous item at this outline level. - */ - public Reference getPrev() { - if (prev == null) { - Object attribute = entries.get(PREV_KEY); - if (attribute instanceof Reference) { - prev = (Reference) attribute; - } - } - return prev; - } - - /** - * Gets the parent of this outline item in the outline hierarchy. The - * parent of a top-level item is the outline dictionary itself. - * - * @return parent of this item. - */ - public Reference getParent() { - if (parent == null) { - Object attribute = entries.get(PARENT_KEY); - if (attribute instanceof Reference) { - parent = (Reference) attribute; - } - } - return parent; - } - - /** - * Gets the number of descendants that would appear under this outline item. - * - * @return descendant count. - */ - private int getCount() { - if (count < 0) { - // grab the count attribute - count = library.getInt(entries, COUNT_KEY); - } - return count; - } - - /** - * Gets the text to be displayed on the screen for this item. - * - * @return text to be displayed - */ - public String getTitle() { - if (title == null) { - // get title String for outline entry - Object obj = library.getObject(entries, TITLE_KEY); - if (obj instanceof StringObject) { - title = Utils.convertStringObject(library, (StringObject) obj); - } - } - return title; - } - - /** - * Gets the destination to be displayed when this item is activated. - * - * @return destination to be displayed. - */ - public Destination getDest() { - if (dest == null) { - // grab the Destination attribute - Object obj = library.getObject(entries, DEST_KEY); - if (obj != null) { - dest = new Destination(library, obj); - } - } - return dest; - } - - /** - * Utility method for loading all children of this outline. The main purpose - * of this is to make sure the count is accurate. - */ - private void ensureSubItemsLoaded() { - if (loadedSubItems) - return; - - loadedSubItems = true; - - if (getFirst() != null) { - // get first child - Reference nextReference = getFirst(); - Reference oldNextReference; - OutlineItem outLineItem; - HashMap dictionary; - Object tmp; - // iterate through children and see if then have children. - while (nextReference != null) { - // result the outline dictionary - tmp = library.getObject(nextReference); - if (tmp == null || !(tmp instanceof HashMap)) { - break; - } else { - dictionary = (HashMap) tmp; - } - // create the new outline - outLineItem = new OutlineItem(library, dictionary); - - // add the new item to the list of children - subItems.add(outLineItem); - - // old reference is kept to make sure we don't iterate out - // of control on a circular reference. - oldNextReference = nextReference; - nextReference = outLineItem.getNext(); - - // make sure we haven't already added this node, some - // Outlines terminate with next being a pointer to itself. - if (oldNextReference.equals(nextReference)) { - break; - } - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Outlines.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Outlines.java deleted file mode 100644 index dd3647170f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Outlines.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - *

This class represents a PDF document outline. A document outline is - * an optional component of a PDF document and is accessible from the document's - * Catalog. The outline consists of a tree-structured hierarchy of outline items - * (sometimes called bookmarks) which can be used to display a documents - * structure to the user.

- *

- *

The outlines class does not build a visible structure; it only represents the - * non-visual structure of the outline. The OutlineItemTreeNode available in - * the packageorg.icepdf.core.ri.common provides an example on converting - * this hierarchy to a Swing JTree.

- * - * @see org.icepdf.ri.common.utility.outline.OutlineItemTreeNode - * @see org.icepdf.core.pobjects.OutlineItem - * @since 1.0 - */ -public class Outlines extends Dictionary { - - public static final Name D_KEY = new Name("D"); - public static final Name COUNT_KEY = new Name("Count"); - - // number of child outline items - private Integer count; - - // needed for future dispose implementation. - //private OutlineItem rootOutlineItem; - - /** - * Creates a new instance of Outlines. - * - * @param l document library. - * @param h Outlines dictionary entries. - */ - public Outlines(Library l, HashMap h) { - super(l, h); - if (entries != null) { - count = library.getInt(entries, COUNT_KEY); - } - } - - /** - * Gets the root OutlineItem. The root outline item can be traversed to build - * a visible outline of the hierarchy. - * - * @return root outline item. - */ - public OutlineItem getRootOutlineItem() { - if (count == null) - return null; - return new OutlineItem(library, entries); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PDate.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PDate.java deleted file mode 100644 index 4504546793..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PDate.java +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.security.SecurityManager; - -import java.text.SimpleDateFormat; -import java.util.*; - -/** - *

This class defines a standard PDF date. The class will try its best - * to parse the date format into its component parts. If a date cannot - * be parsed, a non-standard flag is set to true. In this instance, any - * of the data accessor methods will return the unparsed string.

- *

- *

PDF defines a standard date format, which closely follows that of the - * international standard ASN.1 (Abstract Syntax Notation One), defined in - * ISO/IEC 8824. A date is a string of the form (D:YYYYMMDDHHmmSSOHH'mm') - * where: - *

    - *
  • YYYY is the year
  • - *
  • MM is the month
  • - *
  • DD is the day (01-31)
  • - *
  • HH is the hour (00-23)
  • - *
  • mm is the minute (00-59)
  • - *
  • SS is the second (00-59)
  • - *
  • O is the relationship of local time to Universal Time (UT), denoted by - * one of the characters +, ?, or Z (see below)
  • - *
  • HH followed by ' is the absolute value of the offset from UT in hours - * (00-23)mm followed by ' is the absolute value of the offset from UT - * in minutes (00-59)
  • - *
- *

- *

The apostrophe character (') after HH and mm is part of the syntax. All - * fields after the year are optional. (The prefix D:, although also optional, - * is strongly recommended.) The default values for MM and DD are both 01; all - * other numerical fields default to zero values. A plus sign (+) as the value - * of the O field signifies that local time is later than UT, a minus sign (-) - * that local time is earlier than UT, and the letter Z that local time is equal - * to UT. If no UT information is specified, the relationship of the specified - * time to UT is considered to be unknown. Whether or not the time zone is - * known, the rest of the date should be specified in local time. For example, - * December 23, 1998, at 7:52 PM, U.S. Pacific Standard Time, is represented by - * the string D:199812231952?08'00'

- * - * @since 1.1 - */ -public class PDate { - - protected static final SimpleDateFormat DATE_FORMAT; - - static { - DATE_FORMAT = new SimpleDateFormat("'D:'yyyyMMddHHmmss"); - DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - // offset value for year, YYYY - private static final int OFFSET_YYYY = 4; - // offset value for month, MM - private static final int OFFSET_MM = 2; - // offset value for day, DD - private static final int OFFSET_DD = 2; - // offset value for hour, HH - private static final int OFFSET_HH = 2; - // offset value for minute, mm - private static final int OFFSET_mm = 2; - // offset value for second, SS - private static final int OFFSET_SS = 2; - // offset value for east or west of GMT, 0 - private static final int OFFSET_0 = 1; - - // Optional prefix for a date - private static final String DATE_PREFIX = "D:"; - - // Month Names, 1 indexed based - private static String[] monthNames = {"", - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December"}; - - - // instance values related to time parts - private String year = ""; - private String month = ""; - private String day = ""; - private String hour = ""; - private String minute = ""; - private String second = ""; - private String timeZoneOffset = ""; - private String timeZoneHour = ""; - private String timeZoneMinute = ""; - - // set to true when an non standard data is encountered - private boolean notStandardFormat = false; - - - /** - * Create a new Date object. - * - * @param date date ASCII data. - */ - public PDate(SecurityManager securityManager, String date) { - // parse the the date string - if (date != null) { - parseDate(date); - } - } - - /** - * Gets the year value of the date. - *
Note
- * If the original date value cannot be parsed, this method returns - * the unparsed string. - * - * @return year value. - */ - public String getYear() { - return year; - } - - /** - * Gets the month value of the date. - *
Note
- * If the original date value cannot be parsed, this method returns - * the unparsed string. - * - * @return month value. - */ - public String getMonth() { - return month; - } - - /** - * Gets the day value of the date. - *
Note
- * If the original date value cannot be parsed, this method returns - * the unparsed string. - * - * @return day value. - */ - public String getDay() { - return day; - } - - /** - * Gets the hour value of the date. - *
Note
- * If the original date value cannot be parsed, this method returns - * the unparsed string. - * - * @return hour value. - */ - public String getHour() { - return hour; - } - - /** - * Gets the minute value of the date. - *
Note
- * If the original date value cannot be parsed, this method returns - * the unparsed string. - * - * @return minute value. - */ - public String getMinute() { - return minute; - } - - /** - * Gets the second value of the date. - *
Note
- * If the original date value cannot be parsed, this method returns - * the unparsed string. - * - * @return second value. - */ - public String getSecond() { - return second; - } - - /** - * Gets the time zone offset hour from GMT. - *
Note
- * If the original date value cannot be parsed, this method returns - * the unparsed string. - * - * @return hour value. - */ - public String getTimeZoneHour() { - return timeZoneHour; - } - - /** - * Gets the time zone offset minute from GMT. - *
Note
- * If the original date value cannot be parsed, this method returns - * the unparsed string. - * - * @return minute value. - */ - public String getTimeZoneMinute() { - return timeZoneMinute; - } - - /** - * Gets the time zone offset fromm GMT. If the offset is negative - * true is returned, false otherwise. - *
Note
- * If the original date value cannot be parsed, this method returns - * the unparsed string. - * - * @return time offset value. - */ - public boolean getTimeZoneOffset() { - return !"-".equals(timeZoneOffset); - } - - /** - * Returns a decoded string representation of the date object. - * If the date object could not be parsed, the orginal date value is - * returned. - * - * @return date value. - */ - public String toString() { - if (!notStandardFormat) { - StringBuilder sb = new StringBuilder(40); - if (getMonth(month).length() > 0) - sb.append(getMonth(month)); - if (day.length() > 0) - sb.append(" ").append(day); - if (year.length() > 0) - sb.append(", ").append(year); - if (hour.length() > 0) - sb.append(" ").append(hour); - if (minute.length() > 0) - sb.append(":").append(minute); - if (second.length() > 0) - sb.append(":").append(second); - if (timeZoneOffset.length() > 0) { - if (timeZoneOffset.equalsIgnoreCase("Z")) - sb.append(" (UTC)"); - else { - sb.append(" (UTC ").append(timeZoneOffset); - if (timeZoneHour.length() > 0) - sb.append("").append(timeZoneHour); - if (timeZoneMinute.length() > 0) - sb.append(":").append(timeZoneMinute); - sb.append(")"); - } - } - return sb.toString(); - } else { - // return coded date - return day; - } - } - - /** - * Utility method for parsing PDF docs date format - * (D:YYYYMMDDHHmmSSOHH'mm'). If the date is not in a know format - * all instances variables are assigned the date value. - * - * @param date string representing a PDF date object. - */ - private void parseDate(String date) { - // get ride of "D:" prefix - if (date.indexOf(DATE_PREFIX) >= 0) { - date = date.substring(2); - parseAdobeDate(date); - } - // have none standard form, Ghostscript, 5/26/2004 13:25:11 - else if (date.indexOf("/") >= 0) { - parseGhostScriptDate(date); - } - //try adobe format but with out D: - else { - year = date; - month = date; - day = date; - hour = date; - minute = date; - second = date; - timeZoneOffset = date; - timeZoneHour = date; - timeZoneMinute = date; - notStandardFormat = true; - } - - } - - /** - * Utility method for parsing a ghostscript date formate, 5/26/2004 13:25:11. - * - * @param date string representing a PDF date object. - */ - private void parseGhostScriptDate(String date) { - // month/day/year hour:minute:second - - // break the string on the date/time space - StringTokenizer dateTime = new StringTokenizer(date); - // tokenize the date using "/" - StringTokenizer dateToken = - new StringTokenizer(dateTime.nextToken(), "/"); - // tokenize the time using ":" - StringTokenizer timeToken = - new StringTokenizer(dateTime.nextToken(), ":"); - - // get date vars - month = dateToken.nextToken(); - day = dateToken.nextToken(); - year = dateToken.nextToken(); - - // get time vars - hour = timeToken.nextToken(); - minute = timeToken.nextToken(); - second = timeToken.nextToken(); - } - - /** - * Utility mehtod for parsing Adobe standard date format, - * (D:YYYYMMDDHHmmSSOHH'mm'). - * - * @param date string representing a PDF date object. - */ - private void parseAdobeDate(String date) { - - // total offset count - int totalOffset = 0; - int currentOffset = 0; - - // start peeling of values from string - if (totalOffset + OFFSET_YYYY <= date.length()) { - currentOffset = (totalOffset + OFFSET_YYYY); - year = date.substring(totalOffset, currentOffset); - totalOffset += currentOffset; - } - if (totalOffset + OFFSET_MM <= date.length()) { - currentOffset = (totalOffset + OFFSET_MM); - month = date.substring(totalOffset, currentOffset); - totalOffset += OFFSET_MM; - } - if (totalOffset + OFFSET_DD <= date.length()) { - currentOffset = (totalOffset + OFFSET_DD); - day = date.substring(totalOffset, currentOffset); - totalOffset += OFFSET_DD; - } - if (totalOffset + OFFSET_HH <= date.length()) { - currentOffset = (totalOffset + OFFSET_HH); - hour = date.substring(totalOffset, currentOffset); - totalOffset += OFFSET_HH; - } - if (totalOffset + OFFSET_mm <= date.length()) { - currentOffset = (totalOffset + OFFSET_mm); - minute = date.substring(totalOffset, currentOffset); - totalOffset += OFFSET_mm; - } - if (totalOffset + OFFSET_SS <= date.length()) { - currentOffset = (totalOffset + OFFSET_SS); - second = date.substring(totalOffset, currentOffset); - totalOffset += OFFSET_SS; - } - if (totalOffset + OFFSET_0 <= date.length()) { - currentOffset = (totalOffset + OFFSET_0); - timeZoneOffset = date.substring(totalOffset, currentOffset); - totalOffset += OFFSET_0; - } - if (totalOffset + OFFSET_HH <= date.length()) { - currentOffset = (totalOffset + OFFSET_HH); - timeZoneHour = date.substring(totalOffset, currentOffset); - totalOffset += OFFSET_HH; - } - // lastly pull off 'MM' for timezone minutes - if (totalOffset + 4 <= date.length()) { - // compensate for the ' in 'MM' - timeZoneMinute = date.substring(totalOffset + 1, totalOffset + 3); - //System.out.println(timeZoneMinute); - } - } - - /** - * Utility method for finding month names. - */ - private String getMonth(String month) { - int monthIndex = 0; - try { - monthIndex = Integer.parseInt(month); - } - // eat any problems - catch (NumberFormatException e) { - } - - return monthNames[monthIndex]; - } - - /** - * Formats a date/time according to the PDF specification - * (D:YYYYMMDDHHmmSSOHH'mm'). - * - * @param time date/time value to format - * @param tz the time zone - * @return the requested String representation - */ - public static String formatDateTime(Date time, TimeZone tz) { - Calendar cal = Calendar.getInstance(tz, Locale.ENGLISH); - cal.setTime(time); - - int offset = cal.get(Calendar.ZONE_OFFSET); - offset += cal.get(Calendar.DST_OFFSET); - - //DateFormat is operating on GMT so adjust for time zone offset - Date dt1 = new Date(time.getTime() + offset); - StringBuffer sb = new StringBuffer(); - sb.append(DATE_FORMAT.format(dt1)); - - offset /= (1000 * 60); //Convert to minutes - - if (offset == 0) { - sb.append('Z'); - } else { - if (offset > 0) { - sb.append('+'); - } else { - sb.append('-'); - } - int offsetHour = Math.abs(offset / 60); - int offsetMinutes = Math.abs(offset % 60); - if (offsetHour < 10) { - sb.append('0'); - } - sb.append(Integer.toString(offsetHour)); - sb.append('\''); - if (offsetMinutes < 10) { - sb.append('0'); - } - sb.append(Integer.toString(offsetMinutes)); - sb.append('\''); - } - return sb.toString(); - } - - /** - * Formats a date/time according to the PDF specification. - * (D:YYYYMMDDHHmmSSOHH'mm'). - * - * @param time date/time value to format - * @return the requested String representation - */ - public static String formatDateTime(Date time) { - return formatDateTime(time, TimeZone.getDefault()); - } - - public static PDate createDate(Date date) { - return new PDate(null, formatDateTime(date)); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PDimension.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PDimension.java deleted file mode 100644 index 526f87b52a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PDimension.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import java.awt.*; -import java.awt.geom.Dimension2D; - - -/** - *

This class represents a dimension similar to java.awt.geom.Dimension2D.Dimension - * but ensures that width and height are stored using floating point values.

- * - * @since 2.0 - */ -public class PDimension extends Dimension2D { - private float width; - private float height; - - /** - * Creates a new instance of a PDimension. - * - * @param w width of new dimension. - * @param h height of new dimension. - */ - public PDimension(float w, float h) { - set(w, h); - } - - /** - * Creates a new instance of a PDimension. - * - * @param w width of new dimension. - * @param h height of new dimension. - */ - public PDimension(int w, int h) { - set(w, h); - } - - /** - * Sets the width and height of the dimension. - * - * @param w new width value. - * @param h new height value. - */ - public void set(float w, float h) { - width = w; - height = h; - } - - /** - * Sets the width and height of the dimension. - * - * @param w new width value. - * @param h new height value. - */ - public void set(int w, int h) { - width = w; - height = h; - } - - /** - * Gets the width of the dimension object. - * - * @return width - */ - public double getWidth() { - return width; - } - - /** - * Gets the height of the dimension object. - * - * @return height - */ - public double getHeight() { - return height; - } - - /** - * Converts this object to a java.awt.geom.Dimension2D.Dimension. The - * floating point accuracy of the width and height are lost when converted - * to int. - * - * @return a new java.awt.geom.Dimension2D.Dimension - */ - public Dimension toDimension() { - return new Dimension((int) width, (int) height); - } - - /** - * String representation of this object. - * - * @return string summary of width and height of this object. - */ - public String toString() { - return "PDimension { width=" + width + ", height=" + height + " }"; - } - - @Override - public void setSize(double width, double height) { - this.width = (float) width; - this.height = (float) height; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PInfo.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PInfo.java deleted file mode 100644 index 94193cd693..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PInfo.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.fonts.ofont.Encoding; -import org.icepdf.core.pobjects.security.SecurityManager; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - *

This class represents the data stored in a File trailers optional "info" - * entry.

- *

- *

Any entry whose value is not known should be omitted from the dictionary, - * rather than included with an empty string as its value.

- *

- *

Some plug-in extensions may choose to permit searches on the contents of the - * document information dictionary. To facilitate browsing and editing, all keys - * in the dictionary are fully spelled out, not abbreviated. New keys should be - * chosen with care so that they make sense to users.

- * - * @since 1.1 - */ -public class PInfo extends Dictionary { - - public static final Name RESOURCES_KEY = new Name("Resources"); - public static final Name TITLE_KEY = new Name("Title"); - public static final Name AUTHOR_KEY = new Name("Author"); - public static final Name SUBJECT_KEY = new Name("Subject"); - public static final Name KEYWORDS_KEY = new Name("Keywords"); - public static final Name CREATOR_KEY = new Name("Creator"); - public static final Name PRODUCER_KEY = new Name("Producer"); - public static final Name CREATIONDATE_KEY = new Name("CreationDate"); - public static final Name MODDATE_KEY = new Name("ModDate"); - public static final Name TRAPPED_KEY = new Name("Trapped"); - - // security manager need for decrypting strings. - private SecurityManager securityManager; - - /** - * Create a new instance of a PInfo object. - * - * @param library document library - * @param entries entries for this object dictionary. - */ - public PInfo(Library library, HashMap entries) { - super(library, entries); - securityManager = library.getSecurityManager(); - } - - /** - * Gets the value of the custom extension specified by name. - * - * @param name som plug-in extensions name. - * @return value of the plug-in extension. - */ - public Object getCustomExtension(Name name) { - Object value = library.getObject(entries, name); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return cleanString(text.getDecryptedLiteralString(securityManager)); - } - return value; - } - - /** - * Gets the title of the document. - * - * @return the documents title. - */ - public String getTitle() { - Object value = library.getObject(entries, TITLE_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return cleanString(text.getDecryptedLiteralString(securityManager)); - } else if (value instanceof String) { - return (String) value; - } - return null; - } - - /** - * Gets the name of the person who created the document. - * - * @return author name. - */ - public String getAuthor() { - Object value = library.getObject(entries, AUTHOR_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return cleanString(text.getDecryptedLiteralString(securityManager)); - } else if (value instanceof String) { - return (String) value; - } - return null; - } - - /** - * Gets the subject of the document. - * - * @return documents subject. - */ - public String getSubject() { - Object value = library.getObject(entries, SUBJECT_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return cleanString(text.getDecryptedLiteralString(securityManager)); - } else if (value instanceof String) { - return (String) value; - } - return null; - } - - /** - * Gets the keywords associated with the document. - * - * @return documents keywords. - */ - public String getKeywords() { - Object value = library.getObject(entries, KEYWORDS_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return cleanString(text.getDecryptedLiteralString(securityManager)); - } else if (value instanceof String) { - return (String) value; - } - return null; - } - - /** - * Gets the name of the application. If the PDF document was converted from - * another format that created the original document. - * - * @return creator name. - */ - public String getCreator() { - Object value = library.getObject(entries, CREATOR_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return cleanString(text.getDecryptedLiteralString(securityManager)); - } else if (value instanceof String) { - return (String) value; - } - return null; - } - - /** - * Gets the name of the application. If the PDF document was converted from - * another format that converted the original document. - * - * @return producer name. - */ - public String getProducer() { - Object value = library.getObject(entries, PRODUCER_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return cleanString(text.getDecryptedLiteralString(securityManager)); - } else if (value instanceof String) { - return (String) value; - } - return null; - } - - /** - * Gets the date and time the document was created. - * - * @return creation date. - */ - public PDate getCreationDate() { - Object value = library.getObject(entries, CREATIONDATE_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return new PDate(securityManager, text.getDecryptedLiteralString(securityManager)); - } - return null; - } - - /** - * Gets the date and time the document was most recently modified. - * - * @return modification date. - */ - public PDate getModDate() { - Object value = library.getObject(entries, MODDATE_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return new PDate(securityManager, text.getDecryptedLiteralString(securityManager)); - } - return null; - } - - /** - * Get the name object indicating whether the document has been modified to - * include trapping information: - *
    - *
  • False - The document has not yet been trapped; any desired - * trapping must still be done.
  • - *
  • Unknown - (default) Either it is unknown whether the document has - * been trapped or it has been partly but not yet fully - * trapped; some additional trapping may still be needed.
  • - *
- * - * @return trapped name. - */ - public String getTrappingInformation() { - Object value = library.getObject(entries, TRAPPED_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return cleanString(text.getDecryptedLiteralString(securityManager)); - } else if (value instanceof String) { - return (String) value; - } - return null; - } - - /** - * Utility method for removing extra characters associated with 4 byte - * characters codes. - * - * @param text string to clean - * @return cleaned - */ - private String cleanString(String text) { - if (text != null && text.length() > 0) { - if (((int) text.charAt(0)) == 254 && ((int) text.charAt(1)) == 255) { - StringBuilder sb1 = new StringBuilder(); - - // strip and white space, as the will offset the below algorithm - // which assumes the string is made up of two byte chars. - String hexTmp = ""; - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); - if (!((c == '\t') || (c == '\r') || (c == '\n'))) { - hexTmp = hexTmp + text.charAt(i); - } - } - byte title1[] = hexTmp.getBytes(); - - for (int i = 2; i < title1.length; i += 2) { - try { - int b1 = (((int) title1[i] & 0xFF) << 8) | - (int) title1[i + 1] & 0xFF; - sb1.append((char) (b1)); - } catch (Exception ex) { - // intentionally left empty - } - } - text = sb1.toString(); - } else { - StringBuilder sb = new StringBuilder(); - Encoding enc = Encoding.getPDFDoc(); - for (int i = 0; i < text.length(); i++) { - sb.append(enc.get(text.charAt(i))); - } - text = sb.toString(); - } - return text; - } else { - return ""; - } - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PObject.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PObject.java deleted file mode 100644 index bfe8d1e0e8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PObject.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -/** - * The class represents a generic PDF object. Each PDF object can be identified - * by a unique reference object, which contains the objects object number and - * generation number. - * - * @see org.icepdf.core.pobjects.Reference - * @since 1.0 - */ -public class PObject { - private Object object; - private Reference objectReference = null; - private int linearTraversalOffset; - - /** - * Create a new PObject. - * - * @param object a PDF object that is associated by the objectNumber and - * and objectGeneration data - * @param objectNumber the object number of the PDF object - * @param objectGeneration the generation number of the PDF object - */ - public PObject(Object object, Number objectNumber, Number objectGeneration) { - this.object = object; - objectReference = new Reference(objectNumber, objectGeneration); - } - - /** - * Create a new PObject. - * - * @param object a PDF object that is associated by the objectNumber and - * and objectGeneration data - * @param objectReference Reference object which contains the PDF objects - * number and generation data - */ - public PObject(Object object, Reference objectReference) { - this.object = object; - this.objectReference = objectReference; - } - - /** - * Gets the reference information for this PDF object. - * - * @return Reference object which contains the PDF objects - * number and generation data - */ - public Reference getReference() { - return objectReference; - } - - /** - * Gets the generic PDF Object stored at this object number and generation. - * - * @return object refrenced byt he object number and generation - */ - public Object getObject() { - return object; - } - - @Override - public int hashCode() { - int result = object != null ? object.hashCode() : 0; - result = 31 * result + (objectReference != null ? objectReference.hashCode() : 0); - return result; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - PObject pObject = (PObject) o; - - if (object != null ? !object.equals(pObject.object) : pObject.object != null) { - return false; - } - if (objectReference != null ? !objectReference.equals(pObject.objectReference) : pObject.objectReference != null) { - return false; - } - - return true; - } - - public int getLinearTraversalOffset() { - return linearTraversalOffset; - } - - public void setLinearTraversalOffset(int linearTraversalOffset) { - this.linearTraversalOffset = linearTraversalOffset; - } - - /** - * String representation of this object. Used mainly for debugging. - * - * @return string representation of this object - */ - public String toString() { - return objectReference.toString() + " " + object.toString(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PRectangle.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PRectangle.java deleted file mode 100644 index 194ff81d6d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PRectangle.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.List; - -/** - *

A rectangle in a PDF document is slightly different than the Rectangle class - * in Java. A PDF rectangle is written as an array of four numbers giving the - * coordinates of a pair of diagonally opposite corners. Typically, the - * array takes the form:

- *

- *

    - * [IIx IIy URx URy] - *
- *

- *

This specifies the lower-left x, lower-left y, upper-right x, and upper-right y - * coordinates of the rectangle, in that order. However, this format is not - * guaranteed and this class normalizes such rectangles.

- *

- *

Another very important difference between PRectangles Rectangles is that - * PRectangles use the Cartesian Coordinate system, where Rectangles use the - * Java2D coordinates system. As a result, the user of this class must know the - * context in which the PRectangle is being used. For example there is a significant - * difference between the inherited method createIntersection and PRectangles - * createCartesianIntersection.

- * - * @since 2.0 - */ -@SuppressWarnings("serial") -public class PRectangle extends Rectangle2D.Float { - - private float p1x; - private float p1y; - private float p2x; - private float p2y; - - /** - *

Creates a new PRectangle object. The points are automatically normalized - * by the constructor. These two coordinates represent the diagonal - * corners of the rectangle. - * - * @param p1 first point of diagonal, in the Cartesian coordinate space - * @param p2 second point of diagonal, in the Cartesian coordinate space - */ - public PRectangle(Point2D.Float p1, Point2D.Float p2) { - super(); - normalizeCoordinates(p1.x, p1.y, p2.x, p2.y); - // assign original data - p1x = p1.x; - p1y = p1.y; - p2x = p2.x; - p2y = p2.y; - } - - /** - *

Creates a new PRectangle object assumed to be in the Cartesian coordinate - * space.

- * - * @param x the specified x coordinate - * @param y the specified y coordinate - * @param width the width of the Rectangle - * @param height the height of the Rectangle - */ - private PRectangle(float x, float y, float width, float height) { - super(x, y, width, height); - } - - /** - * Creates a new PRectangle object. The points are automatically normalized - * by the constructor. - * - * @param coordinates a vector containing four elements where the first and - * second elements represent the x and y coordinates of one point and the - * third and fourth elements represent the x and y cooordinates of the second - * point. These two coordinates represent the diagonal corners of the - * rectangle. - * @throws IllegalArgumentException thrown if coordinates is null or does not - * have four elements - */ - public PRectangle(List coordinates) throws IllegalArgumentException { - if (coordinates == null || coordinates.size() < 4) - throw new IllegalArgumentException(); - float x1 = ((Number) coordinates.get(0)).floatValue(); - float y1 = ((Number) coordinates.get(1)).floatValue(); - - float x2 = ((Number) coordinates.get(2)).floatValue(); - float y2 = ((Number) coordinates.get(3)).floatValue(); - - // assign original data - p1x = x1; - p1y = y1; - p2x = x2; - p2y = y2; - - //System.out.println(x1 + " : " + y1 + " : " + x2 + " : " + y2 ); - normalizeCoordinates(x1, y1, x2, y2); - } - - /** - * Returns a new PRectangle object representing the intersection of this - * PRectangle with the specified PRectangle using the Cartesian coordinate - * system. If a Java2D coordinate system is used, then the rectangle should - * be first converted to that space {@see #toJava2dCoordinates() }. - * - * @param src2 the Rectangle2D to be intersected with this Rectangle2D. - * @return object representing the intersection of the two PRectangles. - */ - public PRectangle createCartesianIntersection(PRectangle src2) { - PRectangle rec = new PRectangle(src2.x, src2.y, src2.width, src2.height); - float xLeft = (x > rec.x) ? x : rec.x; - float xRight = ((x + width) > (rec.x + rec.width)) ? - (rec.x + rec.width) : (x + width); - - float yBottom = ((y - height) < (rec.y - rec.height) ? - (rec.y - rec.height) : (y - height)); - float yTop = (y > rec.y) ? rec.y : y; - - rec.x = xLeft; - rec.y = yTop; - rec.width = xRight - xLeft; - rec.height = yTop - yBottom; - - // If rectangles don't intersect, return zeroed intersection. - if (rec.width < 0 || rec.height < 0) { - rec.x = rec.y = rec.width = rec.height = 0; - } - return rec; - } - - /** - *

Gets the orgional two points that created the PRectangle object. The - * first point is represented by the the rectangle positions x, y and the - * second poitn is represented by the width and height of the rectangle. - * - * @return rectangle representing the PRectangle object initial two point. - */ - public Rectangle2D.Float getOriginalPoints() { - return new Rectangle2D.Float(p1x, p1y, p2x, p2y); - } - - /** - *

Converts the Cartesian representation of the Rectangle into Rectangle in - * the Java2D coordinate space.

- * - * @return rectangle in the Java2D coordinate space. - */ - public Rectangle2D.Float toJava2dCoordinates() { - return new Rectangle2D.Float(x, y - height, width, height); - } - - /** - * Converts a rectangle defined in user page in Java2D coordinates back - * to PDF space and in the vector for of the rectangle. - * - * @param rect user space rectangle in Java2D coordinates space. - * @return vector notation of rectangle in PDF space. - */ - public static List getPRectangleVector(Rectangle2D rect) { - - // convert the rectangle back to PDF space. - rect = new Rectangle2D.Double(rect.getX(), - rect.getY(), - rect.getWidth(), rect.getHeight()); - ArrayList coords = new ArrayList(4); - coords.add(rect.getMinX()); - coords.add(rect.getMinY()); - coords.add(rect.getMaxX()); - coords.add(rect.getMaxY()); - return coords; - } - - /** - * Normalizes the given coordinates so that the rectangle is created with the - * proper dimensions. - * - * @param x1 x value of coordinate 1 - * @param y1 y value of coordinate 1 - * @param x2 x value of coordinate 2 - * @param y2 y value of coordinate 2 - */ - private void normalizeCoordinates(float x1, float y1, float x2, float y2) { - float x = x1, y = y1, - w = Math.abs(x2 - x1), - h = Math.abs(y2 - y1); - // get smallest x - if (x1 > x2) { - x = x2; - } - // get largest y - if (y1 < y2) { - y = y2; - } - setRect(x, y, w, h); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PTrailer.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PTrailer.java deleted file mode 100644 index a1b48fe9eb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PTrailer.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.HashMap; -import java.util.List; -import java.util.Set; - -/** - *

The trailer of a PDF file enables an application reading the file to quickly - * find the cross-reference table and certain special objects. Applications - * should read a PDF file from its end. The last line of the file contains only - * the end-of-file marker, %%EOF.

- *

- *

A document can have more then one trailer reference. It is important to use - * the addTrailer() method if a subsequent trailer is found, or the - * addPreviousTrailer() method if a previous trailer is found, depending on if - * the PDF file is being read linearly, or via random access seeking.

- *

- *

If the Prev key entry is present then the document has more then one - * cross-reference section. There is a numerical value, which is typically - * associated with the trailer, that comes after startxref, and before %%EOF. - * It is byte offset from the beginning of the file to the beginning of the last - * cross-reference section.

- *

- *

In a regular PDF, it's the address of the current xref table. In a linearized - * PDF, it's the address of the xref table at the file beginning, or zero. - * In an updated PDF, it's the address of the current xref table. In all cases, - * the LastCrossReferenceSection field, at the end of the PDF file, points - * to the byte offset from the beginning of the file, of the "last" xref section, - * which means the xref section with the highest precedence. For each xref section, - * its following trailer section has a Prev field, which points to the byte - * offset from the beginning of the file, of the xref section with one less - * degree of precedence.

- * - * @since 1.1 - */ -public class PTrailer extends Dictionary { - - public static final Name SIZE_KEY = new Name("Size"); - public static final Name PREV_KEY = new Name("Prev"); - public static final Name ROOT_KEY = new Name("Root"); - public static final Name ENCRYPT_KEY = new Name("Encrypt"); - public static final Name INFO_KEY = new Name("Info"); - public static final Name ID_KEY = new Name("ID"); - public static final Name XREFSTM_KEY = new Name("XRefStm"); - - // Position in the file. The LazyObjectLoader typically keeps this info - // for all PDF objects, but the bootstrapping PTrialer is an exception, - // and we need its location for writing incremental updates, so for - // consistency we'll have all PTrailers maintain their position. - private long position; - - // documents cross reference table - private CrossReference crossReferenceTable; - - // documents cross reference stream. - private CrossReference crossReferenceStream; - - /** - * Create a new PTrailer object - * - * @param dictionary dictionary associated with the trailer - */ - public PTrailer(Library library, HashMap dictionary, CrossReference xrefTable, CrossReference xrefStream) { - super(library, dictionary); - - crossReferenceTable = xrefTable; - crossReferenceStream = xrefStream; - if (crossReferenceTable != null) - crossReferenceTable.setTrailer(this); - if (crossReferenceStream != null) - crossReferenceStream.setTrailer(this); - } - - /** - * Gets the total number of entries in the file's cross-reference table, as - * defined by the combination of the original section and all updated sections. - * Equivalently, this value is 1 greater than the highest object number - * used in the file. - *
    - *
  • Note: Any object in a cross-reference section whose number is - * greater than this value is ignored and considered missing.
  • - *
- *

- * Required : must not be an indirect reference - * - * @return total number of entries in the file's cross-reference table - */ - public int getNumberOfObjects() { - return library.getInt(entries, SIZE_KEY); - } - - /** - * Gets the byte offset from the beginning of the file to the beginning of the - * previous cross-reference section. - *

- * (Present only if the file has more than one cross-reference section; must - * not be an indirect reference) - * - * @return byte offset from beginning of the file to the beginning of the - * previous cross-reference section - */ - public long getPrev() { - return library.getLong(entries, PREV_KEY); - } - - /** - * Depending on if the PDF file is version 1.4 or before, or 1.5 or after, - * it may have a cross reference table, or cross reference stream, or both. - * If there are both, then the cross reference table has precedence. - * - * @return the cross reference object with the highest precedence, for this trailer - */ - protected CrossReference getPrimaryCrossReference() { - if (crossReferenceTable != null) - return crossReferenceTable; - loadXRefStmIfApplicable(); - return crossReferenceStream; - } - - /** - * Gets the cross reference table. - * - * @return cross reference table object; null, if one does not exist. - */ - protected CrossReference getCrossReferenceTable() { - return crossReferenceTable; - } - - /** - * Gets the cross reference stream. - * - * @return cross reference stream object; null, if one does not exist. - */ - protected CrossReference getCrossReferenceStream() { - return crossReferenceStream; - } - - /** - * Gets the catalog reference for the PDF document contained in the file. - *

- * Required : must not be an indirect reference - * - * @return reference number of catalog reference. - */ - public Reference getRootCatalogReference() { - return library.getObjectReference(entries, ROOT_KEY); - } - - /** - * Gets the Catalog entry for this PDF document. - * - * @return Catalog entry. - */ - @SuppressWarnings("unchecked") - public Catalog getRootCatalog() { - Object tmp = library.getObject(entries, ROOT_KEY); - // specification states the the root entry must be a indirect - if (tmp instanceof Catalog) { - return (Catalog) tmp; - } - // there are however a few instances where the dictionary is specified - // directly - else if (tmp instanceof HashMap) { - return new Catalog(library, (HashMap) tmp); - } - // if no root was found we return so that the use will be notified - // of the problem which is the PDF can not be loaded. - else { - return null; - } - } - - /** - * The document's encryption dictionary - *

- * Required : if document is encrypted; PDF 1.1 - * - * @return encryption dictionary - */ - @SuppressWarnings("unchecked") - public HashMap getEncrypt() { - Object encryptParams = library.getObject(entries, ENCRYPT_KEY); - if (encryptParams instanceof HashMap) { - return (HashMap) encryptParams; - } else { - return null; - } - } - - /** - * The document's information dictionary - *

- * Optional : must be an indirect reference. - * - * @return information dictionary - */ - public PInfo getInfo() { - Object info = library.getObject(entries, INFO_KEY); - if (info instanceof HashMap) { - return new PInfo(library, (HashMap) info); - } else { - return null; - } - } - - /** - * A vector of two strings constituting a file identifier - *

- * Optional : PDF 1.1. - * - * @return vector containing constituting file identifier - */ - public List getID() { - return (List) library.getObject(entries, ID_KEY); - } - - /** - * @return The position in te file where this trailer is located - */ - public long getPosition() { - return position; - } - - /** - * After this PTrailer is parsed, we store it's location within the PDF - * here, for future use. - */ - public void setPosition(long pos) { - position = pos; - } - - /** - * Add the trailer dictionary to the current trailer object's dictionary. - * - * @param nextTrailer document trailer object - */ - @SuppressWarnings("unchecked") - protected void addNextTrailer(PTrailer nextTrailer) { - nextTrailer.getPrimaryCrossReference().addToEndOfChainOfPreviousXRefs(getPrimaryCrossReference()); - - // Later key,value pairs take precedence over previous entries - HashMap nextDictionary = nextTrailer.getDictionary(); - HashMap currDictionary = getDictionary(); - Set currKeys = currDictionary.keySet(); - for (Object currKey : currKeys) { - if (!nextDictionary.containsKey(currKey)) { - Object currValue = currDictionary.get(currKey); - nextDictionary.put(currKey, currValue); - } - } - } - - @SuppressWarnings("unchecked") - protected void addPreviousTrailer(PTrailer previousTrailer) { -//System.out.println("PTrailer.addPreviousTrailer()"); - getPrimaryCrossReference().addToEndOfChainOfPreviousXRefs(previousTrailer.getPrimaryCrossReference()); - - // Later key,value pairs take precedence over previous entries - HashMap currDictionary = getDictionary(); - HashMap prevDictionary = previousTrailer.getDictionary(); - Set prevKeys = prevDictionary.keySet(); - for (Object prevKey : prevKeys) { - if (!currDictionary.containsKey(prevKey)) { - Object prevValue = prevDictionary.get(prevKey); - currDictionary.put(prevKey, prevValue); - } - } - } - - protected void onDemandLoadAndSetupPreviousTrailer() { -//System.out.println("PTrailer.onDemandLoadAndSetupPreviousTrailer() : " + this); -//try { throw new RuntimeException(); } catch(Exception e) { e.printStackTrace(); } - long position = getPrev(); - if (position > 0L) { - PTrailer prevTrailer = library.getTrailerByFilePosition(position); - if (prevTrailer != null) - addPreviousTrailer(prevTrailer); - } - } - - protected void loadXRefStmIfApplicable() { - if (crossReferenceStream == null) { - long xrefStreamPosition = library.getLong(entries, XREFSTM_KEY); - if (xrefStreamPosition > 0L) { - // OK, this is a little weird, but basically, any XRef stream - // dictionary is also a Trailer dictionary, so our Parser - // makes both of the objects. - // Now, we don't actually want to chain the trailer as our - // previous, but only want its CrossReferenceStream to make - // our own - PTrailer trailer = library.getTrailerByFilePosition(xrefStreamPosition); - if (trailer != null) - crossReferenceStream = trailer.getCrossReferenceStream(); - } - } - } - - /** - * Get the trailer object's dictionary. - * - * @return dictionary - */ - public HashMap getDictionary() { - return entries; - } - - /** - * Returns a summary of the PTrailer dictionary values. - * - * @return dictionary values. - */ - public String toString() { - return "PTRAILER= " + entries.toString() + " xref table=" + crossReferenceTable + " xref stream=" + crossReferenceStream; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Page.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Page.java deleted file mode 100644 index 12bdc7820f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Page.java +++ /dev/null @@ -1,1772 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.events.*; -import org.icepdf.core.io.SeekableInput; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.FreeTextAnnotation; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.pobjects.graphics.WatermarkCallback; -import org.icepdf.core.pobjects.graphics.text.GlyphText; -import org.icepdf.core.pobjects.graphics.text.LineText; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.pobjects.graphics.text.WordText; -import org.icepdf.core.util.*; -import org.icepdf.core.util.content.ContentParser; -import org.icepdf.core.util.content.ContentParserFactory; - -import java.awt.*; -import java.awt.geom.*; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

This class represents the leaves of a PageTree object known - * as Page class. The page dictionary specifies attributes - * of the single page of the document. Many of the page's attributes are - * inherited from the page tree dictionary if not specified in the page - * dictionary.

- *

- *

The page object also provides a method which will extract a page's content, - * such as text and images. The paint method is the core of - * the ICEpdf renderer, allowing page content to be painted to any Java graphics - * context.

- *

- *

Page objects in a PDF document have different boundaries defined which - * govern various aspects of the pre-press process, such as cropping, bleed, - * and trimming. Facilities for including printer's marks, such a registration - * targets, gray ramps color bars, and cut marks which assist in the production - * process. When getting a page's size, the default boundary used is the crop - * box which is what most viewer applications should use. However, if your application - * requires the use of different page boundaries, they can be specified when - * using the getSize or paint methods. If in doubt, always use the crop box - * constant.

- * - * @see org.icepdf.core.pobjects.PageTree - * @since 1.0 - */ -public class Page extends Dictionary { - - private static final Logger logger = - Logger.getLogger(Page.class.toString()); - - /** - * Transparency value used to simulate text highlighting. - */ - public static final float SELECTION_ALPHA = 0.3f; - - // text selection colour - public static Color selectionColor; - - static { - // sets the shadow colour of the decorator. - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.text.selectionColor", "#0077FF"); //#99c1da - int colorValue = ColorUtil.convertColor(color); - selectionColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("99c1da", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading text selection colour"); - } - } - } - - // text highlight colour - public static Color highlightColor; - - static { - // sets the shadow colour of the decorator. - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.text.highlightColor", "#CC00FF");//ff99ff - int colorValue = ColorUtil.convertColor(color); - highlightColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("ff99ff", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading text highlight colour"); - } - } - } - - public static final Name TYPE = new Name("Page"); - public static final Name ANNOTS_KEY = new Name("Annots"); - public static final Name CONTENTS_KEY = new Name("Contents"); - public static final Name RESOURCES_KEY = new Name("Resources"); - public static final Name THUMB_KEY = new Name("Thumb"); - public static final Name PARENT_KEY = new Name("Parent"); - public static final Name ROTATE_KEY = new Name("Rotate"); - public static final Name MEDIABOX_KEY = new Name("MediaBox"); - public static final Name CROPBOX_KEY = new Name("CropBox"); - public static final Name ARTBOX_KEY = new Name("ArtBox"); - public static final Name BLEEDBOX_KEY = new Name("BleedBox"); - public static final Name TRIMBOX_KEY = new Name("TrimBox"); - /** - * Defines the boundaries of the physical medium on which the page is - * intended to be displayed or printed. - */ - public static final int BOUNDARY_MEDIABOX = 1; - /** - * Defines the visible region of the default user space. When the page - * is displayed or printed, its contents are to be clipped to this - * rectangle and then imposed on the output medium in some implementation - * defined manner. - */ - public static final int BOUNDARY_CROPBOX = 2; - /** - * Defines the region to which the contents of the page should be clipped - * when output in a production environment (Mainly commercial printing). - */ - public static final int BOUNDARY_BLEEDBOX = 3; - /** - * Defines the intended dimensions of the finished page after trimming. - */ - public static final int BOUNDARY_TRIMBOX = 4; - /** - * Defines the extent of the page's meaningful content as intended by the - * page's creator. - */ - public static final int BOUNDARY_ARTBOX = 5; - - // resources for page's parent pages, default fonts, etc. - private Resources resources; - // Vector of annotations - private List annotations; - // Contents - private List contents; - // Container for all shapes stored on page - private Shapes shapes = null; - - // the collection of objects listening for page paint events - private final List paintPageListeners = new ArrayList(8); - // the collection of objects listening for page loading events - private final List pageLoadingListeners = new ArrayList(); - - // Defines the boundaries of the physical medium on which the page is - // intended to be displayed on. - private PRectangle mediaBox; - // Defining the visible region of default user space. - private PRectangle cropBox; - // Defines the region to which the contents of the page should be clipped - // when output in a production environment. - private PRectangle bleedBox; - // Defines the intended dimension of the finished page after trimming. - private PRectangle trimBox; - // Defines the extent of the pages meaningful content as intended by the - // pages creator. - private PRectangle artBox; - - // page has default rotation value - private float pageRotation = 0; - - private int pageIndex; - private int imageCount; - private boolean pageInitialized; - private boolean pagePainted; - - private WatermarkCallback watermarkCallback; - - /** - * Create a new Page object. A page object represents a PDF object that - * has the name page associated with it. It also conceptually represents - * a page entity and all of it child elements that are associated with it. - * - * @param l pointer to default library containing all document objects - * @param h HashMap containing all of the dictionary entries - */ - public Page(Library l, HashMap h) { - super(l, h); - } - - public boolean isInitiated() { - return inited; - } - - private void initPageContents() throws InterruptedException { - Object pageContent = library.getObject(entries, CONTENTS_KEY); - - // if a stream process it as needed - if (pageContent instanceof Stream) { - contents = new ArrayList(1); - Stream tmpStream = (Stream) pageContent; - tmpStream.setPObjectReference( - library.getObjectReference(entries, CONTENTS_KEY)); - contents.add(tmpStream); - } - // if a vector, process it as needed - else if (pageContent instanceof List) { - List conts = (List) pageContent; - int sz = conts.size(); - contents = new ArrayList(Math.max(sz, 1)); - // pull all of the page content references from the library - for (int i = 0; i < sz; i++) { - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException("Page Content initialization thread interrupted"); - } - Object tmp = library.getObject(conts.get(i)); - if (tmp instanceof Stream) { - Stream tmpStream = (Stream) tmp; - // prune any zero length streams, - if (tmpStream != null && tmpStream.getRawBytes().length > 0) { - tmpStream.setPObjectReference((Reference) conts.get(i)); - contents.add(tmpStream); - } - } - } - } - } - - public void initPageResources() throws InterruptedException { - Resources res = library.getResources(entries, RESOURCES_KEY); - PageTree pageTree; - if (res == null) { - pageTree = getParent(); - while (pageTree != null) { - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException("Page Resource initialization thread interrupted"); - } - Resources parentResources = pageTree.getResources(); - if (parentResources != null) { - res = parentResources; - break; - } - pageTree = pageTree.getParent(); - } - } - resources = res; - } - - /** - * Gets a raw list of annotation references. The annotations are not initialized. - * - * @return list of a pages annotation reference list. - */ - public ArrayList getAnnotationReferences() { - Object annots = library.getObject(entries, ANNOTS_KEY); - if (annots != null && annots instanceof ArrayList) { - return (ArrayList) annots; - } - return null; - } - - private void initPageAnnotations() throws InterruptedException { - // find annotations in main library for our pages dictionary - Object annots = library.getObject(entries, ANNOTS_KEY); - if (annots != null && annots instanceof List) { - List v = (List) annots; - annotations = new ArrayList(v.size() + 1); - // add annotations - Object annotObj; - org.icepdf.core.pobjects.annotations.Annotation a = null; - for (int i = 0; i < v.size(); i++) { - - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException( - "Page Annotation initialization thread interrupted"); - } - - annotObj = v.get(i); - Reference ref = null; - // we might have a reference - if (annotObj instanceof Reference) { - ref = (Reference) v.get(i); - annotObj = library.getObject(ref); - } - - // but most likely its an annotations base class - if (annotObj instanceof Annotation) { - a = (Annotation) annotObj; - } - // or build annotations from dictionary. - else if (annotObj instanceof HashMap) { // HashMap lacks "Type"->"Annot" entry - a = Annotation.buildAnnotation(library, (HashMap) annotObj); - } - // set the object reference, so we can save the state correct - // and update any references accordingly. - try { - // set the object reference, so we can save the state correct - // and update any references accordingly. - if (ref != null && a != null) { - a.setPObjectReference(ref); - a.init(); - } - // add any found annotations to the vector. - annotations.add(a); - } catch (IllegalStateException e) { - logger.warning("Malformed annotation could not be initialized. " + - a != null ? " " + a.getPObjectReference() + a.getEntries() : ""); - } - } - } - } - - @Override - public void setPObjectReference(Reference reference) { - super.setPObjectReference(reference); //To change body of overridden methods use File | Settings | File Templates. - } - - /** - * Reset the pages initialized flag and as a result subsequent calls to - * this page may trigger a call to init(). - */ - public void resetInitializedState() { - inited = false; - } - - /** - * Initialize the Page object. This method triggers the parsing of a page's - * child elements. Once a page has been initialized, it can be painted. - */ - public synchronized void init() throws InterruptedException { - try { - // make sure we are not revisiting this method - if (inited) { - return; - } - pageInitialized = false; - - // get pages resources - initPageResources(); - - // annotations - initPageAnnotations(); - - // Get the value of the page's content entry - initPageContents(); - - // send out loading event. - if (resources != null) { - imageCount = resources.getImageCount(); - int contentCount = 0; - if (contents != null) { - contentCount = contents.size(); - } - notifyPageLoadingStarted(contentCount, resources.getImageCount()); - } - - /** - * Finally iterate through the contents vector and concat all of the - * the resource streams together so that the content parser can - * go to town and build all of the page's shapes. - */ - notifyPageInitializationStarted(); - if (contents != null) { - try { - ContentParser cp = ContentParserFactory.getInstance() - .getContentParser(library, resources); - byte[][] streams = new byte[contents.size()][]; - byte[] stream; - for (int i = 0, max = contents.size(); i < max; i++) { - stream = contents.get(i).getDecodedStreamBytes(); - if (stream != null) { - streams[i] = stream; - } - } - // get any optional groups from the catalog, which control - // visibility - OptionalContent optionalContent = - library.getCatalog().getOptionalContent(); - if (optionalContent != null) { - optionalContent.init(); - } - - // pass in option group references into parse. - if (streams.length > 0) { - shapes = cp.parse(streams, this).getShapes(); - } - // set the initiated flag, first as there are couple corner - // cases where the content parsing can call page.init() again - // from the same thread. - inited = true; - - }catch(InterruptedException e){ - throw new InterruptedException(e.getMessage()); - } catch (Exception e) { - shapes = new Shapes(); - logger.log(Level.WARNING, "Error initializing Page.", e); - } - } - // empty page, nothing to do. - else { - shapes = new Shapes(); - logger.log(Level.WARNING, "Error initializing Page, no page content."); - } - } catch (InterruptedException e) { - // keeps shapes vector so we can paint what we have but make init state as false - // so we can try to re parse it later. - inited = false; - throw new InterruptedException(e.getMessage()); - } - notifyPageInitializationEnded(inited); - } - - /** - * Gets a Thumbnail object associated with this page. If no Thumbnail - * entry exists then null is returned. - * - * @return thumbnail object of this page, null if no thumbnail value is - * encoded. - */ - public Thumbnail getThumbnail() { - Object thumb = library.getObject(entries, THUMB_KEY); - if (thumb != null && thumb instanceof Stream) { - return new Thumbnail(library, entries); - } else { - return null; - } - } - - public void requestInterrupt() { - if (shapes != null) { - shapes.interruptPaint(); - } - } - - /** - * Sets a page watermark implementation to be painted on top of the page - * content. Watermark can be specified for each page or once by calling - * document.setWatermark(). - * - * @param watermarkCallback watermark implementation. - */ - public void setWatermarkCallback(WatermarkCallback watermarkCallback) { - this.watermarkCallback = watermarkCallback; - } - - /** - * Paints the contents of this page to the graphics context using - * the specified rotation, zoom, rendering hints and page boundary. - * - * @param g graphics context to which the page content will be painted. - * @param renderHintType Constant specified by the GraphicsRenderingHints class. - * There are two possible entries, SCREEN and PRINT, each with configurable - * rendering hints settings. - * @param boundary Constant specifying the page boundary to use when - * painting the page content. - * @param userRotation Rotation factor, in degrees, to be applied to the rendered page - * @param userZoom Zoom factor to be applied to the rendered page - */ - public void paint(Graphics g, int renderHintType, final int boundary, - float userRotation, float userZoom) throws InterruptedException { - paint(g, renderHintType, boundary, userRotation, userZoom, true, true); - } - - /** - * Paints the contents of this page to the graphics context using - * the specified rotation, zoom, rendering hints and page boundary. - * - * @param g graphics context to which the page content will be painted. - * @param renderHintType Constant specified by the GraphicsRenderingHints class. - * There are two possible entries, SCREEN and PRINT, each with configurable - * rendering hints settings. - * @param boundary Constant specifying the page boundary to use when - * painting the page content. - * @param userRotation Rotation factor, in degrees, to be applied to the rendered page - * @param userZoom Zoom factor to be applied to the rendered page - * @param paintAnnotations true enables the painting of page annotations. False - * paints no annotations for a given page. - * @param paintSearchHighlight true enables the painting of search highlight - * state of text object. The search controller can - * be used to easily search and add highlighted state - * for search terms. - */ - public void paint(Graphics g, int renderHintType, final int boundary, - float userRotation, float userZoom, - boolean paintAnnotations, boolean paintSearchHighlight) throws InterruptedException { - if (!inited) { - // make sure we don't do a page init on the awt thread in the viewer - // ri, let the - return; - } - - Graphics2D g2 = (Graphics2D) g; - GraphicsRenderingHints grh = GraphicsRenderingHints.getDefault(); - g2.setRenderingHints(grh.getRenderingHints(renderHintType)); - - AffineTransform at = getPageTransform(boundary, userRotation, userZoom); - g2.transform(at); - - // Store graphic context state before page content is painted - AffineTransform prePagePaintState = g2.getTransform(); - - PRectangle pageBoundary = getPageBoundary(boundary); - float x = 0 - pageBoundary.x; - float y = 0 - (pageBoundary.y - pageBoundary.height); - - // Draw the (typically white) background - Color backgroundColor = grh.getPageBackgroundColor(renderHintType); - if (backgroundColor != null) { - g2.setColor(backgroundColor); - g2.fillRect((int) (0 - x), - (int) (0 - y), - (int) pageBoundary.width, - (int) pageBoundary.height); - } - - // We have to impose a page clip because some documents don't separate - // pages into separate Page objects, but instead reuse the Page object, - // but with a different clip - // And we can't stomp over the clip, because the PageView might be - // trying to only draw a portion of the page for performance, or - // other reasons - Rectangle2D rect = new Rectangle2D.Double(-x, -y, pageBoundary.width, pageBoundary.height); - Shape oldClip = g2.getClip(); - if (oldClip == null) { - g2.setClip(rect); - } else { - Area area = new Area(oldClip); - area.intersect(new Area(rect)); - g2.setClip(area); - } - - paintPageContent(g2, renderHintType, userRotation, userZoom, paintAnnotations, paintSearchHighlight); - - // one last repaint, just to be sure - notifyPaintPageListeners(); - - // apply old graphics context state, to more accurately paint water mark - g2.setTransform(prePagePaintState); - if (watermarkCallback != null) { - watermarkCallback.paintWatermark(g, this, renderHintType, - boundary, userRotation, userZoom); - } - - } - - /** - * Paints the contents of this page to the graphics context using - * the specified rotation, zoom, rendering hints. - *

- * The drawing commands that are issued on the given graphics context will use coordinates - * in PDF user coordinate space. It is the responsibility of the caller of this method - * to setup the graphics context to correctly interpret these coordinates. - * - * @param g graphics context to which the page content will be painted. - * @param renderHintType Constant specified by the GraphicsRenderingHints class. - * There are two possible entries, SCREEN and PRINT, each with configurable - * rendering hints settings. - * @param userRotation Rotation factor, in degrees, to be applied to the rendered page - * @param userZoom Zoom factor to be applied to the rendered page - * @param paintAnnotations true enables the painting of page annotations. False - * paints no annotations for a given page. - * @param paintSearchHighlight true enables the painting of search highlight - * state of text object. The search controller can - * be used to easily search and add highlighted state - * for search terms. - */ - public void paintPageContent(Graphics g, int renderHintType, float userRotation, float userZoom, - boolean paintAnnotations, boolean paintSearchHighlight) throws InterruptedException { - if (!inited) { - init(); - } - - paintPageContent(((Graphics2D) g), renderHintType, userRotation, userZoom, paintAnnotations, paintSearchHighlight); - } - - private void paintPageContent(Graphics2D g2, int renderHintType, float userRotation, float userZoom, - boolean paintAnnotations, boolean paintSearchHighlight) throws InterruptedException { - // draw page content - if (shapes != null) { - pagePainted = false; - notifyPagePaintingStarted(shapes.getShapesCount()); - AffineTransform pageTransform = g2.getTransform(); - Shape pageClip = g2.getClip(); - - shapes.setPageParent(this); - shapes.paint(g2); - shapes.setPageParent(null); - - g2.setTransform(pageTransform); - g2.setClip(pageClip); - } else { - notifyPagePaintingStarted(0); - } - // paint annotations if available and desired. - if (annotations != null && paintAnnotations) { - float totalRotation = getTotalRotation(userRotation); - int num = annotations.size(); - Annotation annotation; - for (int i = 0; i < num; i++) { - annotation = annotations.get(i); - annotation.render(g2, renderHintType, totalRotation, userZoom, false); - } - } - // paint search highlight values - if (paintSearchHighlight) { - PageText pageText = getViewText(); - if (pageText != null) { - //g2.setComposite(BlendComposite.getInstance(BlendComposite.BlendingMode.MULTIPLY, 1.0f)); - g2.setComposite(AlphaComposite.getInstance( - AlphaComposite.SRC_OVER, - SELECTION_ALPHA)); - // paint the sprites - GeneralPath textPath; - // iterate over the data structure. - if (pageText.getPageLines() != null) { - for (LineText lineText : pageText.getPageLines()) { - if (lineText != null) { - for (WordText wordText : lineText.getWords()) { - // paint whole word - if (wordText.isHighlighted()) { - textPath = new GeneralPath(wordText.getBounds()); - g2.setColor(highlightColor); - g2.fill(textPath); - } else { - for (GlyphText glyph : wordText.getGlyphs()) { - if (glyph.isHighlighted()) { - textPath = new GeneralPath(glyph.getBounds()); - g2.setColor(highlightColor); - g2.fill(textPath); - } - } - } - } - } - } - } - //g2.setComposite(BlendComposite.getInstance(BlendComposite.BlendingMode.NORMAL, 1.0f)); - } - } - pagePainted = true; - // painting is complete interrupted or not. - if (shapes != null) { - notifyPagePaintingEnded(shapes.isInterrupted()); - } else { - notifyPagePaintingEnded(false); - } - // one last repaint, just to be sure - notifyPaintPageListeners(); - // check image count if no images we are done. - if (imageCount == 0 || (pageInitialized && pagePainted)) { - notifyPageLoadingEnded(); - } - } - - /** - * The Java Graphics coordinate system has the origin at the top-left - * of the screen, with Y values increasing as one moves down the screen. - * The PDF coordinate system has the origin at the bottom-left of the - * document, with Y values increasing as one moved up the document. - * As well, PDFs can be displayed both rotated and zoomed. - * This method gives an AffineTransform which can be passed to - * java.awt.Graphics2D.transform(AffineTransform) so that one can then - * use that Graphics2D in the user-perspective PDF coordinate space. - * - * @param boundary Constant specifying the page boundary to use when - * painting the page content. - * @param userRotation Rotation factor, in degrees, to be applied to the rendered page - * @param userZoom Zoom factor to be applied to the rendered page - * @return AffineTransform for translating from the rotated and zoomed PDF - * coordinate system to the Java Graphics coordinate system - */ - public AffineTransform getPageTransform(final int boundary, - float userRotation, - float userZoom) { - AffineTransform at = new AffineTransform(); - - Rectangle2D.Double boundingBox = getBoundingBox(boundary, userRotation, userZoom); - at.translate(0, boundingBox.getHeight()); - - // setup canvas for PDF document orientation - at.scale(1, -1); - - at.scale(userZoom, userZoom); - - float totalRotation = getTotalRotation(userRotation); - PRectangle pageBoundary = getPageBoundary(boundary); - - at = Page.getPageRotation(at, totalRotation, pageBoundary.width, pageBoundary.height); - - // translate crop lower left corner back to where media box corner was - float x = 0 - pageBoundary.x; - float y = 0 - (pageBoundary.y - pageBoundary.height); - at.translate(x, y); - - return at; - } - - public static AffineTransform getPageRotation(AffineTransform at, double totalRotation, float width, float height){ - if (totalRotation == 0) { - // do nothing - } else if (totalRotation == 90) { - at.translate(height, 0); - } else if (totalRotation == 180) { - at.translate(width, height); - } else if (totalRotation == 270) { - at.translate(0, width); - } else { - if (totalRotation > 0 && totalRotation < 90) { - double xShift = width * Math.cos(Math.toRadians(90 - totalRotation)); - at.translate(xShift, 0); - } else if (totalRotation > 90 && totalRotation < 180) { - double rad = Math.toRadians(180 - totalRotation); - double cosRad = Math.cos(rad); - double sinRad = Math.sin(rad); - double xShift = height * sinRad + width * cosRad; - double yShift = height * cosRad; - at.translate(xShift, yShift); - } else if (totalRotation > 180 && totalRotation < 270) { - double rad = Math.toRadians(totalRotation - 180); - double cosRad = Math.cos(rad); - double sinRad = Math.sin(rad); - double xShift = width * cosRad; - double yShift = width * sinRad + height * cosRad; - at.translate(xShift, yShift); - } else if (totalRotation > 270 && totalRotation < 360) { - double yShift = width * Math.cos(Math.toRadians(totalRotation - 270)); - at.translate(0, yShift); - } - } - // apply rotation on canvas, convert to Radians - at.rotate(totalRotation * Math.PI / 180.0); - - return at; - } - - /** - * This method returns a Shape that represents the outline of this Page, - * after being rotated and zoomed. It is used for clipping, and drawing - * borders around the page rendering onscreen. - * - * @param boundary Constant specifying the page boundary to use - * @param userRotation Rotation factor, in degrees, to be applied - * @param userZoom Zoom factor to be applied - * @return Shape outline of the rotated and zoomed portion of this Page - * corresponding to the specified boundary - */ - public Shape getPageShape(int boundary, float userRotation, float userZoom) { - AffineTransform at = getPageTransform(boundary, userRotation, userZoom); - PRectangle pageBoundary = getPageBoundary(boundary); - float x = 0 - pageBoundary.x; - float y = 0 - (pageBoundary.y - pageBoundary.height); - Rectangle2D rect = new Rectangle2D.Double(-x, -y, pageBoundary.width, pageBoundary.height); - GeneralPath path = new GeneralPath(rect); - return path.createTransformedShape(at); - } - - /** - * Adds an annotation that was previously added to the document. It is - * assumed that the annotation has a valid object reference. This - * is commonly used with the undo/redo state manager in the RI. Use - * the method @link{#createAnnotation} for creating new annotations. - * - * @param newAnnotation annotation object to add - * @return reference to annotation that was added. - */ - @SuppressWarnings("unchecked") - public Annotation addAnnotation(Annotation newAnnotation) { - - // make sure the page annotations have been initialized. - if (!inited) { - try { - initPageAnnotations(); - } catch (InterruptedException e) { - logger.warning("Annotation Initialization interrupted"); - } - } - - StateManager stateManager = library.getStateManager(); - - List annotations = library.getArray(entries, ANNOTS_KEY); - boolean isAnnotAReference = library.isReference(entries, ANNOTS_KEY); - - // does the page not already have an annotations or if the annots - // dictionary is indirect. If so we have to add the page to the state - // manager - if (!isAnnotAReference && annotations != null) { - // get annots array from page - // update annots dictionary with new annotations reference, - annotations.add(newAnnotation.getPObjectReference()); - // add the page as state change - stateManager.addChange( - new PObject(this, this.getPObjectReference())); - } else if (isAnnotAReference && annotations != null) { - // get annots array from page - // update annots dictionary with new annotations reference, - annotations.add(newAnnotation.getPObjectReference()); - // add the annotations reference dictionary as state has changed - stateManager.addChange( - new PObject(annotations, library.getObjectReference( - entries, ANNOTS_KEY))); - } - // we need to add the a new annots reference - else { - List annotsVector = new ArrayList(4); - annotsVector.add(newAnnotation.getPObjectReference()); - - // create a new Dictionary of annotations using an external reference - PObject annotsPObject = new PObject(annotsVector, - stateManager.getNewReferencNumber()); - - // add the new dictionary to the page - entries.put(ANNOTS_KEY, annotsPObject.getReference()); - // add it to the library so we can resolve the reference - library.addObject(annotsVector, annotsPObject.getReference()); - - // add the page and the new dictionary to the state change - stateManager.addChange( - new PObject(this, this.getPObjectReference())); - stateManager.addChange(annotsPObject); - - this.annotations = new ArrayList(); - } - - // update parent page reference. - newAnnotation.getEntries().put(Annotation.PARENT_PAGE_KEY, - this.getPObjectReference()); - - // add the annotations to the parsed annotations list - this.annotations.add(newAnnotation); - - // add the new annotations to the library - library.addObject(newAnnotation, newAnnotation.getPObjectReference()); - - // finally add the new annotations to the state manager - stateManager.addChange(new PObject(newAnnotation, newAnnotation.getPObjectReference())); - - // return to caller for further manipulations. - return newAnnotation; - } - - /** - * Deletes the specified annotation instance from his page. If the - * annotation was original then either the page or the annot ref object - * is also added to the state manager. If the annotation was new then - * we just have to update the page and or annot reference as the objects - * will already be in the state manager. - * - * @param annot annotation to delete. - */ - public void deleteAnnotation(Annotation annot) { - - // make sure the page annotations have been initialized. - if (!inited) { - try { - initPageAnnotations(); - } catch (InterruptedException e) { - logger.warning("Annotation Initialization interupted"); - } - } - - StateManager stateManager = library.getStateManager(); - - Object annots = getObject(ANNOTS_KEY); - boolean isAnnotAReference = - library.isReference(entries, ANNOTS_KEY); - - // mark the item as deleted so the state manager can clean up the reference. - annot.setDeleted(true); - Stream nAp = annot.getAppearanceStream(); - if (nAp != null) { - nAp.setDeleted(true); - // find the xobjects font resources. - Object tmp = library.getObject(nAp.entries, RESOURCES_KEY); - if (tmp instanceof Resources) { - Resources resources = (Resources) tmp; - // only remove our font instance, if we remove another font we would have - // to check the document to see if it was used anywhere else. - Dictionary font = resources.getFont(FreeTextAnnotation.EMBEDDED_FONT_NAME); - if (font != null) { - font.setDeleted(true); - } - } - } - - // check to see if this is an existing annotations, if the annotations - // is existing then we have to mark either the page or annot ref as changed. - if (!annot.isNew() && !isAnnotAReference) { - // add the page as state change - stateManager.addChange( - new PObject(this, this.getPObjectReference())); - } - // if not new and annot is a ref, we have to add annot ref as changed. - else if (!annot.isNew() && isAnnotAReference) { - stateManager.addChange( - new PObject(annots, library.getObjectReference( - entries, ANNOTS_KEY))); - } - // if new annotation, then we can remove it from the state manager. - else if (annot.isNew()) { - stateManager.removeChange( - new PObject(annot, annot.getPObjectReference())); - // check for an appearance stream which also needs to be removed. - if (nAp != null) { - stateManager.removeChange(new PObject( - nAp, nAp.getPObjectReference())); - library.removeObject(nAp.getPObjectReference()); - } - } - // removed the annotations from the annots vector - if (annots instanceof List) { - // update annots dictionary with new annotations reference, - ((List) annots).remove(annot.getPObjectReference()); - } - - // remove the annotations form the annotation cache in the page object - if (annotations != null) { - annotations.remove(annot); - } - // finally remove it from the library to free up the memory - library.removeObject(annot.getPObjectReference()); - } - - /** - * Updates the annotation associated with this page. If the annotation - * is not in this page then the annotation is no added. - * - * @param annotation annotation object that should be updated for this page. - * @return true if the update was successful, false otherwise. - */ - @SuppressWarnings("unchecked") - public boolean updateAnnotation(Annotation annotation) { - // bail on null annotations - if (annotation == null) { - return false; - } - - // make sure the page annotations have been initialized. - if (!inited) { - try { - initPageAnnotations(); - } catch (InterruptedException e) { - logger.warning("Annotation Initialization interrupted"); - } - } - - StateManager stateManager = library.getStateManager(); - // if we are doing an update we have at least on annot - List annotations = (List) - library.getObject(entries, ANNOTS_KEY); - - // make sure annotations is in part of page. - boolean found = false; - for (Object ref : annotations) { - if (ref.equals(annotation.getPObjectReference())) { - found = true; - break; - } - } - if (!found) { - return false; - } - - // check the state manager for an instance of this object - if (stateManager.contains(annotation.getPObjectReference())) { - // if found we just have to re add the object, foot work around - // page and annotations creation has already been done. - stateManager.addChange( - new PObject(annotation, annotation.getPObjectReference())); - return true; - } - // we have to do the checks for page and annot dictionary entry. - else { - // update parent page reference. - annotation.getEntries().put(Annotation.PARENT_PAGE_KEY, - this.getPObjectReference()); - - // add the annotations to the parsed annotations list - this.annotations.add(annotation); - - // add the new annotations to the library - library.addObject(annotation, annotation.getPObjectReference()); - - // finally add the new annotations to the state manager - stateManager.addChange(new PObject(annotation, annotation.getPObjectReference())); - - return true; - } - } - - /** - * Gets a reference to the page's parent page tree. A reference can be resolved - * by the Library class. - * - * @return reference to parent page tree. - * @see org.icepdf.core.util.Library - */ - protected Reference getParentReference() { - return (Reference) entries.get(PARENT_KEY); - } - - /** - * Gets the page's parent page tree. - * - * @return parent page tree. - */ - public PageTree getParent() { - // retrieve a pointer to the pageTreeParent - Object tmp = library.getObject(entries, PARENT_KEY); - if (tmp instanceof PageTree) { - return (PageTree) tmp; - } else if (tmp instanceof HashMap) { - return new PageTree(library, (HashMap) tmp); - } else { - return null; - } - } - - /** - * Get the width and height that the page can occupy, given the userRotation, - * page's own pageRotation and cropBox boundary. The page's default zoom of - * 1.0f is used. - * - * @param userRotation Rotation factor specified by the user under which the - * page will be rotated. - * @return Dimension of width and height of the page represented in point - * units. - * @see #getSize(float, float) - */ - public PDimension getSize(float userRotation) { - return getSize(BOUNDARY_CROPBOX, userRotation, 1.0f); - } - - /** - * Get the width and height that the page can occupy, given the userRotation, - * userZoom, page's own pageRotation and cropBox boundary. - * - * @param userRotation rotation factor specified by the user under which the - * page will be rotated. - * @param userZoom zoom factor specified by the user under which the page will - * be rotated. - * @return Dimension of width and height of the page represented in point units. - */ - public PDimension getSize(float userRotation, float userZoom) { - return getSize(BOUNDARY_CROPBOX, userRotation, userZoom); - } - - /** - * Get the width and height that the page can occupy, given the userRotation, - * userZoom, page's own pageRotation and cropBox boundary. - * - * @param boundary boundary constant to specify which boundary to respect when - * calculating the page's size. - * @param userRotation rotation factor specified by the user under which the - * page will be rotated. - * @param userZoom zoom factor specified by the user under which the page will - * be rotated. - * @return Dimension of width and height of the page represented in point units. - * or null if the boundary box is not defined. - */ - public PDimension getSize(final int boundary, float userRotation, float userZoom) { - float totalRotation = getTotalRotation(userRotation); - PRectangle pageBoundary = getPageBoundary(boundary); - float width = pageBoundary.width * userZoom; - float height = pageBoundary.height * userZoom; - // No rotation, or flipped upside down - if (totalRotation == 0 || totalRotation == 180) { - // Do nothing - } - // Rotated sideways - else if (totalRotation == 90 || totalRotation == 270) { - float temp = width; - // flip with and height. - width = height; - height = temp; - } - // Arbitrary rotation - else { - AffineTransform at = new AffineTransform(); - double radians = Math.toRadians(totalRotation); - at.rotate(radians); - Rectangle2D.Double boundingBox = new Rectangle2D.Double(0.0, 0.0, 0.0, 0.0); - Point2D.Double src = new Point2D.Double(); - Point2D.Double dst = new Point2D.Double(); - src.setLocation(0.0, height); // Top left - at.transform(src, dst); - boundingBox.add(dst); - src.setLocation(width, height); // Top right - at.transform(src, dst); - boundingBox.add(dst); - src.setLocation(0.0, 0.0); // Bottom left - at.transform(src, dst); - boundingBox.add(dst); - src.setLocation(width, 0.0); // Bottom right - at.transform(src, dst); - boundingBox.add(dst); - width = (float) boundingBox.getWidth(); - height = (float) boundingBox.getHeight(); - } - return new PDimension(width, height); - } - - /** - * Get the bounding box that the page can occupy, given the userRotation and - * page's own pageRotation. The boundary of BOUNDARY_CROPBOX, and the default - * zoom of 1.0f are assumed. - * - * @param userRotation Rotation factor specified by the user under which the - * page will be rotated. - * @return Dimension of width and height of the page represented in point - * units. - * @see #getSize(float, float) - */ - public Rectangle2D.Double getBoundingBox(float userRotation) { - return getBoundingBox(BOUNDARY_CROPBOX, userRotation, 1.0f); - } - - /** - * Get the bounding box that the page can occupy, given the userRotation, - * userZoom, page's own pageRotation. - * - * @param userRotation rotation factor specified by the user under which the - * page will be rotated. - * @param userZoom zoom factor specified by the user under which the page will - * be rotated. - * @return Rectangle encompassing the page represented in point units. - */ - public Rectangle2D.Double getBoundingBox(float userRotation, float userZoom) { - return getBoundingBox(BOUNDARY_CROPBOX, userRotation, userZoom); - } - - /** - * Get the bounding box that the page can occupy, given the userRotation, - * userZoom, page's own pageRotation and cropBox boundary. - * - * @param boundary boundary constant to specify which boundary to respect when - * calculating the page's size. - * @param userRotation rotation factor specified by the user under which the - * page will be rotated. - * @param userZoom zoom factor specified by the user under which the page will - * be rotated. - * @return Rectangle encompassing the page represented in point units. - */ - public Rectangle2D.Double getBoundingBox(final int boundary, float userRotation, float userZoom) { - float totalRotation = getTotalRotation(userRotation); - PRectangle pageBoundary = getPageBoundary(boundary); - float width = pageBoundary.width * userZoom; - float height = pageBoundary.height * userZoom; - - AffineTransform at = new AffineTransform(); - double radians = Math.toRadians(totalRotation); - at.rotate(radians); - Rectangle2D.Double boundingBox = new Rectangle2D.Double(0.0, 0.0, 0.0, 0.0); - Point2D.Double src = new Point2D.Double(); - Point2D.Double dst = new Point2D.Double(); - src.setLocation(0.0, height); // Top left - at.transform(src, dst); - boundingBox.add(dst); - src.setLocation(width, height); // Top right - at.transform(src, dst); - boundingBox.add(dst); - src.setLocation(0.0, 0.0); // Bottom left - at.transform(src, dst); - boundingBox.add(dst); - src.setLocation(width, 0.0); // Bottom right - at.transform(src, dst); - boundingBox.add(dst); - - return boundingBox; - } - - /** - * Utility method for applying the page boundary rules. If no matching specifiedBox type is found then - * the BOUNDARY_CROPBOX bound will be returned. - * - * @param specifiedBox page boundary constant - * @return bounds of page after the chain of rules have been applied. - */ - public PRectangle getPageBoundary(final int specifiedBox) { - PRectangle userSpecifiedBox; - // required property - if (specifiedBox == BOUNDARY_MEDIABOX) { - userSpecifiedBox = (PRectangle) getMediaBox(); - } - // required property - else if (specifiedBox == BOUNDARY_CROPBOX) { - userSpecifiedBox = (PRectangle) getCropBox(); - } - // optional, default value is crop box - else if (specifiedBox == BOUNDARY_BLEEDBOX) { - userSpecifiedBox = (PRectangle) getBleedBox(); - } - // optional, default value is crop box - else if (specifiedBox == BOUNDARY_TRIMBOX) { - userSpecifiedBox = (PRectangle) getTrimBox(); - } - // optional, default value is crop box - else if (specifiedBox == BOUNDARY_ARTBOX) { - userSpecifiedBox = (PRectangle) getArtBox(); - } - // encase of bad usage, default to crop box - else { - userSpecifiedBox = (PRectangle) getCropBox(); - } - - // just in case, make sure we return a non null boundary, and the - // media box is marked as required and should be in either this dictionary - // or a parent's - if (userSpecifiedBox == null) { - userSpecifiedBox = (PRectangle) getMediaBox(); - } - - return userSpecifiedBox; - } - - /** - * Returns a summary of the page dictionary entries. - * - * @return dictionary entries. - */ - public String toString() { - return "PAGE= " + entries.toString(); - } - - /** - * Gets the total rotation factor of the page after applying a user rotation - * factor. This method will normalize rotation factors to be in the range - * of 0 to 360 degrees. - * - * @param userRotation rotation factor to be applied to page - * @return Total Rotation, representing pageRotation + user rotation - * factor applied to the whole document. - */ - public float getTotalRotation(float userRotation) { - float totalRotation = getPageRotation() + userRotation; - - // correct to keep in rotation in 360 range. - totalRotation %= 360; - - if (totalRotation < 0) - totalRotation += 360; - - // If they calculated the degrees from radians or whatever, - // then we need to make our even rotation comparisons work - if (totalRotation >= -0.001f && totalRotation <= 0.001f) - return 0.0f; - else if (totalRotation >= 89.99f && totalRotation <= 90.001f) - return 90.0f; - else if (totalRotation >= 179.99f && totalRotation <= 180.001f) - return 180.0f; - else if (totalRotation >= 269.99f && totalRotation <= 270.001f) - return 270.0f; - - return totalRotation; - } - - private float getPageRotation() { - // Get the pages default orientation if available, if not defined - // then it is zero. - Object tmpRotation = library.getObject(entries, ROTATE_KEY); - if (tmpRotation != null) { - pageRotation = ((Number) tmpRotation).floatValue(); -// System.out.println("Page Rotation " + pageRotation); - } - // check parent to see if value has been set - else { - PageTree pageTree = getParent(); - while (pageTree != null) { - if (pageTree.isRotationFactor) { - pageRotation = pageTree.rotationFactor; - break; - } - pageTree = pageTree.getParent(); - } - } - // PDF specifies rotation as clockwise, but Java2D does it - // counter-clockwise, so normalise it to Java2D - pageRotation = 360 - pageRotation; - pageRotation %= 360; -// System.out.println("New Page Rotation " + pageRotation); - return pageRotation; - } - - /** - * Gets all annotation information associated with this page. Each entry - * in the vector represents one annotation. The size of the vector represents - * the total number of annotations associated with the page. - * - * @return annotation associated with page; null, if there are no annotations. - */ - public List getAnnotations() { - if (!inited) { - try { - initPageAnnotations(); - } catch (InterruptedException e) { - logger.finer("Interrupt exception getting annotations. "); - } - } - return annotations; - } - - /** - * Returns the decoded content stream for this page instance. A page instance - * can have more then one content stream associated with it. - * - * @return An array of decoded content stream. Each index in the array - * represents one content stream. Null return and null String array - * values are possible. - */ - public String[] getDecodedContentSteam() { - // Some PDF's won't have any content for a given page. - try { - initPageContents(); - - if (contents == null) { - return null; - } - String[] decodedContentStream = new String[contents.size()]; - int i = 0; - for (Stream stream : contents) { - InputStream input = stream.getDecodedByteArrayInputStream(); - String content; - if (input instanceof SeekableInput) { - content = Utils.getContentFromSeekableInput((SeekableInput) input, false); - } else { - InputStream[] inArray = new InputStream[]{input}; - content = Utils.getContentAndReplaceInputStream(inArray, false); - } - decodedContentStream[i] = content; - input.close(); - i++; - } - return decodedContentStream; - } catch (InterruptedException e) { - logger.log(Level.SEVERE, "Error initializing page Contents.", e); - } catch (IOException e) { - logger.log(Level.SEVERE, "Error closing content stream"); - } - return null; - } - - - /** - * Gets the media box boundary defined by this page. The media box is a - * required page entry and can be inherited from its parent page tree. - * - * @return media box boundary in user space units. - */ - public Rectangle2D.Float getMediaBox() { - if (mediaBox != null) { - return mediaBox; - } - // add all of the pages media box dimensions to a vector and process - List boxDimensions = (List) (library.getObject(entries, MEDIABOX_KEY)); - if (boxDimensions != null) { - mediaBox = new PRectangle(boxDimensions); - } - // If mediaBox is null check with the parent pages, as media box is inheritable - if (mediaBox == null) { - PageTree pageTree = getParent(); - while (pageTree != null && mediaBox == null) { - mediaBox = pageTree.getMediaBox(); - if (mediaBox == null) { - pageTree = pageTree.getParent(); - } - } - } - // last resort - if (mediaBox == null) { - mediaBox = new PRectangle(new Point.Float(0, 0), new Point.Float(612, 792)); - } - return mediaBox; - } - - /** - * Gets the crop box boundary defined by this page. The media box is a - * required page entry and can be inherited from its parent page tree. - * - * @return crop box boundary in user space units. - */ - public Rectangle2D.Float getCropBox() { - if (cropBox != null) { - return cropBox; - } - // add all of the pages crop box dimensions to a vector and process - List boxDimensions = (List) (library.getObject(entries, CROPBOX_KEY)); - if (boxDimensions != null) { - cropBox = new PRectangle(boxDimensions); - } - // If cropbox is null check with the parent pages, as media box is inheritable - boolean isParentCropBox = false; - if (cropBox == null) { - PageTree pageTree = getParent(); - while (pageTree != null && cropBox == null) { - if (pageTree.getCropBox() == null) { - break; - } - cropBox = pageTree.getCropBox(); - if (cropBox != null) { - isParentCropBox = true; - } - pageTree = pageTree.getParent(); - } - } - // Default value of the cropBox is the MediaBox if not set implicitly - PRectangle mediaBox = (PRectangle) getMediaBox(); - if ((cropBox == null || isParentCropBox) && mediaBox != null) { - cropBox = (PRectangle) mediaBox.clone(); - } else if (cropBox != null && mediaBox != null) { - // PDF 1.5 spec states that the media box should be intersected with the - // crop box to get the new box. But we only want to do this if the - // cropBox is not the same as the mediaBox - cropBox = mediaBox.createCartesianIntersection(cropBox); - } - return cropBox; - } - - /** - * Gets the art box boundary defined by this page. The art box is a - * required page entry and can be inherited from its parent page tree. - * - * @return art box boundary in user space units. - */ - public Rectangle2D.Float getArtBox() { - if (artBox != null) { - return artBox; - } - // get the art box vector value - List boxDimensions = (List) (library.getObject(entries, ARTBOX_KEY)); - if (boxDimensions != null) { - artBox = new PRectangle(boxDimensions); - } - // Default value of the artBox is the bleed if not set implicitly - if (artBox == null) { - artBox = (PRectangle) getCropBox(); - } - return artBox; - } - - /** - * Gets the bleed box boundary defined by this page. The bleed box is a - * required page entry and can be inherited from its parent page tree. - * - * @return bleed box boundary in user space units. - */ - public Rectangle2D.Float getBleedBox() { - if (bleedBox != null) { - return bleedBox; - } - // get the art box vector value - List boxDimensions = (List) (library.getObject(entries, BLEEDBOX_KEY)); - if (boxDimensions != null) { - bleedBox = new PRectangle(boxDimensions); -// System.out.println("Page - BleedBox " + bleedBox); - } - // Default value of the bleedBox is the bleed if not set implicitly - if (bleedBox == null) { - bleedBox = (PRectangle) getCropBox(); - } - return bleedBox; - } - - /** - * Gets the trim box boundary defined by this page. The trim box is a - * required page entry and can be inherited from its parent page tree. - * - * @return trim box boundary in user space units. - */ - public Rectangle2D.Float getTrimBox() { - if (trimBox != null) { - return trimBox; - } - // get the art box vector value - List boxDimensions = (List) (library.getObject(entries, TRIMBOX_KEY)); - if (boxDimensions != null) { - trimBox = new PRectangle(boxDimensions); -// System.out.println("Page - TrimBox " + trimBox); - } - // Default value of the trimBox is the bleed if not set implicitly - if (trimBox == null) { - trimBox = (PRectangle) getCropBox(); - } - return trimBox; - } - - /** - * Gest the PageText data structure for this page. PageText is made up - * of lines, words and glyphs which can be used for searches, text extraction - * and text highlighting. The coordinates system has been normalized - * to page space. - * - * @return list of text sprites for the given page. - */ - public PageText getViewText() throws InterruptedException { - if (!inited) { - init(); - } - if (shapes != null) { - return shapes.getPageText(); - } else { - return null; - } - } - - /** - * Gets the Shapes object associated with this Page. The return value can be - * null depending on the PDF encoding. The init() method should be called to - * insure the the page parsing and resource loading has completed. This method - * will not call init() if the page has not yet be initialized. - * - * @return shapes object associated with this Page, can be null. - */ - public Shapes getShapes() { - return shapes; - } - - /** - * Gets the PageText data structure for this page using an accelerated - * parsing technique that ignores some text elements. This method should - * be used for straight text extraction. - * - * @return vector of Strings of all text objects inside the specified page. - */ - public synchronized PageText getText() throws InterruptedException { - - // we only do this once per page - if (inited) { - if (shapes != null && shapes.getPageText() != null) { - return shapes.getPageText(); - } - } - - Shapes textBlockShapes = new Shapes(); - - /** - * Finally iterate through the contents vector and concat all of the - * the resouse streams together so that the contant parser can - * go to town and build all of the pages shapes. - */ - if (contents == null) { - // Get the value of the page's content entry - initPageContents(); - } - - if (resources == null) { - // get pages resources - initPageResources(); - } - if (contents != null) { - try { - - ContentParser cp = ContentParserFactory.getInstance() - .getContentParser(library, resources); - byte[][] streams = new byte[contents.size()][]; - for (int i = 0, max = contents.size(); i < max; i++) { - streams[i] = contents.get(i).getDecodedStreamBytes(); - } - textBlockShapes = cp.parseTextBlocks(streams); - // print off any fuzz left on the stack - if (logger.isLoggable(Level.FINER)) { - Stack stack = cp.getStack(); - while (!stack.isEmpty()) { - String tmp = stack.pop().toString(); - if (logger.isLoggable(Level.FINE)) { - logger.fine("STACK=" + tmp); - } - } - } - } catch (Exception e) { - logger.log(Level.FINE, "Error getting page text.", e); - } - } - if (textBlockShapes.getPageText() != null) { - return textBlockShapes.getPageText(); - } else { - return null; - } - } - - /** - * Gets the zero based page index of this page as define by the order - * in the page tree. This does not correspond to a page's label name. - * - * @return zero base page index. - */ - public int getPageIndex() { - return pageIndex; - } - - /** - * Gets the xObject image found for this page which does not include - * any inline images. - * - * @return xObject image count. - */ - public int getImageCount() { - return imageCount; - } - - /** - * Returns true if the page is initialized, this is different then init(), - * as it tracks if the page has started initialization and we don't want to - * do that again, in this case the init() method has completely finished, - * minus any image loading threads. - * - * @return true if page has completed initialization otherwise false. - */ - public boolean isPageInitialized() { - return pageInitialized; - } - - /** - * Returns true if the page painting is complete regardless if it was - * interrupted. - * - * @return true if the page painting is complete. - */ - public boolean isPagePainted() { - return pagePainted; - } - - protected void setPageIndex(int pageIndex) { - this.pageIndex = pageIndex; - } - - /** - * Gets a vector of Images where each index represents an image inside - * this page. - * - * @return vector of Images inside the current page - */ - public synchronized List getImages() throws InterruptedException { - if (!inited) { - init(); - } - return shapes.getImages(); - } - - public Resources getResources() { - return resources; - } - - public void addPaintPageListener(PaintPageListener listener) { - // add a listener if it is not already registered - synchronized (paintPageListeners) { - if (!paintPageListeners.contains(listener)) { - paintPageListeners.add(listener); - } - } - } - - public void removePaintPageListener(PaintPageListener listener) { - // remove a listener if it is already registered - synchronized (paintPageListeners) { - if (paintPageListeners.contains(listener)) { - paintPageListeners.remove(listener); - } - - } - } - - public List getPageLoadingListeners() { - return pageLoadingListeners; - } - - public void addPageProcessingListener(PageLoadingListener listener) { - // add a listener if it is not already registered - synchronized (pageLoadingListeners) { - if (!pageLoadingListeners.contains(listener)) { - pageLoadingListeners.add(listener); - } - } - } - - public void removePageProcessingListener(PageLoadingListener listener) { - // remove a listener if it is already registered - synchronized (pageLoadingListeners) { - if (pageLoadingListeners.contains(listener)) { - pageLoadingListeners.remove(listener); - } - - } - } - - private void notifyPageLoadingStarted(int contentCount, int imageCount) { - PageLoadingEvent pageLoadingEvent = - new PageLoadingEvent(this, contentCount, imageCount); - PageLoadingListener client; - for (int i = pageLoadingListeners.size() - 1; i >= 0; i--) { - client = pageLoadingListeners.get(i); - client.pageLoadingStarted(pageLoadingEvent); - } - } - - private void notifyPageInitializationStarted() { - PageInitializingEvent pageLoadingEvent = - new PageInitializingEvent(this, false); - PageLoadingListener client; - for (int i = pageLoadingListeners.size() - 1; i >= 0; i--) { - client = pageLoadingListeners.get(i); - client.pageInitializationStarted(pageLoadingEvent); - } - } - - private void notifyPagePaintingStarted(int shapesCount) { - PagePaintingEvent pageLoadingEvent = - new PagePaintingEvent(this, shapesCount); - PageLoadingListener client; - for (int i = pageLoadingListeners.size() - 1; i >= 0; i--) { - client = pageLoadingListeners.get(i); - client.pagePaintingStarted(pageLoadingEvent); - } - } - - private void notifyPagePaintingEnded(boolean interrupted) { - pagePainted = true; - PagePaintingEvent pageLoadingEvent = - new PagePaintingEvent(this, interrupted); - PageLoadingListener client; - for (int i = pageLoadingListeners.size() - 1; i >= 0; i--) { - client = pageLoadingListeners.get(i); - client.pagePaintingEnded(pageLoadingEvent); - } - } - - private void notifyPageInitializationEnded(boolean interrupted) { - pageInitialized = true; - PageInitializingEvent pageLoadingEvent = - new PageInitializingEvent(this, interrupted); - PageLoadingListener client; - for (int i = pageLoadingListeners.size() - 1; i >= 0; i--) { - client = pageLoadingListeners.get(i); - client.pageInitializationEnded(pageLoadingEvent); - } - } - - protected void notifyPageLoadingEnded() { - - PageLoadingEvent pageLoadingEvent = - new PageLoadingEvent(this, inited); - PageLoadingListener client; - for (int i = pageLoadingListeners.size() - 1; i >= 0; i--) { - client = pageLoadingListeners.get(i); - client.pageLoadingEnded(pageLoadingEvent); - } - } - - public void notifyPaintPageListeners() { - // create the event object - PaintPageEvent evt = new PaintPageEvent(this); - - // fire the event to all listeners - PaintPageListener client; - for (int i = paintPageListeners.size() - 1; i >= 0; i--) { - client = paintPageListeners.get(i); - client.paintPage(evt); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PageTree.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PageTree.java deleted file mode 100644 index 038ebe71b1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/PageTree.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.graphics.WatermarkCallback; -import org.icepdf.core.util.Library; - -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.List; - -/** - *

This class represents a document's page tree which defines the ordering - * of pages in the document. The tree structure allows a user to quickly - * open a document containing thousands of pages. The tree contains nodes of - * two types, page tree nodes and page nodes, where page tree nodes are - * intermediate nodes and pages are leaves. A simple example of this tree structure - * is a single page tree node that references all of the document's page - * objects directly.

- *

- *

The page tree is accessible via the document catalog and can be traversed - * to display a desired page or extracts its content.

- * - * @see org.icepdf.core.pobjects.Page - * @see org.icepdf.core.pobjects.Catalog - * @since 2.0 - */ -public class PageTree extends Dictionary { - - public static final Name TYPE = new Name("Pages"); - public static final Name PARENT_KEY = new Name("Parent"); - public static final Name COUNT_KEY = new Name("Count"); - public static final Name MEDIABOX_KEY = new Name("MediaBox"); - public static final Name CROPBOX_KEY = new Name("CropBox"); - public static final Name KIDS_KEY = new Name("Kids"); - public static final Name ROTATE_KEY = new Name("Rotate"); - public static final Name RESOURCES_KEY = new Name("Resources"); - - // Number of leaf nodes - private int kidsCount = 0; - // vector of references to leafs - private List kidsReferences; - // vector of the pages associated with tree - private HashMap> kidsPageAndPages; - // pointer to parent page tree - private PageTree parent; - // initiated flag - private boolean inited; - // inheritable page boundary data. - private PRectangle mediaBox; - private PRectangle cropBox; - // inheritable Resources - private Resources resources; - // loaded resource flag, we can't use null check as some trees don't have - // resources. - private boolean loadedResources; - private WatermarkCallback watermarkCallback; - - /** - * Inheritable rotation factor by child pages. - */ - protected float rotationFactor = 0; - - /** - * Indicates that the PageTree has a rotation factor which should be respected. - */ - protected boolean isRotationFactor = false; - - /** - * Creates a new instance of a PageTree. - * - * @param l document library. - * @param h PageTree dictionary entries. - */ - public PageTree(Library l, HashMap h) { - super(l, h); - } - - /** - * Reset the pages initialized flag and as a result subsequent calls to - * this PageTree may trigger a call to init(). - */ - public void resetInitializedState() { - inited = false; - } - - /** - * Initiate the PageTree. - */ - public synchronized void init() { - if (inited) { - return; - } - - Object parentTree = library.getObject(entries, PARENT_KEY); - if (parentTree instanceof PageTree) { - parent = (PageTree) parentTree; - } - kidsCount = library.getNumber(entries, COUNT_KEY).intValue(); - kidsReferences = (List) library.getObject(entries, KIDS_KEY); - kidsPageAndPages = new HashMap>(kidsReferences.size()); - // Rotation is only respected if child pages do not have their own - // rotation value. - Object tmpRotation = library.getObject(entries, ROTATE_KEY); - if (tmpRotation != null) { - rotationFactor = ((Number) tmpRotation).floatValue(); - // mark that we have an inheritable value - isRotationFactor = true; - } - inited = true; - - } - - /** - * Gets the media box boundary defined by this page tree. The media box is a - * required page entry and can be inherited from its parent page tree. - * - * @return media box boundary in user space units. - */ - public PRectangle getMediaBox() { - if (!inited) { - init(); - } - - if (mediaBox != null) { - return mediaBox; - } - // add all of the pages media box dimensions to a vector and process - List boxDimensions = (List) (library.getObject(entries, MEDIABOX_KEY)); - if (boxDimensions != null) { - mediaBox = new PRectangle(boxDimensions); - } - // If mediaBox is null check with the parent pages, as media box is inheritable - if (mediaBox == null) { - PageTree pageTree = getParent(); - while (pageTree != null && mediaBox == null) { - mediaBox = pageTree.getMediaBox(); - if (mediaBox == null) { - pageTree = pageTree.getParent(); - } - } - } - return mediaBox; - } - - /** - * Gets the crop box boundary defined by this page tree. The media box is a - * required page entry and can be inherited from its parent page tree. - * - * @return crop box boundary in user space units. - */ - public PRectangle getCropBox() { - if (!inited) { - init(); - } - - if (cropBox != null) { - return cropBox; - } - // add all of the pages crop box dimensions to a vector and process - List boxDimensions = (List) (library.getObject(entries, CROPBOX_KEY)); - if (boxDimensions != null) { - cropBox = new PRectangle(boxDimensions); - } - // Default value of the cropBox is the MediaBox if not set implicitly - PRectangle mediaBox = getMediaBox(); - if (cropBox == null && mediaBox != null) { - cropBox = (PRectangle) mediaBox.clone(); - } else if (mediaBox != null) { - // PDF 1.5 spec states that the media box should be intersected with the - // crop box to get the new box. But we only want to do this if the - // cropBox is not the same as the mediaBox - cropBox = mediaBox.createCartesianIntersection(cropBox); - } - return cropBox; - } - - /** - * Gets the Resources defined by this PageTree. The Resources entry can - * be inherited by the child Page objects. - *

- * The caller is responsible for disposing of the returned Resources object. - * - * @return Resources associates with the PageTree - */ - public synchronized Resources getResources() { - // make sure we synchronize this to avoid a false resource grab. - if (!loadedResources) { - loadedResources = true; - resources = library.getResources(entries, RESOURCES_KEY); - } - return resources; - } - - /** - * Gets the page tree node that is the immediate parent of this one. - * - * @return parent page tree; null, if this is the root page tree. - */ - public PageTree getParent() { - return parent; - } - - /** - * Gets the page number of the page specifed by a reference. - * - * @param r reference to a page in the page tree. - * @return page number of the specified reference. If no page is found, -1 - * is returned. - */ - public int getPageNumber(Reference r) { - Page pg = (Page) library.getObject(r); - if (pg == null) - return -1; -// pg.init(); - int globalIndex = 0; - Reference currChildRef = r; - Reference currParentRef = pg.getParentReference(); - PageTree currParent = pg.getParent(); - while (currParentRef != null && currParent != null) { - currParent.init(); - int refIndex = currParent.indexOfKidReference(currChildRef); - if (refIndex < 0) - return -1; - int localIndex = 0; - for (int i = 0; i < refIndex; i++) { - Object pageOrPages = currParent.getPageOrPagesPotentiallyNotInitedFromReferenceAt(i); - if (pageOrPages instanceof Page) { - localIndex++; - } else if (pageOrPages instanceof PageTree) { - PageTree peerPageTree = (PageTree) pageOrPages; - peerPageTree.init(); - localIndex += peerPageTree.getNumberOfPages(); - } - } - globalIndex += localIndex; - currChildRef = currParentRef; - currParentRef = (Reference) currParent.entries.get(PARENT_KEY); - currParent = currParent.parent; - } - return globalIndex; - } - - /** - * Utility method for getting kid index. - * - * @param r - * @return - */ - private int indexOfKidReference(Reference r) { - for (int i = 0; i < kidsReferences.size(); i++) { - Reference ref = (Reference) kidsReferences.get(i); - if (ref.equals(r)) - return i; - } - return -1; - } - - /** - * Utility method for initializing a page in the page tree. - * - * @param index index in the kids vector to initialize - * @return - */ - private Object getPageOrPagesPotentiallyNotInitedFromReferenceAt(int index) { - WeakReference pageOrPages = kidsPageAndPages.get(index); - if (pageOrPages == null || pageOrPages.get() == null) { - Reference ref = (Reference) kidsReferences.get(index); - Object tmp = library.getObject(ref); - pageOrPages = new WeakReference(tmp); - kidsPageAndPages.put(index, pageOrPages); - return tmp; - } - return pageOrPages.get(); - } - - /** - * Utility method for initializing a page with its page number - * - * @param globalIndex - * @return - */ - private Page getPagePotentiallyNotInitedByRecursiveIndex(int globalIndex) { - int globalIndexSoFar = 0; - int numLocalKids = kidsReferences.size(); - Object pageOrPages; - for (int i = 0; i < numLocalKids; i++) { - pageOrPages = getPageOrPagesPotentiallyNotInitedFromReferenceAt(i); - if (pageOrPages instanceof Page) { - if (globalIndex == globalIndexSoFar) - return (Page) pageOrPages; - globalIndexSoFar++; - } else if (pageOrPages instanceof PageTree) { - PageTree childPageTree = (PageTree) pageOrPages; - childPageTree.init(); - int numChildPages = childPageTree.getNumberOfPages(); - if (globalIndex >= globalIndexSoFar && globalIndex < (globalIndexSoFar + numChildPages)) { - return childPageTree.getPagePotentiallyNotInitedByRecursiveIndex( - globalIndex - globalIndexSoFar); - } - globalIndexSoFar += numChildPages; - } - // corner case where pages didn't have "pages" key. - else if (pageOrPages instanceof HashMap) { - HashMap dictionary = (HashMap) pageOrPages; - if (dictionary.containsKey(new Name("Kids"))) { - PageTree childPageTree = new PageTree(library, dictionary); - childPageTree.init(); - int numChildPages = childPageTree.getNumberOfPages(); - if (globalIndex >= globalIndexSoFar && globalIndex < (globalIndexSoFar + numChildPages)) { - return childPageTree.getPagePotentiallyNotInitedByRecursiveIndex( - globalIndex - globalIndexSoFar); - } - globalIndexSoFar += numChildPages; - } - - } - } - return null; - } - - /** - * Sets a page watermark implementation to be painted on top of the page - * content. Watermark can be specified for each page or once by calling - * document.setWatermark(). - * - * @param watermarkCallback watermark implementation. - */ - protected void setWatermarkCallback(WatermarkCallback watermarkCallback) { - this.watermarkCallback = watermarkCallback; - } - - /** - * In a PDF file there is a root Pages object, which contains - * children Page objects, as well as children PageTree objects, - * all arranged in a tree. - * getNumberOfPages() exists in every PageTree object, giving - * the number of Page objects under it, recursively. - * So, each PageTree object would have a different number of pages, - * and only the root PageTree objects would have a number - * representative of the whole Document. - * - * @return Total number of Page objects under this PageTree - */ - public int getNumberOfPages() { - return kidsCount; - } - - /** - * Gets a Page from the PDF file, locks it for the user, - * initializes the Page, and returns it. - *

- * ICEpdf uses a caching and memory management mechanism - * to reduce the CPU, I/O, and time to access a Page, - * which requires a locking and releasing protocol. - * Calls to the getPage must be matched with - * corresponding calls to releasePage. - * Calls cannot be nested, meaning that releasePage - * must be called before a subsequent invocation of - * getPage for the same pageIndex. - * - * @param pageNumber Zero-based index of the Page to return. - * @return The requested Page. - */ - public Page getPage(int pageNumber) { - if (pageNumber < 0) - return null; - Page page = getPagePotentiallyNotInitedByRecursiveIndex(pageNumber); - // pass in the watermark, even null to wipe a previous watermark - if (page != null) { - page.setWatermarkCallback(watermarkCallback); - page.setPageIndex(pageNumber); - } - return getPagePotentiallyNotInitedByRecursiveIndex(pageNumber); - } - - /** - * Get the page reference for the specified page number. - * - * @param pageNumber zero-based indox of page to find reference of. - * @return found page reference or null if number could not be resolved. - */ - public Reference getPageReference(int pageNumber) { - if (pageNumber < 0) - return null; - Page p = getPagePotentiallyNotInitedByRecursiveIndex(pageNumber); - if (p != null) { - return p.getPObjectReference(); - } - return null; - } - - /** - * Returns a summary of the PageTree dictionary values. - * - * @return dictionary values. - */ - public String toString() { - return "PAGES= " + entries.toString(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Permissions.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Permissions.java deleted file mode 100644 index 284fdbc956..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Permissions.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * The Perms entry in the document catalogue (see Table 28) shall specify a permissions dictionary (PDF 1.5). Each entry - * in this dictionary (see Table 258 for the currently defined entries) shall specify the name of a permission handler - * that controls access permissions for the document. These permissions are similar to those defined by security handlers - * (see Table 22) but do not require that the document be encrypted. For a permission to be actually granted for a - * document, it shall be allowed by each permission handler that is present in the permissions dictionary as well as - * by the security handler. - */ -public class Permissions extends Dictionary { - - /** - * This dictionary shall contain a Reference entry that shall be a signature reference dictionary (see Table 252) - * that has a DocMDP transform method (see 12.8.2.2, DocMDP) and corresponding transform parameters. - *

- * If this entry is present, consumer applications shall enforce the permissions specified by the P attribute in - * the DocMDP transform parameters dictionary and shall also validate the corresponding signature based on whether - * any of these permissions have been violated. - */ - public static final Name DOC_MDP_KEY = new Name("DocMDP"); - - /** - * (Optional) A signature dictionary that shall be used to specify and validate additional capabilities (usage rights) - * granted for this document; that is, the enabling of interactive features of the conforming reader that are not - * available by default. - *
- * For example, A conforming reader does not permit saving documents by default, but an agent may grant permissions - * that enable saving specific documents. The signature shall be used to validate that the permissions have been - * granted by the agent that did the signing. - *
- * The signature dictionary shall contain a Reference entry that shall be a signature reference dictionary that has - * a UR transform method (see 12.8.2.3, UR). The transform parameter dictionary for this method indicates which - * additional permissions shall be granted for the document. If the signature is valid, the conforming reader shall - * allow the specified permissions for the document, in addition to the application's default permissions. - */ - public static final Name UR3_KEY = new Name("UR3"); - - // todo need to find some info this key - public static final Name UR_KEY = new Name("UR"); - - public Permissions(Library library, HashMap entries) { - super(library, entries); - } - - /** - * Indication if DocMDP handler should be used. - * - * @return true if DocMDP handler should be used. - */ - public boolean isDocMDP() { - return library.getObject(entries, DOC_MDP_KEY) != null; - } - - /** - * Indication if UR3 handler should be used. - * - * @return true if UR3 handler should be used. - */ - public boolean isUR3() { - return library.getObject(entries, UR3_KEY) != null; - } - - /** - * Indication if UR3 handler should be used. - * - * @return true if UR3 handler should be used. - */ - public boolean isUR() { - return library.getObject(entries, UR_KEY) != null; - } - - public SignatureDictionary getSignatureDictionary() { - if (isDocMDP()) { - return new SignatureDictionary(library, library.getDictionary(entries, DOC_MDP_KEY)); - } else if (isUR3()) { - return new SignatureDictionary(library, library.getDictionary(entries, UR3_KEY)); - } else if (isUR()) { - return new SignatureDictionary(library, library.getDictionary(entries, UR_KEY)); - } else { - return null; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Reference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Reference.java deleted file mode 100644 index 77229c032e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Reference.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import java.io.Serializable; - -/** - *

The Reference class represents a PDF object reference number. - * A reference is made of two components:

- *
    - *
  • objectNumnber - a unique number that identifies this object from other - * objects in the PDF document.
  • - *
  • bjectGeneration - identifies the generation number of the Reference. By - * default, the value is normally 0, but if the document - * has been modifed by another user it will be incrementd - * to keep track of changes.
  • - *
- * - * @since 1.0 - */ -@SuppressWarnings("serial") -public class Reference implements Serializable { - // object number - int objf = 0; - // object generation number. - int genf = 0; - - /** - * Creates a new instance of a Reference. - * - * @param o object number - * @param g generation number - */ - public Reference(Number o, Number g) { - if (o != null) { - objf = o.intValue(); - } - if (g != null) { - genf = g.intValue(); - } - } - - /** - * Creates a new instance of a Reference. - * - * @param o object number - * @param g generation number - */ - public Reference(int o, int g) { - objf = o; - genf = g; - } - - /** - * Creates a unique hash code for this reference object. - * - * @return hashcode. - */ - public int hashCode() { - return objf * 1000 + genf; - } - - /** - * Indicates whether some other reference object is "equal to" this one. - * - * @param obj reference object to compare to this reference. - * @return tru, e if the two objects are equal; false, otherwise. - */ - public boolean equals(Object obj) { - if (obj == this) - return true; - if (obj != null && obj instanceof Reference) { - Reference tmp = (Reference) obj; - return (tmp.objf == objf) && (tmp.genf == genf); - } - return false; - } - - /** - * Gets the object number represented by this reference. - * - * @return object number - */ - public int getObjectNumber() { - return objf; - } - - /** - * Gets the generation number represented by this reference. - * - * @return generation number - */ - public int getGenerationNumber() { - return genf; - } - - /** - * Gets a string summary of the reference objects number and generation number. - * - * @return summary of reference object data. - */ - public String toString() { - return objf + " " + genf + " R"; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Resources.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Resources.java deleted file mode 100644 index c5c0c97984..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Resources.java +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.fonts.FontFactory; -import org.icepdf.core.pobjects.graphics.*; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * A resource is a dictionary type as defined by the PDF specification. It - * can contain fonts, xobjects, colorspaces, patterns, shading and - * external graphic states. - * - * @since 1.0 - */ -public class Resources extends Dictionary { - - public static final Name COLORSPACE_KEY = new Name("ColorSpace"); - public static final Name FONT_KEY = new Name("Font"); - public static final Name XOBJECT_KEY = new Name("XObject"); - public static final Name PATTERN_KEY = new Name("Pattern"); - public static final Name SHADING_KEY = new Name("Shading"); - public static final Name EXTGSTATE_KEY = new Name("ExtGState"); - public static final Name PROPERTIES_KEY = new Name("Properties"); - - // shared resource counter. - private static int uniqueCounter = 0; - - private static synchronized int getUniqueId() { - return uniqueCounter++; - } - - private static final Logger logger = - Logger.getLogger(Resources.class.toString()); - - HashMap fonts; - HashMap xobjects; - HashMap colorspaces; - HashMap patterns; - HashMap shading; - HashMap extGStates; - HashMap properties; - - /** - * @param l - * @param h - */ - public Resources(Library l, HashMap h) { - super(l, h); - colorspaces = library.getDictionary(entries, COLORSPACE_KEY); - fonts = library.getDictionary(entries, FONT_KEY); - xobjects = library.getDictionary(entries, XOBJECT_KEY); - patterns = library.getDictionary(entries, PATTERN_KEY); - shading = library.getDictionary(entries, SHADING_KEY); - extGStates = library.getDictionary(entries, EXTGSTATE_KEY); - properties = library.getDictionary(entries, PROPERTIES_KEY); - } - - public HashMap getFonts() { - return fonts; - } - - /** - * @param o - * @return - */ - public PColorSpace getColorSpace(Object o) { - - if (o == null) { - return null; - } - - try { - Object tmp; - // every resource has a color space entry and o can be tmp in it. - if (colorspaces != null && colorspaces.get(o) != null) { - tmp = colorspaces.get(o); - PColorSpace cs = PColorSpace.getColorSpace(library, tmp); - if (cs != null) { - cs.init(); - } - return cs; - } - // look for our name in the pattern dictionary - if (patterns != null && patterns.get(o) != null) { - tmp = patterns.get(o); - PColorSpace cs = PColorSpace.getColorSpace(library, tmp); - if (cs != null) { - cs.init(); - } - return cs; - } - - // if its not in color spaces or pattern then its a plain old - // named colour space. - PColorSpace cs = PColorSpace.getColorSpace(library, o); - if (cs != null) { - cs.init(); - } - return cs; - } catch (InterruptedException e) { - logger.fine("Colorspace parsing was interrupted"); - } - return null; - - } - - /** - * @param s - * @return - */ - public org.icepdf.core.pobjects.fonts.Font getFont(Name s) { - org.icepdf.core.pobjects.fonts.Font font = null; - if (fonts != null) { - Object ob = fonts.get(s); - // check to make sure the library contains a font - if (ob instanceof org.icepdf.core.pobjects.fonts.Font) { - font = (org.icepdf.core.pobjects.fonts.Font) ob; - } - // corner case where font is just a inline dictionary. - else if (ob instanceof HashMap) { - font = FontFactory.getInstance().getFont(library, (HashMap) ob); - } - // the default value is most likely Reference - else if (ob instanceof Reference) { - Reference ref = (Reference) ob; - ob = library.getObject((Reference) ob); - if (ob instanceof PObject) { - ob = ((PObject) ob).getObject(); - } - if (ob instanceof org.icepdf.core.pobjects.fonts.Font) { - font = (org.icepdf.core.pobjects.fonts.Font) ob; - } else { - font = FontFactory.getInstance().getFont(library, (HashMap) ob); - } - // cache the font for later use. - if (font != null) { - library.addObject(font, ref); - font.setPObjectReference(ref); - } - } - // if still null do a deeper search checking the base font name of - // each font for a match to the needed font name. We have a few - // malformed documents that don't refer to a font by the base name - // and not the font name found in the resource table. - if (font == null) { - for (Object tmp : fonts.values()) { - if (tmp instanceof Reference) { - ob = library.getObject((Reference) tmp); - if (ob instanceof PObject) { - ob = ((PObject) ob).getObject(); - } - if (ob instanceof org.icepdf.core.pobjects.fonts.Font) { - font = (org.icepdf.core.pobjects.fonts.Font) ob; - String baseFont = font.getBaseFont(); - if (s.getName().equals(baseFont) || - baseFont.contains(s.getName())) { - // cache the font for later use. - library.addObject(font, (Reference) tmp); - font.setPObjectReference((Reference) tmp); - break; - } else { - font = null; - } - } - } - } - } - } - if (font != null) { - try { - font.setParentResource(this); - font.init(); - } catch (Exception e) { - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error initializing font, falling back to font substitution."); - } else { - logger.log(Level.FINER, "Error initializing font, falling back to font substitution. " + font); - } - } - } - return font; - } - - /** - * @param s - * @param graphicsState - * @return - */ - public Image getImage(Name s, GraphicsState graphicsState) { - - // check xobjects for stream - ImageStream st = (ImageStream) library.getObject(xobjects, s); - if (st == null) { - return null; - } - // return null if the xobject is not an image - if (!st.isImageSubtype()) { - return null; - } - // lastly return the images. - Image image = null; - try { - image = st.getImage(graphicsState, this); - } catch (Exception e) { - logger.log(Level.FINE, "Error getting image by name: " + s, e); - } - return image; - } - - public ImageStream getImageStream(Name s) { - // check xobjects for stream - Object st = library.getObject(xobjects, s); - if (st instanceof ImageStream) { - return (ImageStream) st; - } - return null; - } - - public Object getXObject(Name s) { - return library.getObject(xobjects, s); - } - - /** - * Gets a rough count of the images resources associated with this page. Does - * not include inline images. - * - * @return rough count of images resources. - */ - public int getImageCount() { - int count = 0; - if (xobjects != null) { - for (Object tmp : xobjects.values()) { - if (tmp instanceof Reference) { - tmp = library.getObject((Reference) tmp); - if (tmp instanceof ImageStream) { - count++; - } - } - } - } - return count; - } - - /** - * @param s - * @return - */ - public boolean isForm(Name s) { - Object o = library.getObject(xobjects, s); - return o instanceof Form; - } - - /** - * Gets the Form XObject specified by the named reference. - * - * @param nameReference name of resourse to retreive. - * @return if the named reference is found return it, otherwise return null; - */ - public Form getForm(Name nameReference) { - Form formXObject = null; - Object tempForm = library.getObject(xobjects, nameReference); - if (tempForm instanceof Form) { - formXObject = (Form) tempForm; - } - return formXObject; - } - - /** - * Retrieves a Pattern object given the named resource. This can be - * call for a fill, text fill or do image mask. - * - * @param name of object to find. - * @return tiling or shading type pattern object. If not constructor is - * found, then null is returned. - */ - public Pattern getPattern(Name name) { - if (patterns != null) { - - Object attribute = library.getObject(patterns, name); - // An instance of TilingPattern will always have a stream - if (attribute != null && attribute instanceof TilingPattern) { - return (TilingPattern) attribute; - } else if (attribute != null && attribute instanceof Stream) { - return new TilingPattern((Stream) attribute); - } - // ShaddingPatterns will not have a stream but still need to parsed - else if (attribute != null && attribute instanceof HashMap) { - return ShadingPattern.getShadingPattern(library, - (HashMap) attribute); - } - } - return null; - } - - /** - * Gets the shadding pattern based on a shading dictionary name, similar - * to getPattern but is only called for the 'sh' token. - * - * @param name name of shading dictionary - * @return associated shading pattern if any. - */ - public ShadingPattern getShading(Name name) { - // look for pattern name in the shading dictionary, used by 'sh' tokens - if (shading != null) { - Object shadingDictionary = library.getObject(shading, name); - if (shadingDictionary != null && shadingDictionary instanceof HashMap) { - return ShadingPattern.getShadingPattern(library, entries, - (HashMap) shadingDictionary); - } - else if (shadingDictionary != null && shadingDictionary instanceof Stream) { - return ShadingPattern.getShadingPattern(library, null, - (Stream) shadingDictionary); - } - } - return null; - } - - /** - * Returns the ExtGState object which has the specified reference name. - * - * @param namedReference name of ExtGState object to try and find. - * @return ExtGState which contains the named references ExtGState attributes, - * if the namedReference could not be found null is returned. - */ - public ExtGState getExtGState(Name namedReference) { - ExtGState gsState = null; - if (extGStates != null) { - Object attribute = library.getObject(extGStates, namedReference); - if (attribute instanceof HashMap) { - gsState = new ExtGState(library, (HashMap) attribute); - } else if (attribute instanceof Reference) { - gsState = new ExtGState(library, - (HashMap) library.getObject( - (Reference) attribute)); - } - } - return gsState; - } - - /** - * Looks for the specified key in the Properties dictionary. If the dictionary - * and corresponding value is found the object is returned otherwise null. - * - * @param key key to find a value of in the Properties dictionary. - * @return key value if found, null otherwise. - */ - public OptionalContents getPropertyEntry(Name key) { - if (properties != null) { - Object object = library.getObject(properties.get(key)); - if (object instanceof OptionalContents) { - return (OptionalContents) library.getObject(properties.get(key)); - } - } - return null; - } - - /** - * Checks to see if the Shading key has value in this resource dictionary. - * - * @return true if there are shading values, false otherwise. - */ - public boolean isShading() { - return shading != null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/StateManager.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/StateManager.java deleted file mode 100644 index 10b71aa125..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/StateManager.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import java.util.*; -import java.util.logging.Logger; - -/** - * This class is responsible for keeping track of which object in the document - * have change. When a file is written to disk this class is used to find - * the object that should be written in the body section of the file as part of - * an incremental update. - *

- * Once this object is created should be added to the library so that is - * accessible by any PObject. - * - * @since 4.0 - */ -public class StateManager { - private static final Logger logger = - Logger.getLogger(StateManager.class.getName()); - - // a list is all we might need. - private HashMap changes; - - // access to xref size and next revision number. - private PTrailer trailer; - - private int nextReferenceNumber; - - /** - * Creates a new instance of the state manager. - * - * @param trailer document trailer - */ - public StateManager(PTrailer trailer) { - this.trailer = trailer; - // cache of objects that have changed. - changes = new HashMap(); - - // number of objects is always one more then the current size and - // thus the next available number. - if (trailer != null) { - nextReferenceNumber = trailer.getNumberOfObjects(); - } - } - - /** - * Gets the next available reference number from the trailer. - * - * @return valid reference number. - */ - public Reference getNewReferencNumber() { - // zero revision number for now but technically we can reuse - // deleted references and increment the rev number. For no we - // keep it simple - Reference newReference = new Reference(nextReferenceNumber, 0); - nextReferenceNumber++; - return newReference; - } - - /** - * Add a new PObject containing changed data to the cache. - * - * @param pObject object to add to cache. - */ - public void addChange(PObject pObject) { - changes.put(pObject.getReference(), pObject); - int objectNumber = pObject.getReference().getObjectNumber(); - // check the reference numbers - if (nextReferenceNumber <= objectNumber) { - nextReferenceNumber = objectNumber + 1; - } - } - - /** - * Checks the state manager to see if an instance of the specified reference - * already exists in the cache. - * - * @param reference reference to look for an existing usage. - * @return true if reference is already a key in the cache; otherwise, false. - */ - public boolean contains(Reference reference) { - return changes.containsKey(reference); - } - - /** - * Returns an instance of the specified reference - * - * @param reference reference to look for an existing usage - * @return PObject of corresponding reference if present, false otherwise. - */ - public Object getChange(Reference reference) { - return changes.get(reference); - } - - /** - * Remove a PObject from the cache. - * - * @param pObject pObject to removed from the cache. - */ - public void removeChange(PObject pObject) { - changes.remove(pObject.getReference()); - } - - /** - * @return If there are any changes - */ - public boolean isChanged() { - return !changes.isEmpty(); - } - - /** - * Gets the number of change object in the state manager. - * - * @return zero or more changed object count. - */ - public int getChangedSize() { - return changes.size(); - } - - /** - * @return An Iterator for all the changes objects, sorted - */ - public Iterator iteratorSortedByObjectNumber() { - Collection coll = changes.values(); -/* - * This code allows me to force an object to be treated as modified, - * so I can debug how we write out that kind of object, before we - * add a ui to actually edit it. -Reference ref = new Reference(10,0); -Object ob = trailer.getLibrary().getObject(ref); -logger.severe("Object 10: " + ob + " ob.class: " + ob.getClass().getName()); -java.util.HashSet hs = new java.util.HashSet(coll); -hs.add(new PObject(ob, ref)); -coll = hs; -*/ - PObject[] arr = coll.toArray(new PObject[coll.size()]); - Arrays.sort(arr, new PObjectComparatorByReferenceObjectNumber()); - List sortedList = Arrays.asList(arr); - return sortedList.iterator(); - } - - public PTrailer getTrailer() { - return trailer; - } - - - private static class PObjectComparatorByReferenceObjectNumber - implements Comparator { - public int compare(PObject a, PObject b) { - if (a == null && b == null) - return 0; - else if (a == null) - return -1; - else if (b == null) - return 1; - Reference ar = a.getReference(); - Reference br = b.getReference(); - if (ar == null && br == null) - return 0; - else if (ar == null) - return -1; - else if (br == null) - return 1; - int aron = ar.getObjectNumber(); - int bron = br.getObjectNumber(); - if (aron < bron) - return -1; - else if (aron > bron) - return 1; - return 0; - } - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Stream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Stream.java deleted file mode 100644 index 3610f29c03..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Stream.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.io.BitStream; -import org.icepdf.core.io.ConservativeSizingByteArrayOutputStream; -import org.icepdf.core.io.SeekableInputConstrainedWrapper; -import org.icepdf.core.pobjects.filters.*; -import org.icepdf.core.pobjects.security.SecurityManager; -import org.icepdf.core.util.Library; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * The Stream class is responsible for decoding stream contents and returning - * either an images object or a byte array depending on the content. The Stream - * object worker method is decode which is responsible for decoding the content - * stream, which is if the first step of the rendering process. Once a Stream - * is decoded it is either returned as an image object or a byte array that is - * then processed further by the ContentParser. - * - * @since 1.0 - */ -public class Stream extends Dictionary { - - private static final Logger logger = - Logger.getLogger(Stream.class.toString()); - - public static final Name WIDTH_KEY = new Name("Width"); - public static final Name W_KEY = new Name("W"); - public static final Name HEIGHT_KEY = new Name("Height"); - public static final Name H_KEY = new Name("H"); - public static final Name IMAGEMASK_KEY = new Name("ImageMask"); - public static final Name IM_KEY = new Name("IM"); - public static final Name COLORSPACE_KEY = new Name("ColorSpace"); - public static final Name CS_KEY = new Name("CS"); - public static final Name DECODEPARAM_KEY = new Name("DecodeParms"); - public static final Name FILTER_KEY = new Name("Filter"); - public static final Name F_KEY = new Name("F"); - public static final Name INDEXED_KEY = new Name("Indexed"); - public static final Name I_KEY = new Name("I"); - - // original byte stream that has not been decoded - protected byte[] rawBytes; - - protected HashMap decodeParams; - - // default compression state for a file loaded stream, for re-saving - // of form data we want to avoid re-compressing the data. - protected boolean compressed = true; - - // reference of stream, needed for encryption support - protected Reference pObjectReference; - - /** - * Create a new instance of a Stream. - * - * @param l library containing a hash of all document objects - * @param h HashMap of parameters specific to the Stream object. - * @param streamInputWrapper Accessor to stream byte data - */ - public Stream(Library l, HashMap h, SeekableInputConstrainedWrapper streamInputWrapper) { - super(l, h); - // capture raw bytes for later processing. - if (streamInputWrapper != null) { - this.rawBytes = getRawStreamBytes(streamInputWrapper); - } - decodeParams = library.getDictionary(entries, DECODEPARAM_KEY); - } - - public Stream(Library l, HashMap h, byte[] rawBytes) { - super(l, h); - this.rawBytes = rawBytes; - if (library != null) { - decodeParams = library.getDictionary(entries, DECODEPARAM_KEY); - } - } - - /** - * Sets the PObject referece for this stream. The reference number and - * generation is need by the encryption algorithm. - */ - public void setPObjectReference(Reference reference) { - pObjectReference = reference; - } - - public byte[] getRawBytes() { - return rawBytes; - } - - public void setRawBytes(byte[] rawBytes) { - this.rawBytes = rawBytes; - compressed = false; - } - - public boolean isRawBytesCompressed() { - return compressed; - } - - /** - * Gets the parent PObject reference for this stream. - * - * @return Reference number of parent PObject. - * @see #setPObjectReference(org.icepdf.core.pobjects.Reference) - */ - public Reference getPObjectReference() { - return pObjectReference; - } - - protected boolean isImageSubtype() { - Object subtype = library.getObject(entries, SUBTYPE_KEY); - return subtype != null && subtype.equals("Image"); - } - - - private byte[] getRawStreamBytes(SeekableInputConstrainedWrapper streamInputWrapper) { - // copy the raw bytes out to internal storage for later decoding. - int length = (int) streamInputWrapper.getLength(); - byte[] rawBytes = new byte[length]; - try { - streamInputWrapper.read(rawBytes, 0, length); - } catch (IOException e) { - logger.warning("IO Error getting stream bytes"); - } - return rawBytes; - } - - /** - * Gets the decoded Byte stream of the Stream object. - * - * @return decoded Byte stream - */ - public ByteArrayInputStream getDecodedByteArrayInputStream() { - return new ByteArrayInputStream(getDecodedStreamBytes(0)); - } - - public byte[] getDecodedStreamBytes() { - return getDecodedStreamBytes(8192); - } - - /** - * This is similar to getDecodedStreamByteArray(), except that the returned byte[] - * is not necessarily exactly sized, and may be larger. Therefore the returned - * Integer gives the actual valid size - * - * @param presize potential size to associate with byte array. - * @return Object[] { byte[] data, Integer sizeActualData } - */ - public byte[] getDecodedStreamBytes(int presize) { - // decompress the stream - if (compressed) { - try { - ByteArrayInputStream streamInput = new ByteArrayInputStream(rawBytes); - long rawStreamLength = rawBytes.length; - InputStream input = getDecodedInputStream(streamInput, rawStreamLength); - if (input == null) return null; - int outLength; - if (presize > 0) { - outLength = presize; - } else { - outLength = Math.max(4096, (int) rawStreamLength); - } - ConservativeSizingByteArrayOutputStream out = new - ConservativeSizingByteArrayOutputStream(outLength); - byte[] buffer = new byte[(outLength > 4096) ? 4096 : 8192]; - while (true) { - int read = input.read(buffer); - if (read <= 0) - break; - out.write(buffer, 0, read); - } - input.close(); - out.flush(); - out.close(); - out.trim(); - return out.relinquishByteArray(); - } catch (IOException e) { - logger.log(Level.FINE, "Problem decoding stream bytes: ", e); - } - } - // we have an edited stream which isn't compressed yet, so just return - // the raw bytes. - else { - return rawBytes; - } - return null; - } - - /** - * Utility method for decoding the byte stream using the decode algorithem - * specified by the filter parameter - *

- * The memory manger is called every time a stream is being decoded with an - * estimated size of the decoded stream. Because many of the Filter - * algorithms use compression, further research must be done to try and - * find the average amount of memory used by each of the algorithms. - * - * @return inputstream that has been decoded as defined by the streams filters. - */ - private InputStream getDecodedInputStream(InputStream streamInput, long streamLength) { - // Make sure that the stream actually has data to decode, if it doesn't - // make it null and return. - if (streamInput == null || streamLength < 1) { - return null; - } - - InputStream input = streamInput; - - int bufferSize = Math.min(Math.max((int) streamLength, 64), 16 * 1024); - input = new java.io.BufferedInputStream(input, bufferSize); - - // Search for crypt dictionary entry and decode params so that - // named filters can be assigned correctly. - SecurityManager securityManager = library.getSecurityManager(); -// System.out.println("Thread " + Thread.currentThread() + " " + pObjectReference); - if (securityManager != null) { - // check see of there is a decodeParams for a crypt filter. - input = securityManager.decryptInputStream( - pObjectReference, securityManager.getDecryptionKey(), - decodeParams, input, true); - } - - // Get the filter name for the encoding type, which can be either - // a Name or Vector. - List filterNames = getFilterNames(); - if (filterNames == null) - return input; - - // Decode the stream data based on the filter names. - // Loop through the filterNames and apply the filters in the order - // in which they where found. - for (Object filterName1 : filterNames) { - // grab the name of the filter - String filterName = filterName1.toString(); - //System.out.println(" Decoding: " + filterName); - - if (filterName.equals("FlateDecode") - || filterName.equals("/Fl") - || filterName.equals("Fl")) { - input = new FlateDecode(library, entries, input); - } else if ( - filterName.equals("LZWDecode") - || filterName.equals("/LZW") - || filterName.equals("LZW")) { - input = new LZWDecode(new BitStream(input), library, entries); - } else if ( - filterName.equals("ASCII85Decode") - || filterName.equals("/A85") - || filterName.equals("A85")) { - input = new ASCII85Decode(input); - } else if ( - filterName.equals("ASCIIHexDecode") - || filterName.equals("/AHx") - || filterName.equals("AHx")) { - input = new ASCIIHexDecode(input); - } else if ( - filterName.equals("RunLengthDecode") - || filterName.equals("/RL") - || filterName.equals("RL")) { - input = new RunLengthDecode(input); - } else if ( - filterName.equals("CCITTFaxDecode") - || filterName.equals("/CCF") - || filterName.equals("CCF")) { - // Leave empty so our else clause works - } else if ( - filterName.equals("DCTDecode") - || filterName.equals("/DCT") - || filterName.equals("DCT")) { - // Leave empty so our else clause works - } else if ( // No short name, since no JBIG2 for inline images - filterName.equals("JBIG2Decode")) { - // Leave empty so our else clause works - } else if ( // No short name, since no JPX for inline images - filterName.equals("JPXDecode")) { - // Leave empty so our else clause works - } else { - if (logger.isLoggable(Level.FINE)) { - logger.fine("UNSUPPORTED:" + filterName + " " + entries); - } - } - } - // Apply Predictor Filter logic fo LZW or Flate streams. - if (PredictorDecode.isPredictor(library, entries)) { - input = new PredictorDecode(input, library, entries); - } - - return input; - } - - @SuppressWarnings("unchecked") - protected List getFilterNames() { - List filterNames = null; - Object o = library.getObject(entries, FILTER_KEY); - if (o instanceof Name) { - filterNames = new ArrayList(1); - filterNames.add(o.toString()); - } else if (o instanceof List) { - filterNames = (List) o; - } - return filterNames; - } - - protected List getNormalisedFilterNames() { - List filterNames = getFilterNames(); - if (filterNames == null) - return null; - - String filterName; - for (int i = 0; i < filterNames.size(); i++) { - filterName = filterNames.get(i); - - if (filterName.equals("FlateDecode") - || filterName.equals("/Fl") - || filterName.equals("Fl")) { - filterName = "FlateDecode"; - } else if ( - filterName.equals("LZWDecode") - || filterName.equals("/LZW") - || filterName.equals("LZW")) { - filterName = "LZWDecode"; - } else if ( - filterName.equals("ASCII85Decode") - || filterName.equals("/A85") - || filterName.equals("A85")) { - filterName = "ASCII85Decode"; - } else if ( - filterName.equals("ASCIIHexDecode") - || filterName.equals("/AHx") - || filterName.equals("AHx")) { - filterName = "ASCIIHexDecode"; - } else if ( - filterName.equals("RunLengthDecode") - || filterName.equals("/RL") - || filterName.equals("RL")) { - filterName = "RunLengthDecode"; - } else if ( - filterName.equals("CCITTFaxDecode") - || filterName.equals("/CCF") - || filterName.equals("CCF")) { - filterName = "CCITTFaxDecode"; - } else if ( - filterName.equals("DCTDecode") - || filterName.equals("/DCT") - || filterName.equals("DCT")) { - filterName = "DCTDecode"; - } - // There aren't short names for JBIG2Decode or JPXDecode - filterNames.set(i, filterName); - } - return filterNames; - } - - /** - * Return a string description of the object. Primarly used for debugging. - */ - public String toString() { - StringBuilder sb = new StringBuilder(64); - sb.append("STREAM= "); - sb.append(entries); - if (getPObjectReference() != null) { - sb.append(" "); - sb.append(getPObjectReference()); - } - return sb.toString(); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/StringObject.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/StringObject.java deleted file mode 100644 index d1fe7a325c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/StringObject.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.pobjects.fonts.FontFile; -import org.icepdf.core.pobjects.security.SecurityManager; - -/** - *

This class represents a PDF String Object. A StringObject - * consists of a series of bytes in the range 0 to 255. A StringObject - * can be written in two ways:

- *
    - *
  • Literal Strings - {@see LiteralStringObject}
  • - *
  • Hexadecimal Strings - {@see HexStringObject}
  • - *
- *

The methods define in this interface are common to both Literal and - * Hexadecimal Strings Object.

- * - * @since 2.0 - */ -public interface StringObject { - - /** - *

Returns a string representation of the object.

- * - * @return a string representing the object. - */ - public String toString(); - - /** - *

Gets a literal StringBuffer representation of this object's data.

- * - * @return a StringBuffer representing the objects data. - */ - public StringBuilder getLiteralStringBuffer(); - - /** - *

Gets a literal String representation of this object's data. - * - * @return a String representation of the object's data. - */ - public String getLiteralString(); - - /** - *

Gets a hexadecimal StringBuffer representation of this objects data.

- * - * @return a StringBufffer representation of the objects data. - */ - public StringBuilder getHexStringBuffer(); - - /** - *

Gets a hexadecimal String representation of this object's data.

- * - * @return a String representation of the object's data. - */ - public String getHexString(); - - /** - * Gets the unsigned integer value of this object's data specified by - * the start index and offset parameters. - * - * @param start the beginning index, inclusive. - * @param offset the number of string characters to read. - * @return integer value of the specified range of characters. - */ - public int getUnsignedInt(int start, int offset); - - /** - * Gets a literal String representation of this objects data using the - * specified font and format. - * - * @param fontFormat the type of PDF font which will be used to display - * the text. Valid values are CID_FORMAT and SIMPLE_FORMAT for Adobe - * Composite and Simple font types respectively - * @param font font used to render the literal string data. - * @return StringBuffer which contains all renderaable characters for the - * given font. - */ - public StringBuilder getLiteralStringBuffer(final int fontFormat, FontFile font); - - /** - * The length of the underlying objects data. - * - * @return length of objct's data. - */ - public int getLength(); - - /** - * Sets the parent PDF object's reference. - * - * @param reference parent object reference. - */ - public void setReference(Reference reference); - - /** - * Sets the parent PDF object's reference. - * - * @return returns the reference used for encryption. - */ - public Reference getReference(); - - /** - * Gets the decrypted literal string value of the data using the key provided by the - * security manager. - * - * @param securityManager security manager associated with parent document. - * @return decrypted stream. - */ - public String getDecryptedLiteralString(SecurityManager securityManager); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Thumbnail.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Thumbnail.java deleted file mode 100644 index 071845aeb4..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/Thumbnail.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.HashMap; - -/** - * A PDF document may contain thumbnail images representing the contents of its - * pages in miniature form. A conforming reader may display these images on the - * screen, allowing the user to navigate to a page by clicking its thumbnail - * image: - *

- * NOTEThumbnail images are not required, and may be included for some - * pages and not for others. - */ -public class Thumbnail extends Dictionary { - - public static final Name THUMB_KEY = new Name("Thumb"); - public static final Name WIDTH_KEY = new Name("Width"); - public static final Name HEIGHT_KEY = new Name("Height"); - - private ImageStream thumbStream; - private boolean initialized; - - // thumb image - private BufferedImage image; - - // dimensions - private Dimension dimension; - - public Thumbnail(Library library, HashMap entries) { - super(library, entries); - Object thumb = library.getObject(entries, THUMB_KEY); - if (thumb != null) { - if (thumb instanceof ImageStream) { - // get the thumb image. - thumbStream = (ImageStream) thumb; - } else { - thumbStream = new ImageStream(library, ((Stream) thumb).getEntries(), - ((Stream) thumb).getRawBytes()); - } - // grab its bounds. - int width = library.getInt(thumbStream.entries, WIDTH_KEY); - int height = library.getInt(thumbStream.entries, HEIGHT_KEY); - dimension = new Dimension(width, height); - // the image is lazy loaded on the getImage() call. - - } - } - - public void init() throws InterruptedException { - Resources resource = new Resources(library, thumbStream.entries); - image = thumbStream.getImage(null, resource); - initialized = true; - } - - public BufferedImage getImage() throws InterruptedException { - if (!initialized) { - init(); - } - return image; - } - - public Dimension getDimension() { - return dimension; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ViewerPreferences.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ViewerPreferences.java deleted file mode 100644 index cc4c48d875..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/ViewerPreferences.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects; - -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * The ViewerPreferences class is used to represent and provide access to the - * ViewerPreference keys and values from the PDF Specification, such as HideToolbar - */ -public class ViewerPreferences extends Dictionary { - - // root node of the tree of names. - private NameNode root; - - /** - * Creates a new instance of a NameTree. - * - * @param l document library. - * @param h NameTree dictionary entries. - */ - public ViewerPreferences(Library l, HashMap h) { - super(l, h); - } - - /** - * Initiate the NameTree. - */ - public void init() { - if (inited) { - return; - } - root = new NameNode(library, entries); - inited = true; - } - - public NameNode getRoot() { - return root; - } - - public boolean hasHideToolbar() { - return library.isValidEntry(entries, new Name("HideToolbar")); - } - - public boolean hasHideMenubar() { - return library.isValidEntry(entries, new Name("HideMenubar")); - } - - public boolean hasFitWindow() { - return library.isValidEntry(entries, new Name("FitWindow")); - } - - public boolean getHideToolbar() { - return library.getBoolean(entries, new Name("HideToolbar")); - } - - public boolean getHideMenubar() { - return library.getBoolean(entries, new Name("HideMenubar")); - } - - public boolean getFitWindow() { - return library.getBoolean(entries, new Name("FitWindow")); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/AdditionalActionsDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/AdditionalActionsDictionary.java deleted file mode 100644 index 33d0f1ed27..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/AdditionalActionsDictionary.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.actions.Action; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * An annotation, page object, or (beginning with PDF 1.3) interactive form field may include an entry named AA that - * specifies an additional-actions dictionary (PDF 1.2) that extends the set of events that can trigger the execution - * of an action. In PDF 1.4, the document catalogue dictionary (see 7.7.2, “Document Catalogâ€) may also contain an AA - * entry for trigger events affecting the document as a whole. Tables 194 to 197 show the contents of this type of - * dictionary. - *

- * PDF 1.5 introduces four trigger events in annotation’s additional-actions dictionary to support multimedia - * presentations: - *

    - *
  • The PO and PC entries have a similar function to the O and C entries in the page object’s additional-actions - * dictionary (see Table 194). However, associating these triggers with annotations allows annotation objects to be - * self-contained.
  • - *
  • The PV and PI entries allow a distinction between pages that are open and pages that are visible. At any one - * time, while more than one page may be visible, depending on the page layout.
  • - *
- * - * @since 5.2 - */ -public class AdditionalActionsDictionary extends Dictionary { - - // Table 194 – Entries in an annotation’s additional-actions dictionary - - /** - * (Optional; PDF 1.2) An action that shall be performed when the cursor enters the annotation’s active area. - * An E (enter) event may occur only when the mouse button is up. - */ - public static final Name ANNOTATION_E_KEY = new Name("E"); - - /** - * (Optional; PDF 1.2) An action that shall be performed when the cursor exits the annotation’s active area. - * An X (exit) event may not occur without a preceding E event. - */ - public static final Name ANNOTATION_X_KEY = new Name("X"); - - /** - * Optional; PDF 1.2) An action that shall be performed when the mouse button is pressed inside the annotation’s - * active area. - */ - public static final Name ANNOTATION_D_KEY = new Name("D"); - - /** - * (Optional; PDF 1.2) An action that shall be performed when the mouse button is released inside the annotation’s - * active area. - *

- * For backward compatibility, the A entry in an annotation dictionary, if present, takes precedence over this - * entry (see Table 168). - * A U (up) event may not occur without a preceding E and D event. - */ - public static final Name ANNOTATION_U_KEY = new Name("U"); - - /** - * (Optional; PDF 1.2; widget annotations only) An action that shall be performed when the annotation receives - * the input focus. - */ - public static final Name ANNOTATION_FO_KEY = new Name("Fo"); - - /** - * (Optional; PDF 1.2; widget annotations only) (Uppercase B, lowercase L) An action that shall be performed when - * the annotation loses the input focus. - */ - public static final Name ANNOTATION_Bl_KEY = new Name("Bl"); - - /** - * (Optional; PDF 1.5) An action that shall be performed when the page containing the annotation is opened. - *

- * EXAMPLE 1
- * When the user navigates to it from the next or previous page or by means of a link annotation or outline item. - *

- * The action shall be executed after the O action in the page’s additional-actions dictionary (see Table 195) and - * the OpenAction entry in the document Catalog(see Table 28), if such actions are present. - */ - public static final Name ANNOTATION_PO_KEY = new Name("Bl"); - - /** - * (Optional; PDF 1.5) An action that shall be performed when the page containing the annotation is closed. - *

- * EXAMPLE 2
- * When the user navigates to the next or previous page, or follows a link annotation or outline item. - *

- * The action shall be executed before the C action in the page’s additional-actions dictionary (see Table 195), - * if present. - */ - public static final Name ANNOTATION_PC_KEY = new Name("PC"); - - /** - * (Optional; PDF 1.5) An action that shall be performed when the page containing the annotation becomes visible. - */ - public static final Name ANNOTATION_PV_KEY = new Name("PV"); - - /** - * (Optional; PDF 1.5) An action that shall be performed when the page containing the annotation is no longer - * visible in the conforming reader’s user interface. - */ - public static final Name ANNOTATION_PI_KEY = new Name("PI"); - - // Table 195 – Entries in a page object’s additional-actions dictionary - - /** - * Optional; PDF 1.2) An action that shall be performed when the page is opened (for example, when the user - * navigates to it from the next or previous page or by means of a link annotation or outline item). This action is - * independent of any that may be defined by the OpenAction entry in the document Catalog (see 7.7.2, “Document Catalogâ€) - * and shall be executed after such an action. - */ - public static final Name PAGE_0_KEY = new Name("O"); - - /** - * (Optional; PDF 1.2) An action that shall be performed when the page is closed (for example, when the user - * navigates to the next or previous page or follows a link annotation or an outline item). This action applies to - * the page being closed and shall be executed before any other page is opened. - */ - public static final Name PAGE_C_KEY = new Name("C"); - - // Table 196 – Entries in a form field’s additional-actions dictionary - - /** - * (Optional; PDF 1.3) A JavaScript action that shall be performed when the user modifies a character in a text - * field or combo box or modifies the selection in a scrollable list box. This action may check the added text for - * validity and reject or modify it. - */ - public static final Name FORM_K_KEY = new Name("K"); - - /** - * (Optional; PDF 1.3) A JavaScript action that shall be performed before the field is formatted to display its - * value. This action may modify the field’s value before formatting. - */ - public static final Name FORM_F_KEY = new Name("F"); - - /** - * (Optional; PDF 1.3) A JavaScript action that shall be performed when the field’s value is changed. This action - * may check the new value for validity. (The name V stands for “validate.â€) - */ - public static final Name FORM_V_KEY = new Name("V"); - - /** - * (Optional; PDF 1.3) A JavaScript action that shall be performed to recalculate the value of this field when that - * of another field changes. (The name C stands for “calculate.â€) The order in which the document’s fields are - * recalculated shall be defined by the CO entry in the interactive form dictionary - * (see 12.7.2, “Interactive Form Dictionaryâ€). - */ - public static final Name FORM_C_KEY = new Name("C"); - - // Table 197 – Entries in the document catalog’s additional-actions dictionary - - /** - * (Optional; PDF 1.4) A JavaScript action that shall be performed before closing a document. - * (The name WC stands for “will close.â€) - */ - public static final Name CATALOG_WC_KEY = new Name("WC"); - - /** - * (Optional; PDF 1.4) A JavaScript action that shall be performed before saving a document. - * (The name WS stands for “will save.â€) - */ - public static final Name CATALOG_WS_KEY = new Name("WS"); - - /** - * (Optional; PDF 1.4) A JavaScript action that shall be performed after saving a document. - * (The name DS stands for “did save.â€) - */ - public static final Name CATALOG_DS_KEY = new Name("DS"); - - /** - * (Optional; PDF 1.4) A JavaScript action that shall be performed before printing a document. - * (The name WP stands for “will print.â€) - */ - public static final Name CATALOG_WP_KEY = new Name("WP"); - - /** - * (Optional; PDF 1.4) A JavaScript action that shall be performed after printing a document. - * (The name DP stands for “did print.â€) - */ - public static final Name CATALOG_DP_KEY = new Name("DP"); - - public AdditionalActionsDictionary(Library library, HashMap entries) { - super(library, entries); - } - - public Action getAction(Name actionNameKey) { - Object tmp = library.getObject(entries, actionNameKey); - if (tmp != null && tmp instanceof HashMap) { - return Action.buildAction(library, (HashMap) tmp); - } - return null; - } - - public boolean isAnnotationValue(Name actionKey) { - return library.isValidEntry(entries, actionKey); -// return library.getObject(entries, actionKey) != null; - } - - /** - * @see #ANNOTATION_Bl_KEY - */ - public boolean isAnnotationBIValue() { - return library.getObject(entries, ANNOTATION_Bl_KEY) != null; - } - - /** - * @see #ANNOTATION_D_KEY - */ - public boolean isAnnotationDValue() { - return library.getObject(entries, ANNOTATION_D_KEY) != null; - } - - /** - * @see #ANNOTATION_E_KEY - */ - public boolean isAnnotationEValue() { - return library.getObject(entries, ANNOTATION_E_KEY) != null; - } - - /** - * @see #ANNOTATION_FO_KEY - */ - public boolean isAnnotationFOValue() { - return library.getObject(entries, ANNOTATION_FO_KEY) != null; - } - - /** - * @see #ANNOTATION_PC_KEY - */ - public boolean isAnnotationPCValue() { - return library.getObject(entries, ANNOTATION_PC_KEY) != null; - } - - /** - * @see #ANNOTATION_PI_KEY - */ - public boolean isAnnotationPIValue() { - return library.getObject(entries, ANNOTATION_PI_KEY) != null; - } - - /** - * @see #ANNOTATION_PO_KEY - */ - public boolean isAnnotationPOValue() { - return library.getObject(entries, ANNOTATION_PO_KEY) != null; - } - - /** - * @see #ANNOTATION_PV_KEY - */ - public boolean isAnnotationPVValue() { - return library.getObject(entries, ANNOTATION_PV_KEY) != null; - } - - /** - * @see #ANNOTATION_U_KEY - */ - public boolean isAnnotationUValue() { - return library.getObject(entries, ANNOTATION_U_KEY) != null; - } - - /** - * @see #ANNOTATION_X_KEY - */ - public boolean isAnnotationXValue() { - return library.getObject(entries, ANNOTATION_X_KEY) != null; - } - - /** - * @see #CATALOG_DP_KEY - */ - public boolean isCatalogDPValue() { - return library.getObject(entries, CATALOG_DP_KEY) != null; - } - - /** - * @see #CATALOG_DS_KEY - */ - public boolean isCatalogDSValue() { - return library.getObject(entries, CATALOG_DS_KEY) != null; - } - - /** - * @see #CATALOG_WC_KEY - */ - public boolean isCatalogWCValue() { - return library.getObject(entries, CATALOG_WC_KEY) != null; - } - - /** - * @see #CATALOG_WP_KEY - */ - public boolean isCatalogWPValue() { - return library.getObject(entries, CATALOG_WP_KEY) != null; - } - - /** - * @see #CATALOG_WS_KEY - */ - public boolean isCatalogWSValue() { - return library.getObject(entries, CATALOG_WS_KEY) != null; - } - - /** - * @see #FORM_C_KEY - */ - public boolean isFormCValue() { - return library.getObject(entries, FORM_C_KEY) != null; - } - - /** - * @see #FORM_F_KEY - */ - public boolean isFormFValue() { - return library.getObject(entries, FORM_F_KEY) != null; - } - - /** - * @see #FORM_K_KEY - */ - public boolean isFormKValue() { - return library.getObject(entries, FORM_K_KEY) != null; - } - - /** - * @see #FORM_V_KEY - */ - public boolean isFormVValue() { - return library.getObject(entries, FORM_V_KEY) != null; - } - - /** - * @see #PAGE_0_KEY - */ - public boolean isPageOValue() { - return library.getObject(entries, PAGE_0_KEY) != null; - } - - /** - * @see #PAGE_C_KEY - */ - public boolean isPageCValue() { - return library.getObject(entries, PAGE_C_KEY) != null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/ButtonFieldDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/ButtonFieldDictionary.java deleted file mode 100644 index b542270557..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/ButtonFieldDictionary.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * The ButtonFieldDictionary contains all the dictionary entries specific to - * the button widget. - * - * @since 5.1 - */ -public class ButtonFieldDictionary extends VariableTextFieldDictionary { - - /** - * (Radio buttons only) If set, exactly one radio button shall be selected at - * all times; selecting the currently selected button has no effect. If clear, - * clicking the selected button deselects it, leaving no button selected. - */ - public static final int NO_TOGGLE_TO_OFF_BIT_FLAG = 0x4000; - - /** - * If set, the field is a set of radio buttons; if clear, the field is a - * check box. This flag may be set only if the Push button flag is clear. - */ - public static final int RADIO_BIT_FLAG = 0x8000; - - /** - * If set, the field is a push button that does not retain a permanent value. - */ - public static final int PUSH_BUTTON_BIT_FLAG = 0x10000; - - /** - * (PDF 1.5) If set, a group of radio buttons within a radio button field - * that use the same value for the on state will turn on and off in unison; - * that is if one is checked, they are all checked. If clear, the buttons are - * mutually exclusive (the same behavior as HTML radio buttons). - */ - public static final int RADIO_IN_UNISON_BIT_FLAG = 0x1000000; - - public enum ButtonFieldType { - PUSH_BUTTON, RADIO_BUTTON, CHECK_BUTTON - } - - protected ButtonFieldType buttonFieldType; - - @SuppressWarnings("unchecked") - public ButtonFieldDictionary(Library library, HashMap entries) { - super(library, entries); - - } - - /** - * (Radio buttons only) If set, exactly one radio button shall be selected at - * all times; selecting the currently selected button has no effect. If clear, - * clicking the selected button deselects it, leaving no button selected. - * - * @return true if only one button state should be selected at all times. - */ - public boolean isNoToggleToOff() { - return (getFlags() & NO_TOGGLE_TO_OFF_BIT_FLAG) == NO_TOGGLE_TO_OFF_BIT_FLAG; - } - - /** - * If set, the field is a set of radio buttons; if clear, the field is a - * check box. This flag may be set only if the Push button flag is clear. - * - * @return true if button field is of type push button. - */ - public boolean isRadioButton() { - return (getFlags() & RADIO_BIT_FLAG) == RADIO_BIT_FLAG; - } - - /** - * If set, the field is a push button that does not retain a permanent value. - * - * @return true if button field is of type push button. - */ - public boolean isPushButton() { - return (getFlags() & PUSH_BUTTON_BIT_FLAG) == PUSH_BUTTON_BIT_FLAG; - } - - /** - * If set, a group of radio buttons within a radio button field - * that use the same value for the on state will turn on and off in unison; - * that is if one is checked, they are all checked. If clear, the buttons are - * - * @return true if radio buttons in unison; otherwise false. - */ - public boolean isRadioInUnison() { - return (getFlags() & RADIO_IN_UNISON_BIT_FLAG) == RADIO_IN_UNISON_BIT_FLAG; - } - - public ButtonFieldType getButtonFieldType() { - // apply button bit logic - if ((getFlags() & PUSH_BUTTON_BIT_FLAG) == - PUSH_BUTTON_BIT_FLAG) { - buttonFieldType = ButtonFieldType.PUSH_BUTTON; - } else { - // check for checkbox/radio. - if (isRadioButton()) { - buttonFieldType = ButtonFieldType.RADIO_BUTTON; - } else { - buttonFieldType = ButtonFieldType.CHECK_BUTTON; - } - } - return buttonFieldType; - } - - public void setButtonFieldType(ButtonFieldType buttonFieldType) { - this.buttonFieldType = buttonFieldType; - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/CertSeedValueDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/CertSeedValueDictionary.java deleted file mode 100644 index 1da0ae1937..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/CertSeedValueDictionary.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; -import java.util.List; - -/** - * A certificate seed value dictionary (see Table 235) containing information about the characteristics of the - * certificate that shall be used when signing. - */ -public class CertSeedValueDictionary extends Dictionary { - - public static final Name SV_CERT_TYPE_VALUE = new Name("SVCert"); - - /** - * (Optional) A set of bit flags specifying the interpretation of specific entries in this dictionary. - * A value of 1 for the flag means that a signer shall be required to use only the specified values for the entry. - * A value of 0 means that other values are permissible. - *

- * Bit positions are 1 (Subject); 2 (Issuer); 3 (OID); 4 (SubjectDN); 5 (Reserved); 6 (KeyUsage); 7 (URL). - *

- * Default value: 0. - */ - public static final Name Ff_KEY = new Name("Ff"); - - // Bit 1 (Subject) - private static final int Ff_SUBJECT_BIT = 0x1; - // Bit 2 (Issuer) - private static final int Ff_ISSUER_BIT = 0x2; - // Bit 3 (OID) - private static final int Ff_OID_BIT = 0x4; - // Bit 4 (SubjectDN) - private static final int Ff_SUBJECT_DN_BIT = 0x8; - // Bit 5 (Reserved) - private static final int Ff_RESERVED_BIT = 0x10; - // Bit 6 (KeyUsage); and - private static final int Ff_KEY_USAGE_BIT = 0x20; - // Bit 7 (URL). - private static final int Ff_URL_BIT = 0x40; - - /** - * (Optional) An array of byte strings containing DER-encoded X.509v3 certificateChain that are acceptable for - * signing. X.509v3 certificateChain are described in RFC 3280, Internet X.509 Public Key Infrastructure, Certificate - * and Certificate Revocation List (CRL) Profile (see the Bibliography). The value of the corresponding flag in the - * Ff entry indicates whether this is a required constraint. - */ - public static final Name SUBJECT_KEY = new Name("Subject"); - - /** - * (Optional; PDF 1.7) An array of dictionaries, each specifying a Subject Distinguished Name (DN) that shall be - * present within the certificate for it to be acceptable for signing. The certificate ultimately used for the - * digital signature shall contain all the attributes specified in each of the dictionaries in this array. - * (PDF keys and values are mapped to certificate attributes and values.) The certificate is not constrained to use - * only attribute entries from these dictionaries but may contain additional attributes.The Subject Distinguished - * Name is described in RFC 3280 (see the Bibliography). The key can be any legal attribute identifier (OID). - * Attribute names shall contain characters in the set a-z A-Z 0-9 and PERIOD. - *

- * Certificate attribute names are used as key names in the dictionaries in this array. Values of the attributes are - * used as values of the keys. Values shall be text strings. - *

- * The value of the corresponding flag in the Ff entry indicates whether this entry is a required constraint. - */ - public static final Name SUBJECT_DN_KEY = new Name("SubjectDN"); - - /** - * (Optional; PDF 1.7) An array of ASCII strings, where each string specifies an acceptable key-usage extension that - * shall be present in the signing certificate. Multiple strings specify a range of acceptable key-usage extensions. - * The key-usage extension is described in RFC 3280. - *

- * Each character in a string represents a key-usage type, where the order of the characters indicates the key-usage - * extension it represents. The first through ninth characters in the string, from left to right, represent the - * required value for the following key-usage extensions: - *

    - *
  • 1 digitalSignature
  • - *
  • 2 non-Repudiation
  • - *
  • 3 keyEncipherment
  • - *
  • 4 dataEncipherment
  • - *
  • 5 keyAgreement
  • - *
  • 6 keyCertSign
  • - *
  • 7 cRLSign
  • - *
  • 8 encipherOnly
  • - *
  • 9 decipherOnly
  • - *
- * Any additional characters shall be ignored. Any missing characters or characters that are not one of the following - * values, shall be treated as X. The following character values shall be supported: - *
    - *
  • 0 Corresponding key-usage shall not be set.
  • - *
  • 1 Corresponding key-usage shall be set.
  • - *
  • X State of the corresponding key-usage does not matter.
  • - *
- * EXAMPLE 1
- * The string values 1 and 1XXXXXXXX represent settings where the key-usage type digitalSignature is set - * and the state of all other key-usage types do not matter. - * The value of the corresponding flag in the Ff entry indicates whether this is a required constraint. - */ - public static final Name KEY_USAGE_KEY = new Name("KeyUsage"); - - /** - * (Optional) An array of byte strings containing DER-encoded X.509v3 certificateChain of acceptable issuers. If the - * signer's certificate refers to any of the specified issuers (either directly or indirectly), the certificate shall - * be considered acceptable for signing. The value of the corresponding flag in the Ff entry indicates whether this - * is a required constraint. - *

- * This array may contain self-signed certificateChain. - */ - public static final Name ISSUER_KEY = new Name("Issuer"); - - /** - * (Optional) An array of byte strings that contain Object Identifiers (OIDs) of the certificate policies that shall - * be present in the signing certificate. - *

- * EXAMPLE 2
- * An example of such a string is: (2.16.840.1.113733.1.7.1.1). - *

- * This field shall only be used if the value of Issuer is not empty. The certificate policies extension is - * described in RFC 3280 (see the Bibliography). The value of the corresponding flag in the Ff entry indicates - * whether this is a required constraint. - */ - public static final Name OID_KEY = new Name("OID"); - - /** - * (Optional) A URL, the use for which shall be defined by the URLType entry. - */ - public static final Name URL_KEY = new Name("URL"); - - /** - * (Optional; PDF 1.7) A name indicating the usage of the URL entry. There are standard uses and there can be - * implementation-specific uses for this URL. The following value specifies a valid standard usage: - *

- * Browser - The URL references content that shall be displayed in a web browser to allow enrolling for a new - * credential if a matching credential is not found. The Ff attribute's URL bit shall be ignored for this usage. - *

- * Third parties may extend the use of this attribute with their own attribute values, which shall conform to the - * guidelines described in Annex E. - *

- * The default value is Browser. - */ - public static final Name URL_TYPE_KEY = new Name("URLType"); - - private int flags; - - public CertSeedValueDictionary(Library library, HashMap entries) { - super(library, entries); - - flags = library.getInt(entries, Ff_KEY); - } - - public List getSubject() { - Object tmp = library.getArray(entries, SUBJECT_KEY); - if (tmp != null) { - return (List) tmp; - } else { - return null; - } - } - - public List getSubjectDn() { - Object tmp = library.getArray(entries, SUBJECT_DN_KEY); - if (tmp != null) { - return (List) tmp; - } else { - return null; - } - } - - public List getKeyUsage() { - Object tmp = library.getArray(entries, KEY_USAGE_KEY); - if (tmp != null) { - return (List) tmp; - } else { - return null; - } - } - - public List getIssuer() { - Object tmp = library.getArray(entries, ISSUER_KEY); - if (tmp != null) { - return (List) tmp; - } else { - return null; - } - } - - public List getIOD() { - Object tmp = library.getArray(entries, OID_KEY); - if (tmp != null) { - return (List) tmp; - } else { - return null; - } - } - - public String getUrl() { - return library.getString(entries, URL_KEY); - } - - public Name getUrlType() { - return library.getName(entries, URL_TYPE_KEY); - } - - public boolean isSubject() { - return ((flags & Ff_SUBJECT_BIT) - == Ff_SUBJECT_BIT); - } - - public boolean isIssuer() { - return ((flags & Ff_ISSUER_BIT) - == Ff_ISSUER_BIT); - } - - public boolean isOid() { - return ((flags & Ff_OID_BIT) - == Ff_OID_BIT); - } - - public boolean isSubjectDn() { - return ((flags & Ff_SUBJECT_DN_BIT) - == Ff_SUBJECT_DN_BIT); - } - - public boolean isReserved() { - return ((flags & Ff_RESERVED_BIT) - == Ff_RESERVED_BIT); - } - - public boolean isKeyUsage() { - return ((flags & Ff_KEY_USAGE_BIT) - == Ff_KEY_USAGE_BIT); - } - - public boolean isUrl() { - return ((flags & Ff_URL_BIT) - == Ff_URL_BIT); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/ChoiceFieldDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/ChoiceFieldDictionary.java deleted file mode 100644 index 9e5c2205eb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/ChoiceFieldDictionary.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * The ChoiceFieldDictionary contains all the dictionary entries specific to - * the choice widget. - * - * @since 5.1 - */ -public class ChoiceFieldDictionary extends VariableTextFieldDictionary { - - /** - * (Optional) An array of options that shall be presented to the user. Each - * element of the array is either a text string representing one of the - * available options or an array consisting of two text strings: the option’s - * export value and the text that shall be displayed as the name of the option. - *

- * If this entry is not present, no choices should be presented to the user. - */ - public static final Name OPT_KEY = new Name("Opt"); - - /** - * (Optional) For scrollable list boxes, the top index (the index in the Opt - * array of the first option visible in the list). Default value: 0. - */ - public static final Name TI_KEY = new Name("TI"); - - /** - * (Sometimes required, otherwise optional; PDF 1.4) For choice fields that - * allow multiple selection (MultiSelect flag set), an array of integers, - * sorted in ascending order, representing the zero-based indices in the Opt - * array of the currently selected option items. This entry shall be used - * when two or more elements in the Opt array have different names but the - * same export value or when the value of the choice field is an array. - * This entry should not be used for choice fields that do not allow multiple - * selection. If the items identified by this entry differ from those in the - * V entry of the field dictionary (see discussion following this Table), - * the V entry shall be used. - */ - public static final Name I_KEY = new Name("I"); - - /** - * If set, the field is a combo box; if clear, the field is a list box. - */ - public static final int COMBO_BIT_FLAG = 0x20000; - - /** - * If set, the combo box shall include an editable text box as well as a - * drop-down list; if clear, it shall include only a drop-down list. This - * flag shall be used only if the Combo flag is set. - */ - public static final int EDIT_BIT_FLAG = 0x40000; - - /** - * If set, the field’s option items shall be sorted alphabetically. This flag - * is intended for use by writers, not by readers. Conforming readers shall - * display the options in the order in which they occur in the Opt array - * (see Table 231). - */ - public static final int SORT_BIT_FLAG = 0x80000; - - /** - * (PDF 1.4) If set, more than one of the field’s option items may be selected - * simultaneously; if clear, at most one item shall be selected. - */ - public static final int MULTI_SELECT_BIT_FLAG = 0x200000; - - /** - * (PDF 1.4) If set, text entered in the field shall not be spell-checked. - * This flag shall not be used unless the Combo and Edit flags are both set. - */ - public static final int CHOICE_DO_NOT_SPELL_CHECK_BIT_FLAG = 0x400000; - - /** - * (PDF 1.5) If set, the new value shall be committed as soon as a selection - * is made (commonly with the pointing device). In this case, supplying a - * value for a field involves three actions: selecting the field for fill-in, - * selecting a choice for the fill-in value, and leaving that field, which - * finalizes or “commits†the data choice and triggers any actions associated - * with the entry or changing of this data. If this flag is on, then processing - * does not wait for leaving the field action to occur, but immediately - * proceeds to the third step. - *

- * This option enables applications to perform an action once a selection is - * made, without requiring the user to exit the field. If clear, the new - * value is not committed until the user exits the field. - */ - public static final int COMMIT_ON_SEL_CHANGE_BIT_FLAG = 0x4000000; - - public enum ChoiceFieldType { - CHOICE_COMBO, CHOICE_EDITABLE_COMBO, - CHOICE_LIST_SINGLE_SELECT, CHOICE_LIST_MULTIPLE_SELECT - } - - protected ChoiceFieldType choiceFieldType; - protected ArrayList options; - protected int topIndex; - protected ArrayList indexes; - - @SuppressWarnings("unchecked") - public ChoiceFieldDictionary(Library library, HashMap entries) { - super(library, entries); - - // options/list times. - org.icepdf.core.pobjects.security.SecurityManager securityManager = library.getSecurityManager(); - Object value = library.getArray(entries, OPT_KEY); - if (value == null) { - FieldDictionary parent = getParent(); - value = library.getArray(parent.getEntries(), OPT_KEY); - } - if (value != null) { - ArrayList opts = (ArrayList) value; - options = new ArrayList(opts.size()); - for (Object opt : opts) { - if (opt instanceof StringObject) { - StringObject tmp = (StringObject) opt; - String tmpString = tmp.getDecryptedLiteralString(securityManager); - options.add(new ChoiceOption(tmpString, tmpString)); - } else if (opt instanceof List) { - List tmp = (List) opt; - StringObject tmp1StingObject = (StringObject) tmp.get(0); - String tmpString1 = tmp1StingObject.getDecryptedLiteralString(securityManager); - StringObject tmp2StingObject = (StringObject) tmp.get(1); - String tmpString2 = tmp2StingObject.getDecryptedLiteralString(securityManager); - options.add(new ChoiceOption(tmpString1, tmpString2)); - } - } - } else { - options = null; - } - - // determine combo or list - int flags = getFlags(); - if ((flags & COMBO_BIT_FLAG) == - COMBO_BIT_FLAG) { - // check for editable - if ((flags & EDIT_BIT_FLAG) == - EDIT_BIT_FLAG) { - choiceFieldType = ChoiceFieldType.CHOICE_EDITABLE_COMBO; - } else { - choiceFieldType = ChoiceFieldType.CHOICE_COMBO; - } - } else { - // check for selection mode - if ((flags & MULTI_SELECT_BIT_FLAG) == - MULTI_SELECT_BIT_FLAG) { - choiceFieldType = ChoiceFieldType.CHOICE_LIST_MULTIPLE_SELECT; - } else { - choiceFieldType = ChoiceFieldType.CHOICE_LIST_SINGLE_SELECT; - } - } - // select the selected index. - if (choiceFieldType == ChoiceFieldType.CHOICE_LIST_SINGLE_SELECT) { - value = library.getObject(entries, TI_KEY); - if (value instanceof Number) { - topIndex = ((Number) value).intValue(); - } - } - value = library.getObject(entries, I_KEY); - if (value instanceof ArrayList) { - ArrayList tmp = (ArrayList) value; - indexes = new ArrayList(tmp.size()); - for (Number aTmp : tmp) { - indexes.add(aTmp.intValue()); - } - } - // we might not have an I_key but should have a value to work with if so we build the index our self. - if (indexes == null && options != null) { - indexes = new ArrayList(1); - for (int i = 0, j = 0, max = options.size(); i < max; i++) { - if (options.get(i).getLabel().equals(value)) { - indexes.set(j, i); - j++; - } - } - } - } - - /** - * Regular field value writing takes place as well as the update of the I (indexes) entry in the dictionary. - * TODO: Further work is needed to fully support multiSelect values. - * @param fieldValue value to write. - * @param parentReference parent reference. - */ - @Override - public void setFieldValue(Object fieldValue, Reference parentReference) { - // update the index to reflect the change, - String selectedValue = null; - if (fieldValue instanceof String) { - selectedValue = (String) fieldValue; - super.setFieldValue(selectedValue, parentReference); - } else if (fieldValue instanceof StringObject) { - StringObject tmp = (StringObject) fieldValue; - selectedValue = tmp.getDecryptedLiteralString(library.getSecurityManager()); - super.setFieldValue(selectedValue, parentReference); - }else if (fieldValue instanceof ChoiceOption) { - ChoiceOption tmp = (ChoiceOption) fieldValue; - selectedValue = tmp.getValue(); - super.setFieldValue(selectedValue, parentReference); - } - if (indexes != null) { - indexes.clear(); - }else{ - indexes = new ArrayList(); - } - for (int i = 0, j = 0, max = options.size(); i < max; i++) { - if (options.get(i).getLabel().equals(selectedValue)) { - indexes.add(j, i); - } - } - indexes.trimToSize(); - // store the new indexes in the dictionary. - entries.put(I_KEY, indexes); - } - - public ChoiceOption buildChoiceOption(String label, String value) { - return new ChoiceOption(label, value); - } - - public ChoiceFieldType getChoiceFieldType() { - return choiceFieldType; - } - - /** - * For scrollable list boxes, the top index (the index in the Opt array of the first option visible in the list). - * Default value: 0. - * - * @return the top index of a scrollable list boxes. - */ - public int getTopIndex() { - return topIndex; - } - - public void setTopIndex(int topIndex) { - this.topIndex = topIndex; - } - - public ArrayList getIndexes() { - return indexes; - } - - /** - * For choice fields that allow multiple selection (MultiSelect flag set), an array of integers, sorted in - * ascending order, representing the zero-based indices in the Opt array of the currently selected option items. - * This entry shall be used when two or more elements in the Opt array have different names but the same export - * value or when the value of the choice field is an array. This entry should not be used for choice fields that - * do not allow multiple selection. If the items identified by this entry differ from those in the V entry of the - * field dictionary (see discussion following this Table), the V entry shall be used. - * - * @param indexes list of selected indexes for multiple selection. - */ - public void setIndexes(ArrayList indexes) { - this.indexes = indexes; - } - - /** - * An array of options that shall be presented to the user. Each element of the array is either a text - * string representing one of the available options or an array consisting of two text strings: the option’s - * export value and the text that shall be displayed as the name of the option. - *

- * If this entry is not present, no choices should be presented to the user. - * - * @return choice options. - */ - public ArrayList getOptions() { - return options; - } - - public void setOptions(ArrayList options) { - this.options = options; - } - - public class ChoiceOption { - private String label; - private String value; - private boolean isSelected; - - public ChoiceOption(String label, String value) { - this.label = label; - this.value = value; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public String toString() { - return label; - } - - public boolean isSelected() { - return isSelected; - } - - public void setIsSelected(boolean isSelected) { - this.isSelected = isSelected; - } - } - - /** - * If set, the field’s option items shall be sorted alphabetically. This flag is intended for use by - * writers, not by readers. Conforming readers shall display the options in the order in which they - * occur in the Opt array. - * - * @return true if field items are to be sorted. - */ - public boolean isSortFields() { - return (getFlags() & SORT_BIT_FLAG) == SORT_BIT_FLAG; - } - - /** - * If set, more than one of the field’s option items may be selected simultaneously; if clear, at most - * one item shall be selected. - * - * @return true if more then one field can be selected, otherwise false. - */ - public boolean isMultiSelect() { - return (getFlags() & MULTI_SELECT_BIT_FLAG) == MULTI_SELECT_BIT_FLAG; - } - - /** - * If set, the new value shall be committed as soon as a selection is made (commonly with the pointing device). - * In this case, supplying a value for a field involves three actions: selecting the field for fill-in, selecting - * a choice for the fill-in value, and leaving that field, which finalizes or “commits†the data choice and triggers - * any actions associated with the entry or changing of this data. If this flag is on, then processing does not wait - * for leaving the field action to occur, but immediately proceeds to the third step. - *

- * This option enables applications to perform an action once a selection is made, without requiring the user to - * exit the field. If clear, the new value is not committed until the user exits the field. - * - * @return true if commit on set change, otherwise false. - */ - public boolean isCommitOnSetChange() { - return (getFlags() & COMMIT_ON_SEL_CHANGE_BIT_FLAG) == COMMIT_ON_SEL_CHANGE_BIT_FLAG; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/DocMDPTransferParam.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/DocMDPTransferParam.java deleted file mode 100644 index 49a9922385..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/DocMDPTransferParam.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * The DocMDP transform method shall be used to detect modifications relative to a signature field that is signed by - * the author of a document (the person applying the first signature). A document can contain only one signature field - * that contains a DocMDP transform method; it shall be the first signed field in the document. It enables the author - * to specify what changes shall be permitted to be made the document and what changes invalidate the author's signature. - *

- * NOTE
- * As discussed earlier, MDP stands for modification detection and prevention. Certification signatures that use the - * DocMDP transform method enable detection of disallowed changes specified by the author. In addition, disallowed - * changes can also be prevented when the signature dictionary is referred to by the DocMDP entry in the permissions - * dictionary (see 12.8.4, Permissions). - *

- * A certification signature should have a legal attestation dictionary (see 12.8.5, Legal Content Attestations) that - * specifies all content that might result in unexpected rendering of the document contents, along with the author's - * attestation to such content. This dictionary may be used to establish an author's intent if the integrity of the - * document is questioned. - *

- * The P entry in the DocMDP transform parameters dictionary (see Table 254) shall indicate the author's specification - * of which changes to the document will invalidate the signature. (These changes to the document shall also be - * prevented if the signature dictionary is referred from the DocMDP entry in the permissions dictionary.) A value of 1 - * for P indicates that the document shall be final; that is, any changes shall invalidate the signature. The values 2 - * and 3 shall permit modifications that are appropriate for form field or comment work flows. - */ -public class DocMDPTransferParam extends Dictionary implements TransformParams { - - /** - * The access permissions granted for this document. - * Default value: 2. - */ - public static final Name PERMISSION_KEY = new Name("P"); - - /** - * No changes to the document shall be permitted; any change to the document shall invalidate the signature. - */ - public static final int PERMISSION_VALUE_NO_CHANGES = 1; - - /** - * 2Permitted changes shall be filling in forms, instantiating page templates, and signing; other changes shall - * invalidate the signature. - */ - public static final int PERMISSION_VALUE_FORMS_SIGNING = 2; - - /** - * Permitted changes shall be the same as for 2, as well as annotation creation, deletion, and modification; other - * changes shall invalidate the signature. - */ - public static final int PERMISSION_VALUE_ANNOTATION_CRUD = 3; - - public DocMDPTransferParam(Library library, HashMap entries) { - super(library, entries); - } - - /** - * Get the access permissions granted for this document. - * - * @return PERMISSION_VALUE_NO_CHANGES, PERMISSION_VALUE_FORMS_SIGNING, PERMISSION_VALUE_ANNOTATION_CRUD or zero - * if not set. - */ - public int getPermissions() { - return library.getInt(entries, PERMISSION_KEY); - } - - /** - * Gets the DocMDP transform parameters dictionary version. The only valid value shall be 1.2. - * NOTE
- * this value is a name object, not a number. - * - * @return always returns 1.2 as a name. - */ - public Name getVersion() { - return new Name("1.2"); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/FieldDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/FieldDictionary.java deleted file mode 100644 index b117ed86e8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/FieldDictionary.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.annotations.AbstractWidgetAnnotation; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -/** - * Each field in a document’s interactive form shall be defined by a field - * dictionary, which shall be an indirect object. The field dictionaries may be - * organized hierarchically into one or more tree structures. Many field - * attributes are inheritable, meaning that if they are not explicitly specified - * for a given field, their values are taken from those of its parent in the field - * hierarchy. Such inheritable attributes shall be designated as such in the - * Tables 220 and 221. The designation (Required; inheritable) means that an - * attribute shall be defined for every field, whether explicitly in its own - * field dictionary or by inheritance from an ancestor in the hierarchy. Table - * 220 shows those entries that are common to all field dictionaries, regardless - * of type. Entries that pertain only to a particular type of field are described - * in the relevant sub-clauses in Table 220. - * - * @since 5.0 - */ -public class FieldDictionary extends Dictionary { - - private static final Logger logger = - Logger.getLogger(FieldDictionary.class.toString()); - - /** - * Required for terminal fields; inheritable) The type of field that this - * dictionary describes: - *

- * Button -> Button (see 12.7.4.2, “Button Fieldsâ€) - *

- * Text -> Text (see 12.7.4.3, “Text Fieldsâ€) - *

- * Choice -> Choice (see 12.7.4.4, “Choice Fieldsâ€) - *

- * Signature(PDF 1.3) -> Signature (see 12.7.4.5, “Signature Fieldsâ€) - *

- * This entry may be present in a non-terminal field (one whose descendants - * are fields) to provide an inheritable FT value. However, a non-terminal - * field does not logically have a type of its own; it is merely a container - * for inheritable attributes that are intended for descendant terminal - * fields of any type. - */ - public static final Name FT_KEY = new Name("FT"); - - /** - * (Sometimes required, as described below) An array of indirect references - * to the immediate children of this field. - *

- * In a non-terminal field, the Kids array shall refer to field dictionaries - * that are immediate descendants of this field. In a terminal field, the Kids - * array ordinarily shall refer to one or more separate widget annotations that - * are associated with this field. However, if there is only one associated - * widget annotation, and its contents have been merged into the field dictionary, - * Kids shall be omitted. - */ - public static final Name KIDS_KEY = new Name("Kids"); - /** - * (Required if this field is the child of another in the field hierarchy; - * absent otherwise) The field that is the immediate parent of this one (the - * field, if any, whose Kids array includes this field). A field can have at - * most one parent; that is, it can be included in the Kids array of at most - * one other field. - */ - public static final Name PARENT_KEY = new Name("Parent"); - /** - * (Optional) The partial field name (see 12.7.3.2, “Field Namesâ€). - */ - public static final Name T_KEY = new Name("T"); - /** - * (Optional; PDF 1.3) An alternate field name that shall be used in place - * of the actual field name wherever the field shall be identified in the - * user interface (such as in error or status messages referring to the field). - * This text is also useful when extracting the document’s contents in support - * of accessibility to users with disabilities or for other purposes - * (see 14.9.3, “Alternate Descriptionsâ€). - */ - public static final Name TU_KEY = new Name("TU"); - /** - * (Optional; PDF 1.3) The mapping name that shall be used when exporting - * interactive form field data from the document. - */ - public static final Name TM_KEY = new Name("TM"); - /** - * (Optional; inheritable) A set of flags specifying various characteristics - * of the field (see Table 221). Default value: 0. - */ - public static final Name Ff_KEY = new Name("Ff"); - /** - * (Optional; inheritable) The field’s value, whose format varies depending - * on the field type. See the descriptions of individual field types for - * further information. - */ - public static final Name V_KEY = new Name("V"); - /** - * (Optional; inheritable) The default value to which the field reverts when - * a reset-form action is executed (see 12.7.5.3, “Reset-Form Actionâ€). The - * format of this value is the same as that of V. - */ - public static final Name DV_KEY = new Name("DV"); - /** - * (Optional; PDF 1.2) An additional-actions dictionary defining the field’s - * behaviour in response to various trigger events (see 12.6.3, “Trigger Eventsâ€). - * This entry has exactly the same meaning as the AA entry in an annotation - * dictionary (see 12.5.2, “Annotation Dictionariesâ€). - */ - public static final Name AA_KEY = new Name("AA"); - - /** general field flags **/ - - /** - * If set, the user may not change the value of the field. Any associated - * widget annotations will not interact with the user; that is, they will - * not respond to mouse clicks or change their appearance in response to mouse - * motions. This flag is useful for fields whose values are computed or - * imported from a database. - */ - public static final int READ_ONLY_BIT_FLAG = 0x1; - - /** - * If set, the field shall have a value at the time it is exported by a - * submit-form action (see 12.7.5.2, “Submit-Form Actionâ€). - */ - public static final int REQUIRED_BIT_FLAG = 0x2; - /** - * If set, the field shall not be exported by a submit-form action (see 12.7.5.2, “Submit-Form Actionâ€). - */ - public static final int NO_EXPORT_BIT_FLAG = 0x4; - - protected Name fieldType; - protected FieldDictionary parentField; - protected ArrayList kids; - - protected String partialFieldName; - protected String alternativeFieldName; - protected String exportMappingName; - private int flags; - protected Object fieldValue; - protected Object defaultFieldValue; - protected AdditionalActionsDictionary additionalActionsDictionary; - - @SuppressWarnings("unchecked") - public FieldDictionary(Library library, HashMap entries) { - super(library, entries); - - // field name - Object value = library.getObject(entries, T_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - partialFieldName = Utils.convertStringObject(library, text); - } else if (value instanceof String) { - partialFieldName = (String) value; - } - // alternate field name. - value = library.getObject(entries, TU_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - alternativeFieldName = Utils.convertStringObject(library, text); - } else if (value instanceof String) { - alternativeFieldName = (String) value; - } - // mapping name for data export. - value = library.getObject(entries, TM_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - exportMappingName = Utils.convertStringObject(library, text); - } else if (value instanceof String) { - exportMappingName = (String) value; - } - - // value field -// getFieldValue(); - // todo default value, see 12.7.5.3, Reset-Form Action. - value = library.getObject(entries, DV_KEY); - if (value != null) { - defaultFieldValue = value; - } - - value = library.getObject(entries, AA_KEY); - if (value != null && value instanceof HashMap) { - additionalActionsDictionary = new AdditionalActionsDictionary(library, (HashMap)value); - } - - } - - /** - * Gets the kids of of terminal and non terminal fields. For non-terminal this - * can be a mix of field data and widget annotations. And for terminal notes - * the array will only contain widget annotations. - * - * @return list of child elements. - */ - @SuppressWarnings("unchecked") - public ArrayList getKids() { - // find some kids. - if (kids == null) { - Object value = library.getObject(entries, KIDS_KEY); - if (value != null && value instanceof List) { - List children = (List) value; - kids = new ArrayList(children.size()); - Object tmp; - for (Reference aChildren : children) { - tmp = library.getObject(aChildren); - // have a deeper structure, shouldn't happen though or at least no examples yet. - if (tmp instanceof PObject){ - tmp = ((PObject)tmp).getObject(); - } - if (tmp instanceof HashMap) { - kids.add(FieldDictionaryFactory.buildField(library, (HashMap) tmp)); - } else if (tmp instanceof AbstractWidgetAnnotation) { - kids.add(tmp); - } - } - } - } - return kids; - } - - public FieldDictionary getParent() { - // parent field there is an intermediary parent field dictionary define, not present - // if the widget annotation and dictionary have been flattened. - if (parentField == null) { - Object value = library.getObject(entries, PARENT_KEY); - if (value instanceof HashMap) { - parentField = FieldDictionaryFactory.buildField(library, (HashMap) value); - if (parentField != null) { - parentField.setPObjectReference((Reference) entries.get(PARENT_KEY)); - } - } - } - return parentField; - } - - public Name getFieldType() { - // get teh field type. - if (fieldType == null) { - Object value = library.getName(entries, FT_KEY); - if (value != null) { - fieldType = (Name) value; - } else { - if (getParent() != null) { - fieldType = parentField.getFieldType(); - } - } - } - return fieldType; - } - - public int getFlags() { - // behaviour flags - flags = library.getInt(entries, Ff_KEY); - // check parent for flags value. - if (flags == 0) { - FieldDictionary parent = getParent(); - if (parent != null) { - flags = parent.getFlags(); - } - } - return flags; - } - - public String getPartialFieldName() { - return partialFieldName; - } - - public String getAlternativeFieldName() { - return alternativeFieldName; - } - - public String getExportMappingName() { - return exportMappingName; - } - - /** - * If set, the user may not change the value of the field. Any associated widget annotations will not interact with - * the user; that is, they will not respond to mouse clicks or change their appearance in response to mouse motions. - * This flag is useful for fields whose values are computed or imported from a database. - * - * @return true if read only, otherwise false. - */ - public boolean isReadOnly() { - return ((flags & READ_ONLY_BIT_FLAG) - == READ_ONLY_BIT_FLAG); - } - - /** - * If set, the field shall have a value at the time it is exported by a submit-form action - * - * @return true if value is required, otherwise false. - */ - public boolean isRequired() { - return ((flags & REQUIRED_BIT_FLAG) - == REQUIRED_BIT_FLAG); - } - - /** - * If set, the field shall not be exported by a submit-form action. - * - * @return true if no value should be exported, otherwise false. - */ - public boolean isNoExport() { - return ((flags & NO_EXPORT_BIT_FLAG) - == NO_EXPORT_BIT_FLAG); - } - - /** - * The T entry in the field dictionary (see Table 220) holds a text string defining the field’s partial field name. - * The fully qualified field name is not explicitly defined but shall be constructed from the partial field names - * of the field and all of its ancestors. - *

- * This method will climb back up the inheritance tree to build the name. - * - * @return fully quality name of the field. - */ - public String getFullyQualifiedFieldName() { - String qualifiedFieldName = partialFieldName; - if (parentField != null) { - return parentField.getFullyQualifiedFieldName().concat(".").concat(partialFieldName); - } - return qualifiedFieldName; - } - - public Object getFieldValue() { - Object value = library.getObject(entries, V_KEY); - if (value instanceof Name) { - fieldValue = value; - } else if (value instanceof StringObject) { - StringObject text = (StringObject) value; - fieldValue = Utils.convertStringObject(library, text); - } else if (value instanceof String) { - fieldValue = value; - } else { - fieldValue = ""; - } - return fieldValue; - } - - public boolean hasFieldValue(){ - return entries.containsKey(V_KEY); - } - - public boolean hasDefaultValue(){ - return entries.containsKey(DV_KEY); - } - - /** - * Set the value field of the field dictionary (/V). The value can be anything but special attention is given - * to Strings especially if the document is already encrypted. We need to stored String in an Encrypted environment - * as encrypted so that we can write it correctly later. - * - * @param fieldValue value to write. - * @param parentReference parent reference. - */ - public void setFieldValue(Object fieldValue, Reference parentReference) { - this.fieldValue = fieldValue; - if (fieldValue instanceof String) { - // make sure we store an encrypted documents string as encrypted - setString(V_KEY, (String) fieldValue); - } else { - entries.put(V_KEY, fieldValue); - } - } - - - public Object getDefaultFieldValue() { - return defaultFieldValue; - } - - public AdditionalActionsDictionary getAdditionalActionsDictionary() { - return additionalActionsDictionary; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/FieldDictionaryFactory.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/FieldDictionaryFactory.java deleted file mode 100644 index 756aced2e9..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/FieldDictionaryFactory.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * The FieldDictionaryFactory is responsible for building out the interactive form field tree. When a none terminal - * field is encountered this factor can be used to build an appropriate field dictionary for the given /FT key. - * - * @since 5.2 - */ -public class FieldDictionaryFactory { - - public static final Name TYPE_BUTTON = new Name("Btn"); - public static final Name TYPE_TEXT = new Name("Tx"); - public static final Name TYPE_CHOICE= new Name("Ch"); - public static final Name TYPE_SIGNATURE = new Name("Sig"); - - private FieldDictionaryFactory() {} - - /** - * Creates a new field dictionary object of the type specified by the type constant. - * - * @param library library to register action with - * @param entries field name value pairs. - * @return new field dictionary object of the specified field type. - */ - public static FieldDictionary buildField(Library library, - HashMap entries) { - FieldDictionary fieldDictionary = null; - Name fieldType = library.getName(entries, FieldDictionary.FT_KEY); - if (TYPE_BUTTON.equals(fieldType)) { - fieldDictionary = new ButtonFieldDictionary(library, entries); - } else if (TYPE_TEXT.equals(fieldType)) { - fieldDictionary = new TextFieldDictionary(library, entries); - } else if (TYPE_CHOICE.equals(fieldType)) { - fieldDictionary = new ChoiceFieldDictionary(library, entries); - } else if (TYPE_SIGNATURE.equals(fieldType)) { - fieldDictionary = new SignatureFieldDictionary(library, entries); - }else{ - fieldDictionary = new FieldDictionary(library, entries); - } - return fieldDictionary; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/FieldMDPTransferParam.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/FieldMDPTransferParam.java deleted file mode 100644 index d44ff5504c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/FieldMDPTransferParam.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * The FieldMDP transform method shall be used to detect changes to the values of a list of form fields. - *

- * On behalf of a document author creating a document containing both form fields and signatures the following shall be - * supported by conforming writers: - *

    - *
  • The author specifies that form fields shall be filled in without invalidating the approval or certification - * signature. The P entry of the DocMDP transform parameters dictionary shall be set to either 2 or 3 (see Table 254).
  • - *
  • The author can also specify that after a specific recipient has signed the document, any modifications to - * specific form fields shall invalidate that recipient's signature. There shall be a separate signature field for - * each designated recipient, each having an associated signature field lock dictionary (see Table 233) specifying - * the form fields that shall be locked for that user.
  • - *
  • When the recipient signs the field, the signature, signature reference, and transform parameters dictionaries - * shall be created. The Action and Fields entries in the transform parameters dictionary shall be copied from the - * corresponding fields in the signature field lock dictionary.
  • - *
- * NOTE
- * This copying is done because all objects in a signature dictionary must be direct objects if the dictionary contains - * a byte range signature. Therefore, the transform parameters dictionary cannot reference the signature field lock - * dictionary indirectly. - *

- * FieldMDP signatures shall be validated in a similar manner to DocMDP signatures. See Validating Signatures That Use - * the DocMDP Transform Method in 12.8.2.2, DocMDP for details. - */ -public class FieldMDPTransferParam extends Dictionary implements TransformParams { - - /** - * A name that, along with the Fields array, describes which form fields do not permit changes after the signature - * is applied. - */ - public static final Name ACTION_KEY = new Name("Action"); - - /** - * All form fields. - */ - public static final Name ACTION_VALUE_ALL = new Name("ALL"); - - /** - * Only those form fields that specified in Fields. - */ - public static final Name ACTION_VALUE_INCLUDE = new Name("Include"); - - /** - * Only those form fields not specified in Fields. - */ - public static final Name ACTION_VALUE_EXCLUDE = new Name("Exclude"); - - /** - * (Required if Action is Include or Exclude) An array of text strings containing field names. - */ - public static final Name FIELDS_KEY = new Name("Fields"); - - public FieldMDPTransferParam(Library library, HashMap entries) { - super(library, entries); - } - - /** - * A name that, along with the Fields array, describes which form fields do not permit changes after the signature - * is applied. - * - * @return one of the action values if set, otherwise null. - */ - public Name getAction() { - return library.getName(entries, ACTION_KEY); - } - - /** - * (Required if Action is Include or Exclude) An array of text strings containing field names. - * - * @return array of text string, null if not set. - */ - public ArrayList getFields() { - return (ArrayList) library.getArray(entries, FIELDS_KEY); - } - - /** - * (Optional: PDF 1.5 required) The transform parameters dictionary version. The value for PDF 1.5 and - * later shall be 1.2. - * NOTE
- * this value is a name object, not a number. - * - * @return Default value: 1.2. - */ - public Name getVersion() { - return library.getName(entries, VERSION_KEY); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/InteractiveForm.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/InteractiveForm.java deleted file mode 100644 index e20873be50..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/InteractiveForm.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -/** - * An interactive form (PDF 1.2)—sometimes referred to as an AcroForm is a - * collection of fields for gathering information interactively from the user. - * A PDF document may contain any number of fields appearing on any combination - * of pages, all of which make up a single, global interactive form spanning - * the entire document. - *

- * Each field in a document’s interactive form shall be defined by a field - * dictionary (see 12.7.3, “Field Dictionariesâ€). For purposes of definition and - * naming, the fields can be organized hierarchically and can inherit attributes - * from their ancestors in the field hierarchy. A field’s children in the hierarchy - * may also include widget annotations (see 12.5.6.19, “Widget Annotationsâ€) that - * define its appearance on the page. A field that has children that are fields - * is called a non-terminal field. A field that does not have children that are - * fields is called a terminal field. - *

- * The contents and properties of a document’s interactive form shall be defined - * by an interactive form dictionary that shall be referenced from the AcroForm - * entry in the document catalogue (see 7.7.2, “Document Catalogâ€). - * - * @since 5.1 - */ -public class InteractiveForm extends Dictionary { - - /** - * (Required) An array of references to the document’s root fields(those with - * no ancestors in the field hierarchy). - */ - public static final Name FIELDS_KEY = new Name("Fields"); - /** - * (Optional) A flag specifying whether to construct appearance streams and - * appearance dictionaries for all widget annotations in the document (see - * 12.7.3.3, “Variable Textâ€). Default value: false. - */ - public static final Name NEEDS_APPEARANCES_KEY = new Name("NeedAppearances"); - /** - * (Optional; PDF 1.3) A set of flags specifying various document-level - * characteristics related to signature fields (see Table 219, and 12.7.4.5, - * “Signature Fieldsâ€). Default value: 0. - */ - public static final Name SIG_FLAGS_KEY = new Name("SigFlags"); - /** - * (Required if any fields in the document have additional-actions - * dictionaries containing a C entry; PDF 1.3) An array of indirect - * references to field dictionaries with calculation actions, defining the - * calculation order in which their values will be recalculated when the - * value of any field changes (see 12.6.3, “Trigger Eventsâ€). - */ - public static final Name CO_KEY = new Name("CO"); - /** - * (Optional) A resource dictionary (see 7.8.3, “Resource Dictionariesâ€) - * containing default resources (such as fonts, patterns, or colour spaces) - * that shall be used by form field appearance streams. At a minimum, this - * dictionary shall contain a Font entry specifying the resource name and - * font dictionary of the default font for displaying text. - */ - public static final Name DR_KEY = new Name("DR"); - /** - * (Optional) A document-wide default value for the DA attribute of variable - * text fields (see 12.7.3.3, “Variable Textâ€). - */ - public static final Name DA_KEY = new Name("DA"); - /** - * (Optional) A document-wide default value for the Q attribute of variable - * text fields (see 12.7.3.3, “Variable Textâ€). - */ - public static final Name Q_KEY = new Name("Q"); - /** - * If set, the document contains at least one signature field. This flag - * allows a conforming reader to enable user interface items (such as menu - * items or pushbuttons) related to signature processing without having to - * scan the entire document for the presence of signature fields. - */ - public static final int SIG_FLAGS_SIGNATURES_EXIST = 1; - /** - * If set, the document contains signatures that may be invalidated if the - * file is saved (written) in a way that alters its previous contents, as - * opposed to an incremental update. Merely updating the file by appending - * new information to the end of the previous version is safe - * (see H.7, “Updating Exampleâ€). Conforming readers may use this flag to - * inform a user requesting a full save that signatures will be invalidated - * and require explicit confirmation before continuing with the operation. - */ - public static final int SIG_FLAGS_APPEND_ONLY = 2; - - private static final Logger logger = - Logger.getLogger(InteractiveForm.class.toString()); - - // field list, we keep reference as we don't want these garbage collected. - private ArrayList fields; - - // A flag specifying whether to construct appearance streams and appearance dictionaries for all - // widget annotations in the document (see 12.7.3.3, “Variable Textâ€). Default value: false. - private boolean needAppearances; - - // A set of flags specifying various document-level characteristics related to signature fields . - private int sigFlags; - - // An array of indirect references to field dictionaries with calculation actions, defining the calculation order in - // which their values will be recalculated when the value of any field changes - private List calculationOrder; - - // A resource dictionary containing default resources (such as fonts, patterns, or colour spaces) that shall be used - // by form field appearance streams. - private Resources resources; - - // A document-wide default value for the DA attribute of variable text fields - private String defaultVariableTextDAField; - - // A document-wide default value for the Q attribute of variable text fields - // 0 - left-justified, 1 Centered, 2 right-justified. - private int defaultVariableTextQField; - - // todo XFA entry stream or array processing. - // important to test for data import reasons. - - public InteractiveForm(Library library, HashMap entries) { - super(library, entries); - } - - @SuppressWarnings("unchecked") - public void init() { - - // load the resources - needAppearances = library.getBoolean(entries, NEEDS_APPEARANCES_KEY); - - // sig flags. - Object tmp = library.getObject(entries, SIG_FLAGS_KEY); - if (tmp instanceof HashMap) { - sigFlags = library.getInt(entries, SIG_FLAGS_KEY); - } - - // load the resources - tmp = library.getObject(entries, DR_KEY); - if (tmp instanceof HashMap) { - resources = library.getResources(entries, DR_KEY); - } - - // load the resources, useful for rebuilding form elements. - tmp = library.getObject(entries, SIG_FLAGS_KEY); - if (tmp instanceof HashMap) { - resources = library.getResources(entries, DR_KEY); - } - - // get the calculation order array. - tmp = library.getObject(entries, CO_KEY); - if (tmp instanceof List) { - calculationOrder = library.getArray(entries, CO_KEY); - } - - tmp = library.getObject(entries, Q_KEY); - if (tmp instanceof List) { - defaultVariableTextQField = library.getInt(entries, Q_KEY); - } - - // load the default appearance. - tmp = library.getObject(entries, DA_KEY); - if (tmp instanceof StringObject) { - defaultVariableTextDAField = Utils.convertStringObject(library, (StringObject) tmp); - } - - // get the fields in the document, keeping hierarchy intact. - tmp = library.getObject(entries, FIELDS_KEY); - if (tmp instanceof List) { - List tmpFields = (List) tmp; - fields = new ArrayList(tmpFields.size()); - Object annotObj; - for (Object fieldRef : tmpFields) { - if (fieldRef instanceof Reference) { - // add them all as we find them. - annotObj = library.getObject((Reference) fieldRef); - if (annotObj instanceof HashMap) { - annotObj = FieldDictionaryFactory.buildField(library, (HashMap) annotObj); - } - if (annotObj != null) { - fields.add(annotObj); - } - } - } - } - } - - /** - * Gets the fields associated with this form. - * - * @return array of fields. - */ - public ArrayList getFields() { - return fields; - } - - /** - * Gets the signature fields associated with this form. A new array that references the forms signature annotations. - * If no fields are found an empty list is returned. - * - * @return a list of form signature objects. - */ - public ArrayList getSignatureFields() { - // capture the document signatures. - ArrayList signatures = new ArrayList(); - if (fields != null) { - for (Object field : fields) { - if (field instanceof SignatureWidgetAnnotation) { - signatures.add((SignatureWidgetAnnotation) field); - } - } - } - return signatures; - } - - /** - * Test the byte range of the signature in this form to see if they cover the document in it's entirety. This - * should to be confused with validating a signature this just indicates that there are bytes that have been - * written to the file that aren't covered by one of the documents signature. - * - * @return true if signatures cover the length of the document or false if the signatures don't dover the document - * or there are no signatures. - */ - public boolean isSignaturesCoverDocumentLength() { - SignatureWidgetAnnotation signatureWidgetAnnotation; - try { - if (fields != null) { - boolean isValidByteRange = false; - for (Object field : fields) { - if (field instanceof SignatureWidgetAnnotation) { - signatureWidgetAnnotation = (SignatureWidgetAnnotation) field; - if (signatureWidgetAnnotation.getSignatureValidator() != null && - signatureWidgetAnnotation.getSignatureValidator().checkByteRange()) { - isValidByteRange = true; - break; - } - } - } - if (isValidByteRange) { - for (Object field : fields) { - if (field instanceof SignatureWidgetAnnotation) { - signatureWidgetAnnotation = (SignatureWidgetAnnotation) field; - signatureWidgetAnnotation.getSignatureValidator().setSignaturesCoverDocumentLength(true); - } - } - } - } - } catch (SignatureIntegrityException e) { - logger.warning("Signature validation error has occurred"); - } - return false; - } - - /** - * Checks to see if the fields list contains any signature anntoations. - * - * @return true if there are any signatures, otherwise false. - */ - public boolean isSignatureFields() { - boolean foundSignature = false; - ArrayList fields = getFields(); - if (fields != null) { - for (Object field : fields) { - if (field instanceof SignatureWidgetAnnotation) { - foundSignature = true; - break; - } - } - } - return foundSignature; - } - - /** - * A set of flags specifying various document-level characteristics related to signature fields. It should - * be noted that this filed is not used very often and {@see isSignatureFields} should be used instead. - * - * @return true if enabled, false otherwise. - */ - public boolean signatureExists() { - return ((sigFlags & SIG_FLAGS_SIGNATURES_EXIST) - == SIG_FLAGS_SIGNATURES_EXIST); - } - - /** - * If set, the document contains signatures that may be invalidated if the - * file is saved (written) in a way that alters its previous contents, as - * opposed to an incremental update - * - * @return true if enabled, false otherwise. - */ - public boolean signatureAppendOnly() { - return ((sigFlags & SIG_FLAGS_APPEND_ONLY) - == SIG_FLAGS_APPEND_ONLY); - } - - /** - * A flag specifying whether to construct appearance streams and appearance dictionaries for all - * widget annotations in the document. Default value: false. - * - * @return true if appearance streams need to be generated, otherwise false. - */ - public boolean needAppearances() { - return needAppearances; - } - - /** - * Gets a list of indirect references to fields that have calculation actions, defining the calculation - * order in which values should be calculated when the value of any field changes. - * - * @return list of indirect references if present, otherwise null; - */ - public List getCalculationOrder() { - return calculationOrder; - } - - /** - * Get the resources associated with the child widgets. - * - * @return common resources to all child widgets. Can be null. - */ - public Resources getResources() { - return resources; - } - - /** - * Gest the default variable text DA entry which can be helpful for rebuilding field data appearance streams. - * - * @return default da values, null if not present. - */ - public String getDefaultVariableTextDAField() { - return defaultVariableTextDAField; - } - - /** - * Ges the default variable text quadding rule. - * - * @return integer represented by VariableTextFieldDictionary.QUADDING_LEFT_JUSTIFIED, VariableTextFieldDictionary.QUADDING_CENTERED or - * VariableTextFieldDictionary.QUADDING_RIGHT_JUSTIFIED. - */ - public int getDefaultVariableTextQField() { - return defaultVariableTextQField; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/LockDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/LockDictionary.java deleted file mode 100644 index e2ec732343..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/LockDictionary.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * The signature field lock dictionary (described in Table 233) contains field names from the signature seed value - * dictionary (described in Table 234) that cannot be changed through the user interface of a conforming reader. - * - * @since 6.1 - */ -public class LockDictionary extends Dictionary { - - /** - * (Optional) The type of PDF object that this dictionary describes; if present, shall be SigFieldLock for a - * signature field lock dictionary. - */ - public static final Name LOCK_TYPE_VALUE = new Name("SigFieldLock"); - - /** - * (Required) A name which, in conjunction with Fields, indicates the set of fields that should be locked. - * The value shall be one of the following: - *
    - *
  • AllAll fields in the document
  • - *
  • IncludeAll fields specified in Fields
  • - *
  • ExcludeAll fields except those specified in Fields
  • - *
- */ - public static final Name ACTION_KEY = new Name("Action"); - - public static final Name ACTION_VALUE_ALL = new Name("All"); - public static final Name ACTION_VALUE_INCLUDE = new Name("Include"); - public static final Name ACTION_VALUE_EXCLUDE = new Name("Exclude"); - - /** - * (Required if the value of Action is Include or Exclude) An array of text strings containing field names. - */ - public static final Name FIELDS_KEY = new Name("Fields"); - - private Name action; - - private ArrayList fields; - - public LockDictionary(Library library, HashMap entries) { - super(library, entries); - } - - /** - * If All fields in the document should be locked. - * - * @return true if all should be locked, otherwise false. - */ - public boolean isAllLocked() { - return action != null && action.equals(ACTION_VALUE_ALL); - } - - /** - * All fields specified by "fields" should be locked. - * - * @return true if fields should be locked, otherwise false. - */ - public boolean isIncludeLocked() { - return action != null && action.equals(ACTION_VALUE_INCLUDE); - } - - /** - * All fields specified by "fields" should should not be locked, all others should be locked. . - * - * @return true if fields should be excluded, otherwise false. - */ - public boolean isExcludeLocked() { - return action != null && action.equals(ACTION_VALUE_EXCLUDE); - } - - public Name getAction() { - return action; - } - - public void setAction(Name action) { - this.action = action; - } - - public ArrayList getFields() { - return fields; - } - - public void setFields(ArrayList fields) { - this.fields = fields; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SeedValueDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SeedValueDictionary.java deleted file mode 100644 index 054b9a1c87..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SeedValueDictionary.java +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Names; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; - -import java.util.HashMap; -import java.util.List; - -/** - * The value of the SV entry in the field dictionary is a seed value dictionary whose entries (see Table 234) provide - * constraining information that shall be used at the time the signature is applied. Its Ff entry specifies whether - * the other entries in the dictionary shall be honoured or whether they are merely recommendations. - *

- * The seed value dictionary may include seed values for private entries belonging to multiple handlers. A given handler - * shall use only those entries that are pertinent to itself and ignore the others. - * - */ -public class SeedValueDictionary extends Dictionary { - - /** - * The type of PDF object that this dictionary describes; if present, shall be SV for a seed value dictionary. - */ - public static final Name LOCK_TYPE_VALUE = new Name("SV"); - - /** - * A set of bit flags specifying the interpretation of specific entries in this dictionary. A value of 1 for the - * flag indicates that the associated entry is a required constraint. A value of 0 indicates that the associated - * entry is an optional constraint. - *

- * Bit positions are 1 (Filter); 2 (SubFilter); 3 (V); 4 (Reasons); 5 (LegalAttestation); 6 (AddRevInfo); and - * 7 (DigestMethod). Default value: 0. - */ - public static final Name Ff_KEY = new Name("Ff"); - - // Bit 1 (Filter) - private static final int Ff_FILTER_BIT = 0x1; - // Bit 2 (SubFilter) - private static final int Ff_SUB_FILTER_BIT = 0x2; - // Bit 3 (V) - private static final int Ff_V_BIT = 0x4; - // Bit 4 (Reasons) - private static final int Ff_REASONS_BIT = 0x8; - // Bit 5 (LegalAttestation) - private static final int Ff_LEGAL_ATTESTATION_BIT = 0x10; - // Bit 6 (AddRevInfo); and - private static final int Ff_ADD_REV_INFO_BIT = 0x20; - // Bit 7 (DigestMethod). Default value: 0. - private static final int Ff_DIGEST_METHOD_BIT = 0x40; - - /** - * (Optional) The signature handler that shall be used to sign the signature field. Beginning with PDF 1.7, if - * Filter is specified and the Ff entry indicates this entry is a required constraint, then the signature handler - * specified by this entry shall be used when signing; otherwise, signing shall not take place. If Ff indicates - * that this is an optional constraint, this handler may be used if it is available. If it is not available, a - * different handler may be used instead. - */ - public static final Name FILTER_KEY = new Name("Filter"); - - /** - * (Optional) An array of names indicating encodings to use when signing. The first name in the array that matches - * an encoding supported by the signature handler shall be the encoding that is actually used for signing. - * If SubFilter is specified and the Ff entry indicates that this entry is a required constraint, then the - * first matching encodings shall be used when signing; otherwise, signing shall not take place. If Ff indicates - * that this is an optional constraint, then the first matching encoding shall be used if it is available. If - * none is available, a different encoding may be used. - */ - public static final Name SUB_FILTER_KEY = new Name("SubFilter"); - - /** - * (Optional; PDF 1.7) An array of names indicating acceptable digest algorithms to use while signing. The value - * shall be one of SHA1, SHA256, SHA384, SHA512 and RIPEMD160. The default value is implementation-specific. - *

- * This property is only applicable if the digital credential signing contains RSA public/private keys. If it - * contains DSA public/ private keys, the digest algorithm is always SHA1 and this attribute shall be ignored. - */ - public static final Name DIGEST_METHOD_KEY = new Name("DigestMethod"); - - /** - * (Optional) The minimum required capability of the signature field seed value dictionary parser. A value of 1 - * specifies that the parser shall be able to recognize all seed value dictionary entries in a PDF 1.5 file. - * A value of 2 specifies that it shall be able to recognize all seed value dictionary entries specified. - *

- * The Ff entry indicates whether this shall be treated as a required constraint. - */ - public static final Name V_KEY = new Name("V"); - - /** - * (Optional) A certificate seed value dictionary (see Table 235) containing information about the characteristics - * of the certificate that shall be used when signing. - */ - public static final Name CERT_KEY = new Name("Cert"); - - /** - * (Optional) An array of text strings that specifying possible reasons for signing a document. If specified, the - * reasons supplied in this entry replace those used by conforming products. - *

- * If the Reasons array is provided and the Ff entry indicates that Reasons is a required constraint, one of the - * reasons in the array shall be used for the signature dictionary; otherwise, signing shall not take place. If - * the Ff entry indicates Reasons is an optional constraint, one of the reasons in the array may be chosen or a - * custom reason can be provided. - *

- * If the Reasons array is omitted or contains a single entry with the value PERIOD (2Eh) and the Ff entry - * indicates that Reasons is a required constraint, the Reason entry shall be omitted from the signature - * dictionary (see Table 252). - */ - public static final Name REASONS_KEY = new Name("Reasons"); - - /** - * (Optional; PDF 1.6) A dictionary containing a single entry whose key is P and whose value is an integer - * between 0 and 3. A value of 0 defines the signature as an author signature (see 12.8, Digital Signatures). - * The values 1 through 3 shall be used for certification signatures and correspond to the value of P in a DocMDP - * transform parameters dictionary (see Table 254). - *

- * If this MDP key is not present or the MDP dictionary does not contain a P entry, no rules shall be defined - * regarding the type of signature or its permissions. - */ - public static final Name MDP_KEY = new Name("MDP"); - - /** - * (Optional; PDF 1.6) A time stamp dictionary containing two entries: - *

    - *
  • URL An ASCII string specifying the URL of a time-stamping server, providing a time stamp that is compliant - * ith RFC 3161, Internet X.509 Public Key Infrastructure Time-Stamp Protocol (see the Bibliography).
  • - *
  • Ff An integer whose value is 1 (the signature shall have a time stamp) or 0 (the signature need not have a - * time stamp). Default value: 0.
  • - *
- * NOTEPlease see 12.8.3.3, "PKCS#7 Signatures as used in ISO 32000" for more details about hashing. - */ - public static final Name TIME_STAMP_KEY = new Name("TimeStamp"); - - /** - * (Optional; PDF 1.6) An array of text strings specifying possible legal attestations - * (see 12.8.5, Legal Content Attestations). The value of the corresponding flag in the Ff entry indicates - * whether this is a required constraint. - */ - public static final Name LEGAL_ATTESTATION_KEY = new Name("LegalAttestation"); - - /** - * (Optional; PDF 1.7) A flag indicating whether revocation checking shall be carried out. If AddRevInfo is true, - * the conforming processor shall perform the following additional tasks when signing the signature field: - *

- * Perform revocation checking of the certificate (and the corresponding issuing certificateChain) used to sign. - *

- * Include the revocation information within the signature value. - *

- * Three SubFilter values have been defined for ISO 32000. For those values the AddRevInfo value shall be true - * only if SubFilter is adbe.pkcs7.detached or adbe.pkcs7.sha1. If SubFilter is x509.rsa_sha1, this entry shall - * be omitted or set to false. Additional SubFilters may be defined that also use AddRevInfo values. - *

- * If AddRevInfo is true and the Ff entry indicates this is a required constraint, then the preceding tasks shall - * be performed. If they cannot be performed, then signing shall fail. - * Default value: false - *

- * NOTE 1Revocation information is carried in the signature data as specified by PCKS#7. See 12.8.3.3, - * "PKCS#7 Signatures as used in ISO 32000". - *

- * NOTE 2The trust anchors used are determined by the signature handlers for both creation and validation. - */ - public static final Name ADD_REV_INFO_KEY = new Name("AddRevInfo"); - - - private int flags; - - public SeedValueDictionary(Library library, HashMap entries) { - super(library, entries); - - flags = library.getInt(entries, Ff_KEY); - } - - public Name getFilterKey() { - Object tmp = library.getObject(entries, FILTER_KEY); - if (tmp instanceof Name) { - return (Name) tmp; - } else { - return null; - } - } - - /** - * @return filter array or null. - * @see #FILTER_KEY - */ - public List getSubFilter() { - List tmp = library.getArray(entries, FILTER_KEY); - if (tmp != null) { - return tmp; - } - return null; - } - - /** - * @return digest methods or null. - * @see #DIGEST_METHOD_KEY - */ - public List getDigestMethod() { - List tmp = library.getArray(entries, FILTER_KEY); - if (tmp != null) { - return tmp; - } - return null; - } - - /** - * @return minimum capability - * @see #V_KEY - */ - public double getV() { - return library.getFloat(entries, V_KEY); - } - - /** - * @return Get the certificate see value dictionary, can be null. - * @see #CERT_KEY - */ - public CertSeedValueDictionary getCert() { - Object tmp = library.getObject(entries, CERT_KEY); - if (tmp instanceof HashMap) { - return new CertSeedValueDictionary(library, (HashMap) tmp); - } else { - return null; - } - } - - /** - * @return an array of text strings the specify possible reasons for singing. - * @see #REASONS_KEY - */ - public List getReasons() { - List tmp = library.getArray(entries, REASONS_KEY); - if (tmp != null) { - return tmp; - } - return null; - } - - /** - * todo consider class for dictionary def. - * - * @return - */ - public HashMap getMDP() { - Object tmp = library.getObject(entries, MDP_KEY); - if (tmp instanceof HashMap) { - return (HashMap) tmp; - } else { - return null; - } - } - - /** - * todo consider class for dictionary def. - * - * @return - */ - public HashMap getTimeStamp() { - Object tmp = library.getObject(entries, TIME_STAMP_KEY); - if (tmp instanceof HashMap) { - return (HashMap) tmp; - } else { - return null; - } - } - - /** - * @return an array of text strings the specify possible legal attestations. - * @see #LEGAL_ATTESTATION_KEY - */ - public List getLegalAttestation() { - List tmp = library.getArray(entries, LEGAL_ATTESTATION_KEY); - if (tmp != null) { - return tmp; - } - return null; - } - - /** - * @return Flag indicating whether revocation checking shall be carried out. - * @see #ADD_REV_INFO_KEY - */ - public boolean getAddRevInfo() { - return library.getBoolean(entries, ADD_REV_INFO_KEY); - } - - public boolean isFilter() { - return ((flags & Ff_FILTER_BIT) - == Ff_FILTER_BIT); - } - - public boolean isSubFilter() { - return ((flags & Ff_SUB_FILTER_BIT) - == Ff_SUB_FILTER_BIT); - } - - public boolean isV() { - return ((flags & Ff_V_BIT) - == Ff_V_BIT); - } - - public boolean isReasons() { - return ((flags & Ff_REASONS_BIT) - == Ff_REASONS_BIT); - } - - public boolean isLegalAttenstation() { - return ((flags & Ff_LEGAL_ATTESTATION_BIT) - == Ff_LEGAL_ATTESTATION_BIT); - } - - public boolean isAddRevInfo() { - return ((flags & Ff_ADD_REV_INFO_BIT) - == Ff_ADD_REV_INFO_BIT); - } - - public boolean isDigestMethod() { - return ((flags & Ff_DIGEST_METHOD_BIT) - == Ff_DIGEST_METHOD_BIT); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureDictionary.java deleted file mode 100644 index e74074d66d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureDictionary.java +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.HexStringObject; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -/** - * A digital signature (PDF 1.3) may be used to authenticate the identity of a user and the document’s contents. It stores - * information about the signer and the state of the document when it was signed. The signature may be purely mathematical, - * such as a public/private-key encrypted document digest, or it may be a biometric form of identification, such as a - * handwritten signature, fingerprint, or retinal scan. The specific form of authentication used shall be implemented by - * a special software module called a signature handler. - * - * The SignatureDictionary store root data for signing and verifying signature in a document. - */ -public class SignatureDictionary extends Dictionary { - - /** - * (Required; inheritable) The name of the preferred signature handler to use when validating this signature. - * If the Prop_Build entry is not present, it shall be also the name of the signature handler that was used to - * create the signature. If Prop_Build is present, it may be used to determine the name of the handler that - * created the signature (which is typically the same as Filter but is not needed to be). A conforming reader may - * substitute a different handler when verifying the signature, as long as it supports the specified SubFilter - * format. Example signature handlers are Adobe.PPKLite, Entrust.PPKEF, CICI.SignIt, and VeriSign.PPKVS. The name - * of the filter (i.e. signature handler) shall be identified in accordance with the rules defined in Annex E. - */ - public static final Name FILTER_KEY = new Name("Filter"); - - /** - * (Optional) A name that describes the encoding of the signature value and key information in the signature dictionary. - * A conforming reader may use any handler that supports this format to validate the signature. - *

- * (PDF 1.6) The following values for public-key cryptographic signatures shall be used: adbe.x509.rsa_sha1, - * adbe.pkcs7.detached, and adbe.pkcs7.sha1 (see 12.8.3, Signature Interoperability). Other values may be defined - * by developers, and when used, shall be prefixed with the registered developer identification. All prefix names - * shall be registered (see Annex E). The prefix adbe has been registered by Adobe Systems and the three subfilter - * names listed above and defined in 12.8.3, Signature Interoperability may be used by any developer. - */ - public static final Name SUB_FILTER_KEY = new Name("SubFilter"); - - /** - * (Required) The signature value. When ByteRange is present, the value shall be a hexadecimal string (see 7.3.4.3, - * "Hexadecimal Strings") representing the value of the byte range digest. - *
- * For public-key signatures, Contents should be either a DER-encoded PKCS#1 binary data object or a DER-encoded - * PKCS#7 binary data object. - * Space for the Contents value must be allocated before the message digest is computed. (See 7.3.4, String Objects) - */ - public static final Name CONTENTS_KEY = new Name("Contents"); - - /** - * (Required when SubFilter is adbe.x509.rsa_sha1) An array of byte strings that shall represent the X.509 - * certificate chain used when signing and verifying signatures that use public-key cryptography, or a byte - * string if the chain has only one entry. The signing certificate shall appear first in the array; it shall - * be used to verify the signature value in Contents, and the other certificateChain shall be used to verify the - * authenticity of the signing certificate. - *
- * If SubFilter is adbe.pkcs7.detached or adbe.pkcs7.sha1, this entry shall not be used, and the certificate chain - * shall be put in the PKCS#7 envelope in Contents. - */ - public static final Name CERT_KEY = new Name("Cert"); - - /** - * (Required for all signatures that are part of a signature field and usage rights signatures referenced from the - * UR3 entry in the permissions dictionary) An array of pairs of integers (starting byte offset, length in bytes) - * that shall describe the exact byte range for the digest calculation. Multiple discontiguous byte ranges shall - * be used to describe a digest that does not include the signature value (theContents entry) itself. - */ - public static final Name BYTE_RANGE_KEY = new Name("ByteRange"); - - /** - * (Optional; PDF 1.5) An array of signature reference dictionaries (see Table 253). - */ - public static final Name REFERENCE_KEY = new Name("Reference"); - - /** - * (Optional) An array of three integers that shall specify changes to the document that have been made between the - * previous signature and this signature: in this order, the number of pages altered, the number of fields altered, - * and the number of fields filled in. - *
- * The ordering of signatures shall be determined by the value of ByteRange. Since each signature results in an - * incremental save, later signatures have a greater length value. - */ - public static final Name CHANGES_KEY = new Name("Changes"); - - /** - * (Optional) The name of the person or authority signing the document. This value should be used only when it is - * not possible to extract the name from the signature. - *
- * EXAMPLE 1
- * From the certificate of the signer. - */ - public static final Name NAME_KEY = new Name("Name"); - - /** - * (Optional) The time of signing. Depending on the signature handler, this may be a normal unverified computer - * time or a time generated in a verifiable way from a secure time server. - *
- * This value should be used only when the time of signing is not available in the signature. - *
- * EXAMPLE 2
- * A time stamp can be embedded in a PKCS#7 binary data object - * (see 12.8.3.3, PKCS#7 Signatures as used in ISO 32000). - */ - public static final Name M_KEY = new Name("M"); - - /** - * (Optional) The CPU host name or physical location of the signing. - */ - public static final Name LOCATION_KEY = new Name("Location"); - - /** - * (Optional) The reason for the signing, such as (I agree). - */ - public static final Name REASON_KEY = new Name("Reason"); - - /** - * (Optional) The version of the signature handler that was used to create the signature. (PDF 1.5) This entry - * shall not be used, and the information shall be stored in the Prop_Build dictionary. - */ - public static final Name R_KEY = new Name("R"); - - /** - * (Optional; PDF 1.5) The version of the signature dictionary format. It corresponds to the usage of the signature - * dictionary in the context of the value of SubFilter. The value is 1 if the Reference dictionary shall be - * considered critical to the validation of the signature. - *
- * Default value: 0. - */ - public static final Name V_KEY = new Name("V"); - - /** - * (Optional; PDF 1.5) A dictionary that may be used by a signature handler to record information that captures the - * state of the computer environment used for signing, such as the name of the handler used to create the signature, - * software build date, version, and operating system. - *
- * The PDF Signature Build Dictionary Specification, provides implementation guidelines for the use of this dictionary. - */ - public static final Name PROP_BUILD_KEY = new Name("Prop_Build"); - - /** - * (Optional; PDF 1.5) The number of seconds since the signer was last authenticated, used in claims of signature - * repudiation. It should be omitted if the value is unknown. - */ - public static final Name PROP_AUTH_TYPE_KEY = new Name("Prop_AuthType"); - - /** - * Optional; PDF 1.5) The method that shall be used to authenticate the signer, used in claims of signature - * repudiation. Valid values shall be PIN, Password, and Fingerprint. - */ - public static final Name PROP_AUTH_TIME_KEY = new Name("Prop_AuthTime"); - - /** - * (Optional) Information provided by the signer to enable a recipient to contact the signer to verify the signature. - *
- * EXAMPLE 3
- * A phone number. - */ - public static final Name CONTACT_INFO_KEY = new Name("ContactInfo"); - - public SignatureDictionary(Library library, HashMap entries) { - super(library, entries); - } - - public Name getFilter() { - return library.getName(entries, FILTER_KEY); - } - - public void setFilter(Name filterName) { - entries.put(FILTER_KEY, filterName); - } - - public Name getSubFilter() { - return library.getName(entries, SUB_FILTER_KEY); - } - - public void setSubFilter(Name filterName) { - entries.put(SUB_FILTER_KEY, filterName); - } - - public HexStringObject getContents() { - Object tmp = library.getObject(entries, CONTENTS_KEY); - if (tmp instanceof HexStringObject) { - return (HexStringObject) tmp; - } else { - return null; - } - } - - public void setContents(HexStringObject hexString) { - entries.put(CONTENTS_KEY, hexString); - } - - public boolean isCertArray() { - return library.getObject(entries, CERT_KEY) instanceof List; - } - - public boolean isCertString() { - return library.getObject(entries, CERT_KEY) instanceof StringObject; - } - - public ArrayList getCertArray() { - Object tmp = library.getObject(entries, CERT_KEY); - if (tmp instanceof List) { - return (ArrayList) tmp; - } else { - return null; - } - } - - public StringObject getCertString() { - Object tmp = library.getObject(entries, CERT_KEY); - if (tmp instanceof StringObject) { - return (StringObject) tmp; - } else { - return null; - } - } - - public void setCert(Object cert) { - entries.put(CERT_KEY, cert); - } - - public ArrayList getByteRange() { - Object tmp = library.getObject(entries, BYTE_RANGE_KEY); - if (tmp instanceof List) { - return (ArrayList) tmp; - } else { - return null; - } - } - - public void setByteRangeKey(ArrayList range) { - entries.put(BYTE_RANGE_KEY, range); - } - - public ArrayList getReferences() { - List tmp = library.getArray(entries, REFERENCE_KEY); - if (tmp != null && tmp.size() > 0) { - ArrayList references = new ArrayList(tmp.size()); - for (HashMap reference : tmp) { - references.add(new SignatureReferenceDictionary(library, reference)); - } - return references; - } else { - return null; - } - } - - public ArrayList getChanges() { - Object tmp = library.getArray(entries, CHANGES_KEY); - if (tmp instanceof ArrayList) { - return (ArrayList) tmp; - } else { - return null; - } - } - - public String getName() { - Object tmp = library.getObject(entries, NAME_KEY); - if (tmp instanceof StringObject) { - return Utils.convertStringObject(library, (StringObject) tmp); - } else { - return null; - } - } - - public String getDate() { - return library.getString(entries, M_KEY); - } - - public String getLocation() { - Object tmp = library.getObject(entries, LOCATION_KEY); - if (tmp instanceof StringObject) { - return Utils.convertStringObject(library, (StringObject) tmp); - } else { - return null; - } - } - - public String getReason() { - Object tmp = library.getObject(entries, REASON_KEY); - if (tmp instanceof StringObject) { - return Utils.convertStringObject(library, (StringObject) tmp); - } else { - return null; - } - } - - public String getContactInfo() { - Object tmp = library.getObject(entries, CONTACT_INFO_KEY); - if (tmp instanceof StringObject) { - return Utils.convertStringObject(library, (StringObject) tmp); - } else { - return null; - } - } - - public int getHandlerVersion() { - return library.getInt(entries, R_KEY); - } - - public int getDictionaryVersion() { - return library.getInt(entries, V_KEY); - } - - public HashMap getBuildDictionary() { - return library.getDictionary(entries, PROP_BUILD_KEY); - } - - public int getAuthTime() { - return library.getInt(entries, PROP_AUTH_TIME_KEY); - } - - public Name getAuthType() { - return library.getName(entries, PROP_AUTH_TYPE_KEY); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureFieldDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureFieldDictionary.java deleted file mode 100644 index 519ec9b568..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureFieldDictionary.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * Signature field (PDF 1.3) is a form field that contains a digital signature (see 12.8, "Digital Signatures"). The field - * dictionary representing a signature field may contain the additional entries listed in Table 232, as well as the - * standard entries described in Table 220. The field type (FT) shall be Sig, and the field value (V), if present, shall - * be a signature dictionary containing the signature and specifying various attributes of the signature field - * (see Table 252). - *

- * NOTE 1This signature form field serves two primary purposes. The first is to define the form field that will provide - * the visual signing properties for display but it also may hold information needed later when the actual signing takes - * place, such as the signature technology to use. This carries information from the author of the document to the - * software that later does the signing. - *

- * NOTE 2Filling in (signing) the signature field entails updating at least the V entry and usually also the AP entry of - * the associated widget annotation. Exporting a signature field typically exports the T, V, and AP entries. - *

- * Like any other field, a signature field may be described by a widget annotation dictionary containing entries pertaining - * to an annotation as well as a field (see 12.5.6.19, "Widget Annotations"). The annotation rectangle (Rect) in such a - * dictionary shall give the position of the field on its page. Signature fields that are not intended to be visible shall - * have an annotation rectangle that has zero height and width. Conforming readers shall treat such signatures as not - * visible. Conforming readers shall also treat signatures as not visible if either the Hidden bit or the NoView bit of - * the F entry is true. The F entry is described in Table 164, and annotation flags are described in Table 165. - * - * @since 5.2 - */ -public class SignatureFieldDictionary extends FieldDictionary { - - /** - * (Optional; shall be an indirect reference; PDF 1.5) A signature field lock dictionary that specifies a set of form - * fields that shall be locked when this signature field is signed. Table 233 lists the entries in this dictionary. - */ - public static final Name LOCK_KEY = new Name("Lock"); - - /** - * (Optional; shall be an indirect reference; PDF 1.5) A seed value dictionary (see Table 234) containing information - * that constrains the properties of a signature that is applied to this field. - */ - public static final Name SV_KEY = new Name("SV"); - - // optional - private LockDictionary lockDictionary; - // optional - private SeedValueDictionary seedValueDictionary; - // not optional - private SignatureDictionary signatureDictionary; - - public SignatureFieldDictionary(Library library, HashMap entries) { - super(library, entries); - - // get the lock, todo currently no examples of this - Object tmp = library.getObject(entries, LOCK_KEY); - if (tmp instanceof HashMap) { - lockDictionary = new LockDictionary(library, (HashMap) tmp); - } - // get the seeds, todo currently no examples of this - tmp = library.getObject(entries, SV_KEY); - if (tmp instanceof HashMap) { - seedValueDictionary = new SeedValueDictionary(library, (HashMap) tmp); - } - // get the sig dictionary - if (hasFieldValue()) { - tmp = library.getObject(entries, V_KEY); - if (tmp instanceof HashMap) { - signatureDictionary = new SignatureDictionary(library, (HashMap) tmp); - } - } - - } - - /** - * Gets the associated signature dictionary and sub dictionaries. - * - * @return /sig's field dictionary. - */ - public SignatureDictionary getSignatureDictionary() { - return signatureDictionary; - } - - /** - * A signature field lock dictionary that specifies a set of form fields that shall be locked when this signature - * field is signed. Table 233 lists the entries in this dictionary. - * - * @return signature field object, can be null. - */ - public LockDictionary getLockDictionary() { - return lockDictionary; - } - - /** - * A seed value dictionary (see Table 234) containing information that constrains the properties of a signature - * that is applied to this field. - * - * @return seed value object, can be null. - */ - public SeedValueDictionary getSeedValueDictionary() { - return seedValueDictionary; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureHandler.java deleted file mode 100644 index ed3654aae8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.acroform.signature.DigitalSignatureFactory; -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.util.Defs; - -import java.security.Provider; -import java.security.Security; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * The signature handler is responsible for returning validation results for a given Digital signature's - * signature field dictionary. The returned Validation objected can be interrogated to see which properties - * are considered valid. - */ -public class SignatureHandler { - - private static final Logger logger = - Logger.getLogger(SignatureHandler.class.toString()); - - static { - // Load security handler from system property if possible - String defaultSecurityProvider = - "org.bouncycastle.jce.provider.BouncyCastleProvider"; - - // check system property security provider - String customSecurityProvider = - Defs.sysProperty("org.icepdf.core.security.jceProvider"); - - // if no custom security provider load default security provider - if (customSecurityProvider != null) { - defaultSecurityProvider = customSecurityProvider; - } - try { - // try and create a new provider - Object provider = Class.forName(defaultSecurityProvider).newInstance(); - Security.insertProviderAt((Provider) provider, 2); - } catch (ClassNotFoundException e) { - logger.log(Level.FINE, "Optional BouncyCastle security provider not found"); - } catch (InstantiationException e) { - logger.log(Level.FINE, "Optional BouncyCastle security provider could not be instantiated"); - } catch (IllegalAccessException e) { - logger.log(Level.FINE, "Optional BouncyCastle security provider could not be created"); - } - } - - public SignatureHandler() { - } - - /** - * Validates the given SignatureFieldDictionary. - * - * @param signatureFieldDictionary signature to validate - * @return SignatureValidator object if cert and public key verified, null otherwise. - */ - public SignatureValidator validateSignature(SignatureFieldDictionary signatureFieldDictionary) { - - SignatureDictionary signatureDictionary = signatureFieldDictionary.getSignatureDictionary(); - if (signatureDictionary != null) { - // Generate the correct validator and try to validate the signature. - try { - SignatureValidator signatureValidator = DigitalSignatureFactory.getInstance().getValidatorInstance(signatureFieldDictionary); - return signatureValidator; - } catch (SignatureIntegrityException e) { - logger.log(Level.WARNING, "Signature certificate could not be initialized.", e); - } catch (Throwable e) { - logger.log(Level.WARNING, "Signature validation was unsuccessful.", e); - } - } - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureReferenceDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureReferenceDictionary.java deleted file mode 100644 index f590daa1d7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/SignatureReferenceDictionary.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * Signature reference dictionary. - */ -public class SignatureReferenceDictionary extends Dictionary { - - /** - * (Optional) The type of PDF object that this dictionary describes; if present, shall be SigRef for a signature - * reference dictionary. - */ - public static final Name SIG_REF_TYPE_VALUE = new Name("SigRef"); - - /** - * (Required) The name of the transform method (see Section 12.8.2, Transform Methods) that shall guide the - * modification analysis that takes place when the signature is validated. Valid values shall be: - *

    - *
  • DocMDP Used to detect modifications to a document relative to a signature field that is signed by the - * originator of a document; see 12.8.2.2, DocMDP.
  • - *
  • UR Used to detect modifications to a document that would invalidate a signature in a rights-enabled - * document; see 12.8.2.3, UR.
  • - *
  • FieldMDPUsed to detect modifications to a list of form fields specified in TransformParams; - * see 12.8.2.4, FieldMDP.
  • - *
- */ - public static final Name TRANSFORM_METHOD_KEY = new Name("TransformMethod"); - - private TransformParams transformParams; - - /** - * Available Transfer Method currently available. - */ - public enum TransformMethods { - FieldMDP, - DocMDP, - UR3 - } - - /** - * (Optional) A dictionary specifying transform parameters (variable data) for the transform method specified by - * TransformMethod. Each method takes its own set of parameters. See each of the sub-clauses specified previously - * for details on the individual transform parameter dictionaries - */ - public static final Name TRANSFORM_PARAMS_KEY = new Name("TransformParams"); - - /** - * (Required when TransformMethod is FieldMDP) An indirect reference to the object in the document upon which the - * object modification analysis should be performed. For transform methods other than FieldMDP, this object is - * implicitly defined. - */ - public static final Name DATA_KEY = new Name("Data"); - - /** - * (Optional; PDF 1.5 required) A name identifying the algorithm that shall be used when computing the digest. - * Valid values are MD5 and SHA1. Default value: MD5. For security reasons, MD5 should not be used. It is mentioned - * for backwards compatibility, since it remains the default value. - */ - public static final Name DIGEST_METHOD_KEY = new Name("DigestMethod"); - - /** - * Creates a new instance of a Dictionary. - * - * @param library document library. - * @param entries dictionary entries. - */ - public SignatureReferenceDictionary(Library library, HashMap entries) { - super(library, entries); - } - - /** - * Gets the transform method use by - * - * @return TransformMethods representing one of the preferred transform methods. - */ - public TransformMethods getTransformMethod() { - Name tmp = library.getName(entries, TRANSFORM_METHOD_KEY); - if (tmp != null) { - if (tmp.equals(TransformMethods.DocMDP.toString())) { - return TransformMethods.DocMDP; - } else if (tmp.equals(TransformMethods.FieldMDP.toString())) { - return TransformMethods.FieldMDP; - } else if (tmp.equals(TransformMethods.UR3.toString())) { - return TransformMethods.UR3; - } - } - return null; - } - - /** - * Gets the transforms Params implementations specified by the transform method. - * - * @return TransformParams of type; DocMDPTransferParam, FieldMDPTransferParam, or UR3TransferParam. - */ - public TransformParams getTransformParams() { - Name tmp = library.getName(entries, TRANSFORM_METHOD_KEY); - if (tmp.equals(TransformMethods.DocMDP.toString())) { - transformParams = - new DocMDPTransferParam(library, library.getDictionary(entries, TRANSFORM_PARAMS_KEY)); - } else if (tmp.equals(TransformMethods.FieldMDP.toString())) { - transformParams = - new FieldMDPTransferParam(library, library.getDictionary(entries, TRANSFORM_PARAMS_KEY)); - } else if (tmp.equals(TransformMethods.UR3.toString())) { - transformParams = - new UR3TransferParam(library, library.getDictionary(entries, TRANSFORM_PARAMS_KEY)); - } - return transformParams; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/TextFieldDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/TextFieldDictionary.java deleted file mode 100644 index d5e2153592..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/TextFieldDictionary.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * Text field (field type Tx) is a box or space for text fill-in data typically - * entered from a keyboard. The text may be restricted to a single line or may - * be permitted to span multiple lines, depending on the setting of the Multi line - * flag in the field dictionary’s Ff entry. Table 228 shows the flags pertaining - * to this type of field. A text field shall have a field type of Tx. A conforming - * PDF file, and a conforming processor shall obey the usage guidelines as - * defined by the big flags below. - *

- * The field’s text shall be held in a text string (or, beginning with PDF 1.5, - * a stream) in the V (value) entry of the field dictionary. The contents of this - * text string or stream shall be used to construct an appearance stream for - * displaying the field, as described under 12.7.3.3, “Variable Text.†The text - * shall be presented in a single style (font, size, colour, and so forth), as - * specified by the DA (default appearance) string. - *

- * If the FileSelect flag (PDF 1.4) is set, the field shall function as a file-select - * control. In this case, the field’s text represents the pathname of a file whose - * contents shall be submitted as the field’s value: - *

    - *
  • For fields submitted in HTML Form format, the submission shall use - * the MIME content type multipart/form-data, as described in Internet RFC 2045, - * Multipurpose Internet Mail Extensions (MIME), Part One: Format of Internet - * Message Bodies (see the Bibliography).
  • - *
  • For Forms Data Format (FDF) submission, the value of the V entry in - * the FDF field dictionary (see FDF Fields in 12.7.7.3, “FDF Catalogâ€) shall - * be a file specification (7.11, “File Specificationsâ€) identifying the - * selected file.
  • - *
  • XML format is not supported for file-select controls; therefore, no - * value shall be submitted in this case.
  • - *
- * Besides the usual entries common to all fields (see Table 220) and to fields - * containing variable text (see Table 222), the field dictionary for a text field may - * contain the additional entry shown in Table 229. - * - * @since 5.1 - */ -public class TextFieldDictionary extends VariableTextFieldDictionary { - - /** - * The maximum length of the fields text, in characters. - */ - public static final Name MAX_LENGTH_KEY = new Name("MaxLen"); - - /** - * (Radio buttons only) If set, exactly one radio button shall be selected at - * all times; selecting the currently selected button has no effect. If clear, - * clicking the selected button deselects it, leaving no button selected. - */ - public static final int MULTILINE_BIT_FLAG = 0x1000; - - /** - * should not be echoed visibly to the screen. Characters typed from the - * keyboard shall instead be echoed in some unreadable form, such as asterisks - * or bullet characters. - * NOTE: To protect password confidentiality, readers should never store the - * value of the text field in the PDF file if this flag is set. - */ - public static final int PASSWORD_BIT_FLAG = 0x2000; - - /** - * (PDF 1.4) If set, the text entered in the field represents the pathname of - * a file whose contents shall be submitted as the value of the field. - */ - public static final int FILE_SELECT_BIT_FLAG = 0x100000; - - /** - * (PDF 1.4) If set, text entered in the field shall not be spell-checked. - */ - public static final int TEXT_DO_NOT_SPELL_CHECK_BIT_FLAG = 0x100000; - - /** - * (PDF 1.4) If set, the field shall not scroll (horizontally for single-line - * fields, vertically for multiple-line fields) to accommodate more text than - * fits within its annotation rectangle. Once the field is full, no further - * text shall be accepted for interactive form filling; for non-interactive - * form filling, the filler should take care not to add more character than - * will visibly fit in the defined area. - */ - public static final int DO_NOT_SCROLL_BIT_FLAG = 0x800000; - - /** - * (PDF 1.5) May be set only if the MaxLen entry is present in the text field - * dictionary (see Table 229) and if the Multiline, Password, and FileSelect - * flags are clear. If set, the field shall be automatically divided into as - * many equally spaced positions, or combs, as the value of MaxLen, and the - * text is laid out into those combs. - */ - public static final int COMB_BIT_FLAG = 0x1000000; - - public enum TextFieldType { - TEXT_INPUT, TEXT_AREA, TEXT_PASSWORD, FILE_SELECT - } - - /** - * (PDF 1.5) If set, the value of this field shall be a rich text string - * (see 12.7.3.4, “Rich Text Stringsâ€). If the field has a value, the RV entry - * of the field dictionary (Table 222) shall specify the rich text string. - */ - public static final int RICH_TEXT_BIT_FLAG = 0x2000000; - protected TextFieldType textFieldType; - protected int maxLength = 0; - - public TextFieldDictionary(Library library, HashMap entries) { - super(library, entries); - // parse out max length. - Object value = library.getObject(entries, MAX_LENGTH_KEY); - if (value != null && value instanceof Number) { - maxLength = ((Number) value).intValue(); - } - // determine the text type - int flags = getFlags(); - if ((flags & MULTILINE_BIT_FLAG) == - MULTILINE_BIT_FLAG) { - textFieldType = TextFieldType.TEXT_AREA; - } else if ((flags & PASSWORD_BIT_FLAG) == - PASSWORD_BIT_FLAG) { - textFieldType = TextFieldType.TEXT_PASSWORD; - } else if ((flags & FILE_SELECT_BIT_FLAG) == - FILE_SELECT_BIT_FLAG) { - textFieldType = TextFieldType.FILE_SELECT; - } else { - textFieldType = TextFieldType.TEXT_INPUT; - } - } - - public int getMaxLength() { - return maxLength; - } - - public TextFieldType getTextFieldType() { - return textFieldType; - } - - /** - * Field may container multiple lines of text. - * - * @return true if multiline text, otherwise false. - */ - public boolean isMultiLine() { - return (getFlags() & MULTILINE_BIT_FLAG) == MULTILINE_BIT_FLAG; - } - - /** - * Filed is a file select component. - * - * @return true if file select, otherwise false. - */ - public boolean isFileSelect() { - return (getFlags() & FILE_SELECT_BIT_FLAG) == FILE_SELECT_BIT_FLAG; - } - - /** - * If set, the field shall not scroll (horizontally for single-line fields, vertically for multiple-line fields) - * to accommodate more text than fits within its annotation rectangle. Once the field is full, no further text - * shall be accepted for interactive form filling; for non-interactive form filling, the filler should take care - * not to add more character than will visibly fit in the defined area. - * - * @return true if do not scroll is enabled, otherwise false. - */ - public boolean isDoNotScroll() { - return (getFlags() & DO_NOT_SCROLL_BIT_FLAG) == DO_NOT_SCROLL_BIT_FLAG; - } - - /** - * May be set only if the MaxLen entry is present in the text field dictionary (see Table 229) and if the Multiline, - * Password, and FileSelect flags are clear. If set, the field shall be automatically divided into as many equally - * spaced positions, or combs, as the value of MaxLen, and the text is laid out into those combs. - * - * @return true if comb is enabled, otherwise false. - */ - public boolean isComb() { - return (getFlags() & COMB_BIT_FLAG) == COMB_BIT_FLAG; - } - - /** - * If set, the value of this field shall be a rich text string (see 12.7.3.4, “Rich Text Stringsâ€). If the field has - * a value, the RV entry of the field dictionary (Table 222) shall specify the rich text string. - * - * @return true if file select, otherwise false. - */ - public boolean isRichText() { - return (getFlags() & RICH_TEXT_BIT_FLAG) == RICH_TEXT_BIT_FLAG; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/TransformParams.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/TransformParams.java deleted file mode 100644 index 1d317c4564..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/TransformParams.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Name; - -/** - * Base interface for TransformParams. - */ -public interface TransformParams { - /** - * (Optional) The type of PDF object that this dictionary describes; if present, shall be TransformParams for a - * transform parameters dictionary. - */ - public static final Name TRANSFORM_PARAMS_TYPE_VALUE = new Name("TransformParams"); - - /** - * The UR transform parameters dictionary version. - */ - public static final Name VERSION_KEY = new Name("V"); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/UR3TransferParam.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/UR3TransferParam.java deleted file mode 100644 index e3d2cb9e1c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/UR3TransferParam.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * The UR transform method shall be used to detect changes to a document that shall invalidate a usage rightssignature, - * which is referred to from the UR3 entry in the permissions dictionary (see 12.8.4, Permissions). Usage rights - * signatures shall be used to enable additional interactive features that may not available by default in a conforming - * reader. The signature shall be used to validate that the permissions have been granted by a bonafide granting - * authority. The transform parameters dictionary (see Table 255) specifies the additional rights that shall be enabled - * if the signature is valid. If the signature is invalid because the document has been modified in a way that is not - * permitted or the identity of the signer is not granted the extended permissions, additional rights shall not be granted. - *
- * EXAMPLE
- * Adobe Systems grants permissions to enable additional features in Adobe Reader, using public-key cryptography. It - * uses certificate authorities to issue public key certificateChain to document creators with which it has entered into a - * business relationship. Adobe Reader verifies that the rights-enabling signature uses a certificate from an - * Adobe-authorized certificate authority. Other conforming readers are free to use this same mechanism for their - * own purposes. - *
- * UR3 (PDF 1.6): The ByteRange entry in the signature dictionary (see Table 252) shall be present. First, a conforming - * reader shall verify the byte range digest to determine whether the portion of the document specified by ByteRange - * corresponds to the state of the document at the time of signing. Next, - * a conforming reader shall examine the current - * version of the document to see whether there have been modifications to any objects that are not permitted by the - * transform parameters. - */ -public class UR3TransferParam extends Dictionary implements TransformParams { - - /** - * An array of names specifying additional document-wide usage rights for the document. - */ - public static final Name DOCUMENT_KEY = new Name("Document"); - - /** - * The UR transform parameters dictionary version. The value shall be 2.2. - */ - public static final Name VERSION_DEFAULT_VALUE = new Name("2.2"); - - /** - * (Optional) A text string that may be used to specify any arbitrary information, such as the reason for adding - * usage rights to the document. - */ - public static final Name MSG_KEY = new Name("Msg"); - - - /** - * (Optional) An array of names specifying additional annotation-related usage rights for the document. Valid names - * (PDF 1.5) are Create, Delete, Modify, Copy, Import, and Export, which shall permit the user to perform the named - * operation on annotations. - */ - public static final Name ANNOTATION_KEY = new Name("Annots"); - - // PDF 1.5 Valid names - public static final Name ANNOTATION_VALUE_CREATE = new Name("Create"); - public static final Name ANNOTATION_VALUE_DELETE = new Name("Delete"); - public static final Name ANNOTATION_VALUE_MODIFY = new Name("Modify"); - public static final Name ANNOTATION_VALUE_COPY = new Name("Copy"); - public static final Name ANNOTATION_VALUE_IMPORT = new Name("Import"); - public static final Name ANNOTATION_VALUE_EXPORT = new Name("Export"); - - // PDF 1.6 Valid names - - /** - * Permits online commenting; that is, the ability to upload or download markup annotations from a server. - */ - public static final Name ANNOTATION_VALUE_ONLINE = new Name("Online"); - - /** - * Permits a user interface to be shown that summarizes the comments (markup annotations) in a document. - */ - public static final Name ANNOTATION_VALUE_SUMMARY_VIEW = new Name("SummaryView"); - - /** - * (Optional) An array of names specifying additional form-field-related usage rights for the document. - */ - public static final Name FORM_KEY = new Name("Form"); - - /** - * Permits the user to add form fields to the document. - */ - public static final Name FORM_VALUE_ADD = new Name("Add"); - - /** - * Permits the user to delete form fields to the document. - */ - public static final Name FORM_VALUE_DELETE = new Name("Delete"); - - /** - * Permits the user to save a document on which form fill-in has been done. - */ - public static final Name FORM_VALUE_FILL_IN = new Name("FillIn"); - - /** - * Permits the user to import form data files in FDF, XFDF and text (CSV/TSV) formats. - */ - public static final Name FORM_VALUE_IMPORT = new Name("Import"); - - /** - * Permits the user to export form data files as FDF or XFDF. - */ - public static final Name FORM_VALUE_EXPORT = new Name("Export"); - - /** - * Permits the user to submit form data when the document is not open in a Web browser. - */ - public static final Name FORM_VALUE_SUBMIT_STANDALONE = new Name("SubmitStandalone"); - - /** - * Permits new pages to be instantiated from named page templates. - */ - public static final Name FORM_VALUE_SPAWN_TEMPLATE = new Name("SpawnTemplate"); - - /** - * The following names (PDF 1.6) shall be permitted only when the signature dictionary is referenced from the UR3 - * entry of the permissions dictionary; - */ - - /** - * Permits (PDF 1.6) text form field data to be encoded as a plaintext two-dimensional barcode. - */ - public static final Name FORM_VALUE_BARCODE_PLAIN_TEXT = new Name("BarcodePlainText"); - - /** - * Permits (PDF 1.6) the use of forms-specific online mechanisms such as SOAP or Active Data Object. - */ - public static final Name FORM_VALUE_ONLINE = new Name("Online"); - - /** - * (Optional) An array of names specifying additional signature-related usage rights for the document. The only - * defined value shall be Modify, which permits a user to apply a digital signature to an existing signature form - * field or clear a signed signature form field. - */ - public static final Name SIGNATURE_KEY = new Name("Signature"); - - /** - * Modify, which permits a user to apply a digital signature to an existing signature form - * field or clear a signed signature form field. - */ - public static final Name SIGNATURE_VALUE_MODIFY = new Name("Modify"); - - /** - * (Optional; PDF 1.6) An array of names specifying additional usage rights for named embedded files in the - * document. Valid names shall be Create, Delete, Modify, and Import, which shall permit the user to perform the - * named operation on named embedded files. - */ - public static final Name EMBEDDED_FILES_KEY = new Name("EF"); - - public static final Name EMBEDDED_FILES_VALUE_CREATE = new Name("Create"); - public static final Name EMBEDDED_FILES_VALUE_DELETE = new Name("Delete"); - public static final Name EMBEDDED_FILES_VALUE_MODIFY = new Name("Modify"); - public static final Name EMBEDDED_FILES_VALUE_IMPORT = new Name("Import"); - - public static final Name PERMISSION_KEY = new Name("P"); - - public UR3TransferParam(Library library, HashMap entries) { - super(library, entries); - } - - /** - * (Optional) An array of names specifying additional document-wide usage rights for the document. The only defined - * value shall be FullSave, which permits a user to save the document along with modified form and/or annotation - * data. (PDF 1.5) Any usage right that permits the document to be modified implicitly shall enable the FullSave - * right. - *
- * If the PDF document contains a UR3 dictionary, only rights specified by the Annots entry that permit the document - * to be modified shall implicitly enable the FullSave right. For all other rights, FullSave shall be explicitly - * enabled in order to save the document. (Signature rights shall permit saving as part of the signing process but - * not otherwise). - *
- * If the P entry in the UR transform parameters dictionary is true (PDF 1.6) and greater conforming readers shall - * permit only those rights that are enabled by the entries in the dictionary. However, conforming readers shall - * permit saving the document as long as any rights that permit modifying the document are enabled. - * - * @return array of named documents rights. - */ - public ArrayList getDocumentRights() { - return (ArrayList) library.getArray(entries, DOCUMENT_KEY); - } - - /** - * A text string that may be used to specify any arbitrary information, such as the reason for adding - * usage rights to the document. - * - * @return arbitrary info if any, null otherwise. - */ - public String getMsg() { - Object value = library.getObject(entries, MSG_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - return Utils.convertStringObject(library, text); - } else { - return null; - } - } - - /** - * Gets the UR transform parameters dictionary version. The value shall be 2.2. If an unknown version is present, - * no rights shall be enabled. - * NOTE
- * this value is a name object, not a number. - * - * @return a name value of 2.2 if present, otherwise specified value. - */ - public Name getVersion() { - return library.getName(entries, VERSION_KEY); - } - - /** - * An array of names specifying additional annotation-related usage rights for the document. - * - * @return Array of annotation rights names, null if not set. - */ - public ArrayList getAnnotationRights() { - return (ArrayList) library.getArray(entries, ANNOTATION_KEY); - } - - /** - * An array of names specifying additional form-field-related usage rights for the document. - * - * @return Array of forms rights names, null if not set. - */ - public ArrayList getFormRights() { - return (ArrayList) library.getArray(entries, FORM_KEY); - } - - /** - * An array of names specifying additional signature-related usage rights for the document. - * - * @return if the value if isn't Modify, will will be null. - */ - public ArrayList getSignatureRights() { - return (ArrayList) library.getArray(entries, SIGNATURE_KEY); - } - - /** - * An array of names specifying additional usage rights for named embedded files in the document. - * - * @return list of EMBEDDED_FILES_* names or null if not set. - */ - public ArrayList getEmbeddedFilesRights() { - return (ArrayList) library.getArray(entries, EMBEDDED_FILES_KEY); - } - - /** - * Default value: false. - * - * @return If true, permissions for the document shall be restricted in all consumer applications to those permissions - * granted by a conforming reader, while allowing permissions for rights enabled by other entries in this dictionary. - */ - public boolean getPermission() { - return library.getBoolean(entries, PERMISSION_KEY); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/VariableTextFieldDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/VariableTextFieldDictionary.java deleted file mode 100644 index c22e73c574..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/VariableTextFieldDictionary.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.pobjects.fonts.Font; -import org.icepdf.core.pobjects.graphics.GraphicsState; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; -import org.icepdf.core.util.content.ContentParser; -import org.icepdf.core.util.content.ContentParserFactory; - -import java.awt.*; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.icepdf.core.pobjects.acroform.InteractiveForm.DR_KEY; - -/** - * When the contents and properties of a field are known in advance, its visual - * appearance can be specified by an appearance stream defined in the PDF file - * (see 12.5.5, “Appearance Streams,†and 12.5.6.19, “Widget Annotationsâ€). In - * some cases, however, the field may contain text whose value is not known - * until viewing time. - * - * @since 5.1 - */ -public class VariableTextFieldDictionary extends FieldDictionary { - - private static final Logger logger = - Logger.getLogger(VariableTextFieldDictionary.class.toString()); - - public enum Quadding { - LEFT_JUSTIFIED, CENTERED, RIGHT_JUSTIFIED - } - - /** - * The default appearance string containing a sequence of valid page-content - * graphics or text state operators that define such properties as the field’s - * text size and colour. - */ - public static final Name DA_KEY = new Name("DA"); - - /** - * A code specifying the form of quadding (justification) that shall be used - * in displaying the text: - * 0 Left-justified - * 1 Centered - * 2 Right-justified - * Default value: 0 (left-justified). - */ - public static final Name Q_KEY = new Name("Q"); - - /** - * A default style string, as described in 12.7.3.4, “Rich Text Strings.†- */ - public static final Name DS_KEY = new Name("DS"); - - /** - * Variable text fields. - */ - private String defaultAppearance; - private String defaultStyle; - private String defaultRichText; - - /** - * A rich text string, as described in 12.7.3.4, “Rich Text Strings.†- */ - public static final Name RV_KEY = new Name("RV"); - - protected Quadding quadding = Quadding.LEFT_JUSTIFIED; - protected float size = 12; - protected Name fontName = new Name("Helv"); - protected Font font = null; - protected Color color = Color.BLACK; - - public VariableTextFieldDictionary(Library library, HashMap entries) { - super(library, entries); - - // parse out quadding - Number value = library.getInt(entries, Q_KEY); - int quad = value.intValue(); - switch (quad) { - case 0: - quadding = Quadding.LEFT_JUSTIFIED; - break; - case 1: - quadding = Quadding.CENTERED; - break; - case 2: - quadding = Quadding.RIGHT_JUSTIFIED; - break; - default: - quadding = Quadding.LEFT_JUSTIFIED; - break; - } - // get the default style string - Object tmp = library.getObject(entries, DS_KEY); - if (tmp != null) { - defaultStyle = Utils.convertStringObject(library, (StringObject) tmp); - } - - tmp = library.getObject(entries, RV_KEY); - if (tmp != null) { - if (tmp instanceof StringObject) { - defaultStyle = Utils.convertStringObject(library, (StringObject) tmp); - } else if (tmp instanceof Stream) { - defaultStyle = new String(((Stream) tmp).getDecodedStreamBytes()); - } - } - - // parse out fontName, size and color. - // /ZaDb 12 Tf 0 g - tmp = library.getObject(entries, DA_KEY); - if (tmp instanceof StringObject) { - defaultAppearance = Utils.convertStringObject(library, (StringObject) tmp); - Resources resources = library.getResources(entries, DR_KEY); - // use the DA and DR dictionary to get a valid graphics state and thus the - // the font and colour information we need to generate a new content stream - if (resources != null) { - try { - ContentParser cp = ContentParserFactory.getInstance() - .getContentParser(library, resources); - cp.parseTextBlocks(new byte[][]{defaultAppearance.getBytes()}); - GraphicsState gs = cp.getGraphicsState(); - if (gs != null) { - color = gs.getFillColor(); - size = gs.getTextState().tsize; - if (gs.getTextState().font != null && - gs.getTextState().font.getSubTypeFormat() != Font.CID_FORMAT) { - font = gs.getTextState().font; - fontName = gs.getTextState().fontName; - } - } - } catch (Throwable e) { - logger.warning("Could not validate default appearance, defaulting."); - } - } - } - - } - - /** - * If the DA key is present the appearance stream is generated as is, however if not then the content - * is passed and we try to pull the color, size, font, and font name. - * - * @param content - * @return - */ - public String generateDefaultAppearance(String content, Resources resources) { - try { - String possibleContent; - if (library.getObject(entries, DA_KEY) != null) { - possibleContent = library.getString(entries, DA_KEY); - } else if (parentField != null && library.getObject(parentField.getEntries(), DA_KEY) != null) { - possibleContent = library.getString(parentField.getEntries(), DA_KEY); - } else { - possibleContent = content != null ? content : ""; - } - if (resources == null) { - resources = library.getCatalog().getInteractiveForm().getResources(); - } - ContentParser cp = ContentParserFactory.getInstance() - .getContentParser(library, resources); - cp.parseTextBlocks(new byte[][]{possibleContent.getBytes()}); - GraphicsState gs = cp.getGraphicsState(); - if (gs != null) { - if (gs.getFillColor() != null) color = gs.getFillColor(); - if (gs.getTextState().tsize > 0) { - size = gs.getTextState().tsize; - } else { - // default to basic size, as last resort. - size = 10; - } - // further work is needed here to add font mapping support when CID fonts are detected, - // this may also be a fix for our asian font write support problem. - if (gs.getTextState().font != null && - gs.getTextState().font.getSubTypeFormat() != Font.CID_FORMAT) { - if (gs.getTextState().font != null) font = gs.getTextState().font; - if (gs.getTextState().fontName != null) fontName = gs.getTextState().fontName; - } - } - } catch (Throwable e) { - logger.warning("Could not generate default appearance stream."); - if (logger.isLoggable(Level.FINEST)) { - logger.log(Level.FINEST, "Error parsing text feld content stream", e); - } - } - return color.getRed() / 255.0f + " " + color.getGreen() / 255.0f + " " + color.getBlue() / 255.0f + " rg " + - "/" + fontName + " " + - size + " Tf "; - } - - public String getDefaultAppearance() { - return defaultAppearance; - } - - public float getDefaultFontSize() { - return size; - } - - public Name getFontName() { - return fontName; - } - - public float getSize() { - return size; - } - - public Font getFont() { - return font; - } - - public Color getColor() { - return color; - } - - public Quadding getQuadding() { - return quadding; - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/AbstractPkcsValidator.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/AbstractPkcsValidator.java deleted file mode 100644 index f47028e3de..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/AbstractPkcsValidator.java +++ /dev/null @@ -1,791 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature; - -import org.bouncycastle.asn1.*; -import org.bouncycastle.asn1.cms.Attribute; -import org.bouncycastle.asn1.cms.AttributeTable; -import org.bouncycastle.asn1.cms.ContentInfo; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.jce.provider.X509CertParser; -import org.bouncycastle.tsp.TimeStampToken; -import org.bouncycastle.x509.util.StreamParsingException; -import org.icepdf.core.io.SeekableInput; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.signature.certificates.CertificateVerifier; -import org.icepdf.core.pobjects.acroform.signature.exceptions.CertificateVerificationException; -import org.icepdf.core.pobjects.acroform.signature.exceptions.RevocationVerificationException; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SelfSignedVerificationException; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.util.Defs; - -import javax.security.auth.x500.X500Principal; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.security.*; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.X509Certificate; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * PKCS#1 and PKCS#7 are fairly close from a verification point of view so we'll use this class for common - * functionality between PKCS#1 and PKCS#7. - */ -public abstract class AbstractPkcsValidator implements SignatureValidator { - - private static final Logger logger = - Logger.getLogger(AbstractPkcsValidator.class.toString()); - - private static String caCertLocation = "/lib/security/cacerts"; - - static { - String javaHome = Defs.sysProperty("java.home"); - caCertLocation = Defs.sysProperty("org.icepdf.core.signatures.caCertPath", javaHome + caCertLocation); - } - - // data object descriptor codes. - public static final String ID_DATA_OBJECT_IDENTIFIER = PKCSObjectIdentifiers.data.getId(); - public static final String ID_SIGNED_DATA_OBJECT_IDENTIFIER = PKCSObjectIdentifiers.signedData.getId(); - public static final String ID_ENVELOPED_DATA_OBJECT_IDENTIFIER = PKCSObjectIdentifiers.envelopedData.getId(); - public static final String ID_DIGESTED_DATA_OBJECT_IDENTIFIER = PKCSObjectIdentifiers.digestedData.getId(); - public static final String ID_ENCRYPTED_DATA_OBJECT_IDENTIFIER = PKCSObjectIdentifiers.encryptedData.getId(); - - private static final String ALGORITHM_WITH = "with"; - - // signature dictionary of signature do verify - protected SignatureFieldDictionary signatureFieldDictionary; - - // signer certificate - protected Collection certificateChain; - protected X509Certificate signerCertificate; - // digests used for verification - protected String digestAlgorithmIdentifier; - protected String signatureAlgorithmIdentifier; - // PKCS - protected ASN1Set signedAttributesSequence; - protected byte[] encapsulatedContentInfoData; - protected byte[] messageDigest; - protected byte[] signatureValue; - - // validity checks. - private boolean isSignedDataModified = true; - private boolean isDocumentDataModified; - private boolean isSignaturesCoverDocumentLength; - private boolean isCertificateChainTrusted; - private boolean isCertificateDateValid = true; - private boolean isRevocation; - private boolean isSelfSigned; - // todo impelement singer time check. - private boolean isSignerTimeValid; - private boolean isEmbeddedTimeStamp; - // last time validate call was made. - private Date lastVerified; - - protected boolean initialized; - - public AbstractPkcsValidator(SignatureFieldDictionary signatureFieldDictionary) throws SignatureIntegrityException { - this.signatureFieldDictionary = signatureFieldDictionary; - if (!initialized) { - init(); - } - } - - /** - * Runs a series of tests to try and determine the validity o - * - * @throws SignatureIntegrityException - */ - public abstract void validate() throws SignatureIntegrityException; - - protected void announceSignatureType(SignatureDictionary signatureDictionary) { - if (logger.isLoggable(Level.FINE)) { - Name preferredHandler = signatureDictionary.getFilter(); - Name encoding = signatureDictionary.getSubFilter(); - if (logger.isLoggable(Level.FINER)) { - logger.finer("Signature Handler: " + preferredHandler); - logger.finer(" Encoding: " + encoding); - logger.finer("Starting Validation"); - } - } - } - - /** - * SignedData ::= SEQUENCE { - * 0, version CMSVersion, - * 1, digestAlgorithms DigestAlgorithmIdentifiers, - * 2, encapContentInfo EncapsulatedContentInfo, - * 3, certificateChain [0] IMPLICIT CertificateSet OPTIONAL, - * 4, crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, - * 5, signerInfos SignerInfos } - *

- * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier - * SignerInfos ::= SET OF SignerInfo - */ - protected void parseSignerData(ASN1Sequence signedData, byte[] cmsData) throws SignatureIntegrityException { - // digest algorithms ID, not currently using them but useful for debug. - if (logger.isLoggable(Level.FINER)) { - // should always be 1. - int cmsVersion = ((ASN1Integer) signedData.getObjectAt(0)).getValue().intValue(); - logger.finest("CMS version: " + cmsVersion); - Enumeration enumeration = ((ASN1Set) signedData.getObjectAt(1)).getObjects(); - while (enumeration.hasMoreElements()) { - String objectId = ((ASN1ObjectIdentifier) enumeration.nextElement().getObjectAt(0)).getId(); - try { - String digestAlgorithmName = AlgorithmIdentifier.getDigestAlgorithmName(objectId); - MessageDigest tmp = AlgorithmIdentifier.getDigestInstance(objectId, null); - logger.finest("DigestAlgorithmIdentifiers: " + digestAlgorithmName + " " + objectId); - logger.finest(tmp.toString()); - } catch (Throwable ex) { - logger.log(Level.WARNING, "Error finding iod: " + objectId, ex); - } - } - } - /** - * EncapsulatedContentInfo ::= SEQUENCE { - * eContentType ContentType, - * eContent [0] EXPLICIT OCTET STRING OPTIONAL } - * - * ContentType ::= OBJECT IDENTIFIER - */ - encapsulatedContentInfoData = null; - ASN1Sequence encapsulatedContentInfo = (ASN1Sequence) signedData.getObjectAt(2); - // grab just the first definitions, as we are looking for encapuslated data for PKCS7.sha1. - if (encapsulatedContentInfo.size() >= 2) { - // should still be iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 ... - ASN1ObjectIdentifier eObjectIdentifier = (ASN1ObjectIdentifier) encapsulatedContentInfo.getObjectAt(0); - String eObjectIdentifierId = eObjectIdentifier.getId(); - if (logger.isLoggable(Level.FINER)) { - logger.finest("EncapsulatedContentInfo: " + eObjectIdentifierId + " " + - Pkcs7Validator.getObjectIdName(eObjectIdentifierId)); - } - // should be octets encode as pkcs#7 - ASN1OctetString eContent = (ASN1OctetString) ((ASN1TaggedObject) encapsulatedContentInfo.getObjectAt(1)) - .getObject(); - // shows up in pkcs7.sha1 only - encapsulatedContentInfoData = eContent.getOctets(); - if (logger.isLoggable(Level.FINER)) { - logger.finest("EncapsulatedContentInfo Data " + eContent.toString()); - } - } else if (encapsulatedContentInfo.size() == 1) { - if (logger.isLoggable(Level.FINER)) { - ASN1ObjectIdentifier eObjectIdentifier = (ASN1ObjectIdentifier) encapsulatedContentInfo.getObjectAt(0); - String eObjectIdentifierId = eObjectIdentifier.getId(); - logger.finest("EncapsulatedContentInfo size is 1: " + eObjectIdentifierId + " " + - Pkcs7Validator.getObjectIdName(eObjectIdentifierId)); - } - } - - // grab the signer info. - ASN1Sequence signerInfo = parseCertificateData(cmsData, signedData); - // DigestAlgorithmIdentifier ::= AlgorithmIdentifier - digestAlgorithmIdentifier = ((ASN1ObjectIdentifier) - ((ASN1Sequence) signerInfo.getObjectAt(2)).getObjectAt(0)).getId(); - - // signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, - // signedAttrs is optional so we look for the occurrence - // - // SignedAttributes ::= SET SIZE (1..MAX) OF Attribute - // - // Attribute ::= SEQUENCE { - // attrType OBJECT IDENTIFIER, - // attrValues SET OF AttributeValue } - // - // AttributeValue ::= ANY - // SignatureValue ::= OCTET STRING - int nextEntry = 3; - messageDigest = null; - ASN1TaggedObject signedAttributes; - signedAttributesSequence = null; - if (signerInfo.getObjectAt(nextEntry) instanceof ASN1TaggedObject) { - signedAttributes = (ASN1TaggedObject) signerInfo.getObjectAt(nextEntry); - signedAttributesSequence = ASN1Set.getInstance(signedAttributes, false); - for (int i = 0, max = signedAttributesSequence.size(); i < max; ++i) { - // attribute type/value pair. - ASN1Sequence attributePair = (ASN1Sequence) signedAttributesSequence.getObjectAt(i); - // mainly just looking for the message digest. - if (((ASN1ObjectIdentifier) attributePair.getObjectAt(0)).getId().equals( - PKCSObjectIdentifiers.pkcs_9_at_messageDigest.getId())) { - ASN1Set set = (ASN1Set) attributePair.getObjectAt(1); - messageDigest = ((ASN1OctetString) set.getObjectAt(0)).getOctets(); - } - // try and pull out the signing time. - // currently not using this time. -// if (((ASN1ObjectIdentifier) attributePair.getObjectAt(0)).getId().equals( -// PKCSObjectIdentifiers.pkcs_9_at_signingTime.getId())) { -// ASN1Set set = (ASN1Set) attributePair.getObjectAt(1); -// ASN1UTCTime signerTime = ((ASN1UTCTime) set.getObjectAt(0)); -// try { -// // see if the signer time matches the certificate validity times. -// System.out.println(" SignatureSigner Time " + signerTime.getDate()); -// } catch (ParseException e) { -// e.printStackTrace(); -// } -// } - // more attributes to come. - } - if (messageDigest == null) { - throw new SignatureIntegrityException("Message Digest can nut be null"); - } - ++nextEntry; - } - // signatureAlgorithm SignatureAlgorithmIdentifier, - signatureAlgorithmIdentifier = ((ASN1ObjectIdentifier) ((ASN1Sequence) signerInfo.getObjectAt(nextEntry)) - .getObjectAt(0)).getId(); - nextEntry++; - // signature SignatureValue - signatureValue = ((ASN1OctetString) signerInfo.getObjectAt(nextEntry)).getOctets(); - nextEntry++; - // unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL - // once again optional so we check to see if the entry is available. - if (nextEntry < signerInfo.size() && signerInfo.getObjectAt(nextEntry) instanceof ASN1TaggedObject) { - ASN1TaggedObject unsignedAttributes = (ASN1TaggedObject) signerInfo.getObjectAt(nextEntry); - ASN1Set unsignedAttributeSequence = ASN1Set.getInstance(unsignedAttributes, false); - AttributeTable attributeTable = new AttributeTable(unsignedAttributeSequence); - Attribute timeStamp = attributeTable.get(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken); - if (timeStamp != null && timeStamp.getAttrValues().size() > 0) { - ASN1Set attributeValues = timeStamp.getAttrValues(); - ASN1Sequence tokenSequence = ASN1Sequence.getInstance(attributeValues.getObjectAt(0)); - ContentInfo contentInfo = ContentInfo.getInstance(tokenSequence); - // if we can parse it we call it good, so cert has a embedded time but we don't do any validation on it - try { - new TimeStampToken(contentInfo); - isEmbeddedTimeStamp = true; - } catch (Throwable e1) { - throw new SignatureIntegrityException("Valid TimeStamp could now be created"); - } - } - } - } - - private ASN1Sequence parseCertificateData(byte[] cmsData, ASN1Sequence signedData) throws SignatureIntegrityException { - - // Next two entries are optional. - // 3, certificateChain [0] IMPLICIT CertificateSet OPTIONAL, - // crls [1] IMPLICIT RevocationInfoChoices OPTIONAL, - // Most of our example seem to have what looks like a CertificateSet but I haven't had much luck finding - // a specific format to follow ot parse out the data. - // CertificateSet is defined as:
- // The CertificateSet type provides a set of certificateChain. It is - // intended that the set be sufficient to contain certification paths - // from a recognized "root" or "top-level certification authority" to - // all of the sender certificateChain with which the set is associated. - // However, there may be more certificateChain than necessary, or there MAY - // be fewer than necessary. - //
- // The precise meaning of a "certification path" is outside the scope of - // this document. However, [PROFILE] provides a definition for X.509 - // certificateChain. Some applications may impose upper limits on the - // length of a certification path; others may enforce certain - // relationships between the subjects and issuers of certificateChain within - // a certification path. - //
- // Object tmp = signedData.getObjectAt(3); - - // the certificateChain - X509CertParser x509CertParser = new X509CertParser(); - x509CertParser.engineInit(new ByteArrayInputStream(cmsData)); - try { - certificateChain = x509CertParser.engineReadAll(); - } catch (StreamParsingException e) { - logger.log(Level.WARNING, "Error parsing certificate data: ", e); - throw new SignatureIntegrityException("Error parsing certificate data "); - } - - /** - * SignerInfo ::= SEQUENCE { - * 0, version CMSVersion, - * 1, sid SignerIdentifier, - * 2, digestAlgorithm DigestAlgorithmIdentifier, - * signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, - * signatureAlgorithm SignatureAlgorithmIdentifier, - * signature SignatureValue, - * unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } - */ - // the signerInfos is going to be the last entry in the sequence. - ASN1Set signerInfos = (ASN1Set) signedData.getObjectAt(signedData.size() - 1); - // and we only need the first entry, as enveloped signatures aren't found in PDF land. - ASN1Sequence signerInfo = (ASN1Sequence) signerInfos.getObjectAt(0); - // If the SignerIdentifier is the CHOICE issuerAndSerialNumber, then the version MUST be 1. - // If the SignerIdentifier is subjectKeyIdentifier, then the version MUST be 3. - int signerVersion = ((ASN1Integer) signerInfo.getObjectAt(0)).getValue().intValue(); - /** - * SignerIdentifier ::= CHOICE { - * issuerAndSerialNumber IssuerAndSerialNumber, - * subjectKeyIdentifier [0] SubjectKeyIdentifier } - * - * SubjectKeyIdentifier ::= OCTET STRING - */ - ASN1Sequence issuerAndSerialNumber = (ASN1Sequence) signerInfo.getObjectAt(1); - signerCertificate = null; - if (signerVersion == 1) { - // parse out the issue and SerialNumber. - X500Principal issuer; - try { - issuer = new X500Principal(issuerAndSerialNumber.getObjectAt(0).toASN1Primitive().getEncoded()); - } catch (IOException e1) { - logger.warning("Could not create X500 Principle data "); - throw new SignatureIntegrityException("Could not create X500 Principle data"); - } - BigInteger serialNumber = ((ASN1Integer) issuerAndSerialNumber.getObjectAt(1)).getValue(); - signerCertificate = null; - // signer cert should always be the first in the list. - for (Object element : certificateChain) { - X509Certificate certificate = (X509Certificate) element; - if (certificate.getIssuerX500Principal().equals(issuer) && - serialNumber.equals(certificate.getSerialNumber())) { - signerCertificate = certificate; - break; - } else { - if (logger.isLoggable(Level.FINER)) { - logger.finer("Certificate and issuer could not be verified as the same entity."); - } - } - } - } else if (signerVersion == 3) { - // SubjectKeyIdentifier ::= OCTET STRING - // ASN1Primitive subjectKeyIdentifier = issuerAndSerialNumber.getObjectAt(0).toASN1Primitive(); - throw new IllegalStateException("Singer version 3 not supported"); - } - return signerInfo; - } - - - /** - * The CMS associates a content type identifier with a content. The syntax MUST have ASN.1 type ContentInfo: - * ContentInfo ::= SEQUENCE { - * contentType ContentType, - * content [0] EXPLICIT ANY DEFINED BY contentType } - * ContentType ::= OBJECT IDENTIFIER - */ - protected ASN1Sequence captureSignedData(byte[] cmsData) - throws SignatureIntegrityException { - ASN1Sequence cmsSequence = buildASN1Primitive(cmsData); - if (cmsSequence == null || cmsSequence.getObjectAt(0) == null) { - throw new SignatureIntegrityException("ContentInfo does not contain content type."); - } - /** - * id-data OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 } - * Currently not doing anything with this but we may need it at a later date to support different signed data. - * But we are looking pkcs7 variants. - */ - ASN1ObjectIdentifier objectIdentifier = (ASN1ObjectIdentifier) cmsSequence.getObjectAt(0); - if (objectIdentifier == null || - !(ID_DATA_OBJECT_IDENTIFIER.equals(objectIdentifier.getId()) || - ID_DIGESTED_DATA_OBJECT_IDENTIFIER.equals(objectIdentifier.getId()) || - ID_ENCRYPTED_DATA_OBJECT_IDENTIFIER.equals(objectIdentifier.getId()) || - ID_ENVELOPED_DATA_OBJECT_IDENTIFIER.equals(objectIdentifier.getId()) || - ID_SIGNED_DATA_OBJECT_IDENTIFIER.equals(objectIdentifier.getId()))) { - logger.warning("ANSI object id is not a valid PKCS7 identifier " + objectIdentifier); - throw new SignatureIntegrityException("ANSI object id is not a valid PKCS7 identifier"); - } else { - logger.finest("Object identifier: " + objectIdentifier.getId() + " " + - Pkcs7Validator.getObjectIdName(objectIdentifier.getId())); - } - - if (!ID_SIGNED_DATA_OBJECT_IDENTIFIER.equals(objectIdentifier.getId())) { - throw new SignatureIntegrityException("ANSI.1 object must be of type Signed Data"); - } - // Signed-data content type -- start of parsing - return (ASN1Sequence) ((ASN1TaggedObject) cmsSequence.getObjectAt(1)).getObject(); - } - - // Verify that the signature is indeed correct and verify the public key is a match. - protected boolean verifySignedAttributes(String provider, X509Certificate signerCertificate, - byte[] signatureValue, - String signatureAlgorithmIdentifier, - String digestAlgorithmIdentifier, - byte[] attr) throws SignatureIntegrityException { - try { - Signature signature = createSignature(signerCertificate.getPublicKey(), provider, - signatureAlgorithmIdentifier, digestAlgorithmIdentifier); - signature.update(attr); - return signature.verify(signatureValue); - } catch (InvalidKeyException e) { - throw new SignatureIntegrityException(e); - } catch (NoSuchAlgorithmException e) { - throw new SignatureIntegrityException(e); - } catch (SignatureException e) { - throw new SignatureIntegrityException(e); - } - } - - // Creates a signature object for the given ID's and verifies the public key. - protected Signature createSignature(PublicKey publicKey, String provider, - String signatureAlgorithmIdentifier, String digestAlgorithmIdentifier) - throws InvalidKeyException, NoSuchAlgorithmException { - String encryptionAlgorithmName = AlgorithmIdentifier.getEncryptionAlgorithmName(signatureAlgorithmIdentifier); - String digestAlgorithmName = AlgorithmIdentifier.getDigestAlgorithmName(digestAlgorithmIdentifier); - String digestAlgorithm = digestAlgorithmName + ALGORITHM_WITH + encryptionAlgorithmName; - logger.finest("DigestAlgorithm " + digestAlgorithm); - Signature signature; - if (provider != null) { - try { - signature = Signature.getInstance(digestAlgorithm, provider); - } catch (NoSuchProviderException e) { - signature = Signature.getInstance(digestAlgorithm); - } - } else { - signature = Signature.getInstance(digestAlgorithm); - } - - signature.initVerify(publicKey); - return signature; - } - - /** - * Takes the DER-encoded PKCS#1 binary data or PKCS#7 binary data object and reads it into an - * Abstract Syntax Notation One (ASNI.1) object. - * - * @return ASN1Sequence representing the Cryptographic Message Syntax (CMS), null if data stream - * could not be loaded - */ - protected ASN1Sequence buildASN1Primitive(byte[] cmsData) { - try { - // setup the - ASN1InputStream abstractSyntaxNotationStream = new ASN1InputStream(new ByteArrayInputStream(cmsData)); - ASN1Primitive pkcs = abstractSyntaxNotationStream.readObject(); - - if (pkcs instanceof ASN1Sequence) { - if (logger.isLoggable(Level.FINER)) { - logger.finest("ASN1Sequence found starting sequence processing. "); - } - return (ASN1Sequence) pkcs; - } else if (logger.isLoggable(Level.FINER)) { - logger.finest("ASN1Sequence was not found backing out. "); - } - - } catch (IOException e) { - logger.log(Level.WARNING, "ASN1 stream could not be read.", e); - } - return null; - } - - /** - * Gets a descriptive name for the given ANSI.1 object identifier number. - * - * @param objectId object id to lookup against know list of PKCS#7 id's. - * @return string describing the hard to read object id. - */ - protected static String getObjectIdName(String objectId) { - if (ID_DATA_OBJECT_IDENTIFIER.equals(objectId)) { - return "ID Data Object Identifier"; - } else if (ID_SIGNED_DATA_OBJECT_IDENTIFIER.equals(objectId)) { - return "ID Signed Data Object Identifier"; - } else if (ID_ENVELOPED_DATA_OBJECT_IDENTIFIER.equals(objectId)) { - return "ID Enveloped Data Object Identifier"; - } else if (ID_ENCRYPTED_DATA_OBJECT_IDENTIFIER.equals(objectId)) { - return "ID Encrypted Data Object Identifier"; - } else if (ID_DIGESTED_DATA_OBJECT_IDENTIFIER.equals(objectId)) { - return "ID Digested Data Object Identifier"; - } - return "Unknown"; - } - - /** - * Validates the document against the data in the signatureDictionary. - * - * @throws SignatureIntegrityException - */ - protected void validateDocument() throws SignatureIntegrityException { - - SignatureDictionary signatureDictionary = signatureFieldDictionary.getSignatureDictionary(); - - Signature signature; - MessageDigest messageDigestAlgorithm; - MessageDigest eConMessageDigestAlgorithm; - try { - String provider = signatureDictionary.getFilter().getName(); - - messageDigestAlgorithm = AlgorithmIdentifier.getDigestInstance( - digestAlgorithmIdentifier, provider); - eConMessageDigestAlgorithm = AlgorithmIdentifier.getDigestInstance( - digestAlgorithmIdentifier, provider); - - signature = createSignature(signerCertificate.getPublicKey(), provider, - signatureAlgorithmIdentifier, digestAlgorithmIdentifier); - - PublicKey publicKey = signerCertificate.getPublicKey(); - if (logger.isLoggable(Level.FINER)) { - logger.finest("Certificate: \n" + signerCertificate.toString()); - logger.finest("Public Key: \n" + publicKey); - } - } catch (NoSuchProviderException e1) { - logger.log(Level.WARNING, "No such provider found ", e1); - return; - } catch (NoSuchAlgorithmException e1) { - logger.log(Level.WARNING, "No such algorithm found ", e1); - return; - } catch (InvalidKeyException e1) { - logger.log(Level.WARNING, "Invalid key ", e1); - return; - } - // let digest the data. - ArrayList byteRange = signatureFieldDictionary.getSignatureDictionary().getByteRange(); - SeekableInput documentInput = signatureFieldDictionary.getLibrary().getDocumentInput(); - documentInput.beginThreadAccess(); - try { - long totalLength = documentInput.getLength(); - long digestedLength = byteRange.get(2) + byteRange.get(3); - // this doesn't mean the signature has been tampered with just that there are subsequent modification - // or signatures added after this signature. - if (digestedLength < totalLength) { - isDocumentDataModified = true; - } - documentInput.seekAbsolute(byteRange.get(0)); - byte[] firstSection = new byte[byteRange.get(1)]; - documentInput.read(firstSection); - messageDigestAlgorithm.update(firstSection); - documentInput.seekAbsolute(byteRange.get(2)); - byte[] secondSection = new byte[byteRange.get(3)]; - documentInput.read(secondSection); - messageDigestAlgorithm.update(secondSection); - } catch (IOException e) { - throw new SignatureIntegrityException(e); - } finally { - documentInput.endThreadAccess(); - } - // setup the compare - try { - // RFC3852 - The result of the message digest calculation process depends on whether the signedAttrs field - // is present. When the field is absent, the result is just the message digest of the content as described - // above. When the field is present, however, the result is the message digest of the complete DER encoding - // of the SignedAttrs value contained in the signedAttrs field. - byte[] documentDigestBytes = messageDigestAlgorithm.digest(); - if (signedAttributesSequence != null) { - boolean encapsulatedDigestCheck = true; - boolean verifyEncContentInfoData = true; - if (encapsulatedContentInfoData != null) { - verifyEncContentInfoData = Arrays.equals(documentDigestBytes, encapsulatedContentInfoData); - eConMessageDigestAlgorithm.update(encapsulatedContentInfoData); - encapsulatedDigestCheck = Arrays.equals(eConMessageDigestAlgorithm.digest(), messageDigest); - } - boolean nonEncapsulatedDigestCheck = Arrays.equals(documentDigestBytes, messageDigest); - // When the field is present, however, the result is the message digest of the complete DER encoding of - // the SignedAttrs value contained in the signedAttrs field - boolean isSignatureValid = - verifySignedAttributes(signatureDictionary.getFilter().getName(), signerCertificate, signatureValue, - signatureAlgorithmIdentifier, - digestAlgorithmIdentifier, - signedAttributesSequence.getEncoded(ASN1Encoding.DER)); - if (logger.isLoggable(Level.FINEST)) { - logger.finest("Encapsulated Digest verified: " + encapsulatedDigestCheck); - logger.finest("Non-encapsulated Digest verified: " + nonEncapsulatedDigestCheck); - logger.finest("Signature verified: " + isSignatureValid); - logger.finest("Encapsulated data verified: " + verifyEncContentInfoData); - } - // verify the attributes. - if ((encapsulatedDigestCheck || nonEncapsulatedDigestCheck) && verifyEncContentInfoData) { - isSignedDataModified = false; - } - } else { - if (encapsulatedContentInfoData != null) { - signature.update(messageDigestAlgorithm.digest()); - } - boolean nonEncapsulatedDigestCheck = Arrays.equals(documentDigestBytes, messageDigest); - if (nonEncapsulatedDigestCheck) { - isSignedDataModified = false; - } - } - lastVerified = new Date(); - } catch (SignatureException e) { - throw new SignatureIntegrityException(e); - } catch (IOException e) { - throw new SignatureIntegrityException(e); - } - - try { - KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - java.io.FileInputStream fis = null; - try { - fis = new java.io.FileInputStream(caCertLocation); - trustStore.load(fis, null); - } finally { - if (fis != null) { - fis.close(); - } - } - // cert validation - X509Certificate[] cers = certificateChain.toArray(new X509Certificate[0]); - ArrayList trusted = new ArrayList(trustStore.size()); - Enumeration aliases = trustStore.aliases(); - while (aliases.hasMoreElements()) { - trusted.add((X509Certificate) trustStore.getCertificate(aliases.nextElement())); - } - CertificateVerifier.verifyCertificate(cers[0], trusted); - isCertificateChainTrusted = true; - isCertificateDateValid = true; - lastVerified = new Date(); - } catch (CertificateExpiredException e) { - logger.log(Level.FINEST, "Certificate chain could not be validated, certificate is expired", e); - isCertificateDateValid = false; - } catch (SelfSignedVerificationException e) { - logger.log(Level.FINEST, "Certificate chain could not be validated, signature is self singed.", e); - isSelfSigned = true; - } catch (CertificateVerificationException e) { - logger.log(Level.FINEST, "Certificate chain could not be validated. ", e); - isCertificateChainTrusted = false; - } catch (RevocationVerificationException e) { - logger.log(Level.FINEST, "Certificate chain could not be validated, certificate has been revoked.", e); - isRevocation = true; - } catch (IOException e) { - logger.log(Level.FINEST, "Error locating trusted keystore .", e); - isCertificateChainTrusted = false; - } catch (CertificateException e) { - logger.log(Level.FINEST, "Certificate exception.", e); - isCertificateChainTrusted = false; - } catch (Throwable e) { - logger.log(Level.FINEST, "Error validation certificate chain.", e); - isCertificateChainTrusted = false; - } - } - - public boolean checkByteRange() throws SignatureIntegrityException { - if (signatureFieldDictionary == null) { - return false; - } - ArrayList byteRange = signatureFieldDictionary.getSignatureDictionary().getByteRange(); - SeekableInput documentInput = signatureFieldDictionary.getLibrary().getDocumentInput(); - documentInput.beginThreadAccess(); - try { - long totalLength = documentInput.getLength(); - long digestedLength = byteRange.get(2) + byteRange.get(3); - // this doesn't mean the signature has been tampered with just that there are subsequent modification - // or signatures added after this signature. - if (digestedLength == totalLength) { - return true; - } - } catch (IOException e) { - throw new SignatureIntegrityException(e); - } finally { - documentInput.endThreadAccess(); - } - return false; - } - - /** - * Gets the certificate used to sing the document. The signature principle matches the certificates - * principle in other words. - * - * @return signer certificate. - */ - public X509Certificate getSignerCertificate() { - return signerCertificate; - } - - /** - * Gets the certificate chain associated with this signature. - * - * @return certificate chain of one or more certificates. - */ - public Collection getCertificateChain() { - return certificateChain; - } - - /** - * Date that validation process was last executed. - * - * @return Date last validation cycle was executed - */ - public Date getLastValidated() { - return lastVerified; - } - - /** - * Indicates if the singed data section specified by a signature has been modified. This indicates the document - * has been tampered with. - * - * @return true if singed data has been altered, false otherwise. - */ - public boolean isSignedDataModified() { - return isSignedDataModified; - } - - /** - * Indicates that data after the signature definition has been been modified. This is most likely do to another - * signature being added to the document or some form or page manipulation. However it is possible that - * an major update has been appended to the document. - * - * @return true if the document has been modified outside the byte range of the signature. - */ - public boolean isDocumentDataModified() { - return isDocumentDataModified; - } - - public boolean isSignaturesCoverDocumentLength() { - return isSignaturesCoverDocumentLength; - } - - public void setSignaturesCoverDocumentLength(boolean signaturesCoverDocumentLength) { - isSignaturesCoverDocumentLength = signaturesCoverDocumentLength; - } - - /** - * Indicates the certificate chain has been validated against keystore of trusted certificates. - * - * @return true if the certificate chain has been validated, false otherwise. - */ - public boolean isCertificateChainTrusted() { - return isCertificateChainTrusted; - } - - /** - * Indicates if the signing certificate or a certificate in the chain is on a revocation list. - * - * @return true if the certy have been revoked, false otherwise. - */ - public boolean isRevocation() { - return isRevocation; - } - - /** - * Indicates the signature was self singed and the certificate can not be trusted. - * - * @return true if self signed, false otherwise. - */ - public boolean isSelfSigned() { - return isSelfSigned; - } - - /** - * Indicates if a certificate data has been marked as invalid. This generally means that a certificate - * has expired. - * - * @return true if the certificate data is valid, otherwise false. - */ - public boolean isCertificateDateValid() { - return isCertificateDateValid; - } - - public boolean isEmbeddedTimeStamp() { - return isEmbeddedTimeStamp; - } - - /** - * Will always return fals, timestamps are currently not validated. - * - * @return false. - */ - public boolean isSignerTimeValid() { - return false; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/AlgorithmIdentifier.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/AlgorithmIdentifier.java deleted file mode 100644 index b6b77c6c5a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/AlgorithmIdentifier.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature; - -import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; -import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; -import org.bouncycastle.cms.CMSSignedDataGenerator; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.HashMap; - -/** - * Utility method for mapping the hard to read DigestAlgorithmIdentifier to the more descriptive layman form. - */ -public class AlgorithmIdentifier { - - private static final HashMap encryptionAlgorithms = new HashMap(); - private static final HashMap digestAlgorithms = new HashMap(); - - static { - // common encryption numbers/names used in PDF - encryptionAlgorithms.put(X9ObjectIdentifiers.id_dsa_with_sha1.getId(), "DSA"); - encryptionAlgorithms.put(X9ObjectIdentifiers.id_dsa.getId(), "DSA"); - encryptionAlgorithms.put(OIWObjectIdentifiers.dsaWithSHA1.getId(), "DSA"); - encryptionAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption.getId(), "RSA"); - encryptionAlgorithms.put(PKCSObjectIdentifiers.sha1WithRSAEncryption.getId(), "RSA"); - encryptionAlgorithms.put(TeleTrusTObjectIdentifiers.teleTrusTRSAsignatureAlgorithm.getId(), "RSA"); - encryptionAlgorithms.put(X509ObjectIdentifiers.id_ea_rsa.getId(), "RSA"); - encryptionAlgorithms.put(CMSSignedDataGenerator.ENCRYPTION_ECDSA, "ECDSA"); - encryptionAlgorithms.put(X9ObjectIdentifiers.ecdsa_with_SHA2.getId(), "ECDSA"); - encryptionAlgorithms.put(X9ObjectIdentifiers.ecdsa_with_SHA224.getId(), "ECDSA"); - encryptionAlgorithms.put(X9ObjectIdentifiers.ecdsa_with_SHA256.getId(), "ECDSA"); - encryptionAlgorithms.put(X9ObjectIdentifiers.ecdsa_with_SHA384.getId(), "ECDSA"); - encryptionAlgorithms.put(X9ObjectIdentifiers.ecdsa_with_SHA512.getId(), "ECDSA"); - encryptionAlgorithms.put(CMSSignedDataGenerator.ENCRYPTION_RSA_PSS, "RSAandMGF1"); - encryptionAlgorithms.put(CryptoProObjectIdentifiers.gostR3410_94.getId(), "GOST3410"); - encryptionAlgorithms.put(CryptoProObjectIdentifiers.gostR3410_2001.getId(), "ECGOST3410"); - encryptionAlgorithms.put("1.3.6.1.4.1.5849.1.6.2", "ECGOST3410"); - encryptionAlgorithms.put("1.3.6.1.4.1.5849.1.1.5", "GOST3410"); - encryptionAlgorithms.put("1.2.840.113549.1.1.11", "RSA"); - // common digest numbesr/names used in PDF. - digestAlgorithms.put(PKCSObjectIdentifiers.md5.getId(), "MD5"); - digestAlgorithms.put(OIWObjectIdentifiers.idSHA1.getId(), "SHA1"); - digestAlgorithms.put(NISTObjectIdentifiers.id_sha224.getId(), "SHA224"); - digestAlgorithms.put(NISTObjectIdentifiers.id_sha256.getId(), "SHA256"); - digestAlgorithms.put(NISTObjectIdentifiers.id_sha384.getId(), "SHA384"); - digestAlgorithms.put(NISTObjectIdentifiers.id_sha512.getId(), "SHA512"); - digestAlgorithms.put(PKCSObjectIdentifiers.sha1WithRSAEncryption.getId(), "SHA1"); - digestAlgorithms.put(PKCSObjectIdentifiers.sha224WithRSAEncryption.getId(), "SHA224"); - digestAlgorithms.put(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), "SHA256"); - digestAlgorithms.put(PKCSObjectIdentifiers.sha384WithRSAEncryption.getId(), "SHA384"); - digestAlgorithms.put(PKCSObjectIdentifiers.sha512WithRSAEncryption.getId(), "SHA512"); - digestAlgorithms.put(TeleTrusTObjectIdentifiers.ripemd128.getId(), "RIPEMD128"); - digestAlgorithms.put(TeleTrusTObjectIdentifiers.ripemd160.getId(), "RIPEMD160"); - digestAlgorithms.put(TeleTrusTObjectIdentifiers.ripemd256.getId(), "RIPEMD256"); - digestAlgorithms.put(CryptoProObjectIdentifiers.gostR3411.getId(), "GOST3411"); - digestAlgorithms.put("1.3.6.1.4.1.5849.1.2.1", "GOST3411"); - } - - /** - * Gets an instance of a MessageDigest for the given algorithm and provider. - * - * @param algorithm algorithm reference number as a string. - * @param provider provider, optional, can be null. - * @return message digest - * @throws NoSuchProviderException provider could not be found associated with a MD. - * @throws NoSuchAlgorithmException algorithm could not be found associated with a MD. - */ - public static MessageDigest getDigestInstance(String algorithm, String provider) - throws NoSuchProviderException, NoSuchAlgorithmException { - if (provider != null) { - try { - return MessageDigest.getInstance(algorithm, provider); - } catch (NoSuchAlgorithmException e) { - return MessageDigest.getInstance(algorithm); - } catch (NoSuchProviderException e) { - return MessageDigest.getInstance(algorithm); - } - } else { - return MessageDigest.getInstance(algorithm); - } - } - - /** - * Gets the encryption algorithm name for the specified encryption object ID. - * - * @param encryptionAlgorithmOID object id to reference. - * @return algorithm name in layman form. - */ - public static String getEncryptionAlgorithmName(String encryptionAlgorithmOID) { - String algName = encryptionAlgorithms.get(encryptionAlgorithmOID); - if (algName != null) { - return algName; - } - return encryptionAlgorithmOID; - } - - /** - * Get the digest algorithm name for the given object ID. - * - * @param digestAlgorithmOID OID of the digest. - * @return algorithm name in layman form. - */ - public static String getDigestAlgorithmName(String digestAlgorithmOID) { - String name = digestAlgorithms.get(digestAlgorithmOID); - if (name != null) { - return name; - } - return digestAlgorithmOID; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/DigitalSignatureFactory.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/DigitalSignatureFactory.java deleted file mode 100644 index c6c1c1a744..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/DigitalSignatureFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; - -/** - * DigitalSignatureFactory which takes a SignatureDictionary and returns the appropriate validator - * or signer implementation. - */ -public class DigitalSignatureFactory { - - // current list of sub filter types, suspect a stronger then sha1 will be in the spec soon. - public static final Name DSS_SUB_FILTER_PKCS7_DETACHED = new Name("adbe.pkcs7.detached"); - public static final Name DSS_SUB_FILTER_PKCS7_SHA1 = new Name("adbe.pkcs7.sha1"); - public static final Name DSS_SUB_FILTER_PKCS7__SHA1 = new Name("adbe.x509.rsa_sha1"); - // few examples with alternate ras sha1 name - public static final Name DSS_SUB_FILTER_RSA_SHA1 = new Name("adbe.x509.rsa.sha1"); - - private static DigitalSignatureFactory digitalSignatureFactory; - - private DigitalSignatureFactory() { - } - - public static DigitalSignatureFactory getInstance() { - if (digitalSignatureFactory == null) { - digitalSignatureFactory = new DigitalSignatureFactory(); - } - return digitalSignatureFactory; - } - - // TODO: implement singer stance creation, likely just go with adbe.x509.rsa.sha1 for forget about adbe.pkcs7.detached - public SignatureSigner getSignerInstance(SignatureFieldDictionary signatureFieldDictionary) { - return null; - } - - /** - * Returns an appropriate validator instance for the the specified SignatureFieldDictionary. - * The returned SignatureValidator can then be used to validate the respective signature against the - * current document. - * - * @param signatureFieldDictionary documents signature dictionary. - * @return validator for the given implementation. - * @throws SignatureIntegrityException can occur if the signature dictionary certificate and - * public key are invalid or can not be verified. - */ - public SignatureValidator getValidatorInstance(SignatureFieldDictionary signatureFieldDictionary) throws SignatureIntegrityException { - SignatureDictionary signatureDictionary = signatureFieldDictionary.getSignatureDictionary(); - // PKCS#7 detached and sha-1 digest method - if (signatureDictionary.getSubFilter().equals(DSS_SUB_FILTER_PKCS7_DETACHED) || - signatureDictionary.getSubFilter().equals(DSS_SUB_FILTER_PKCS7_SHA1)) { - return new Pkcs7Validator(signatureFieldDictionary); - } - // PKCS#1 RSA encryption and SHA-1 digest method - else if (signatureDictionary.getSubFilter().equals(DSS_SUB_FILTER_RSA_SHA1) || - signatureDictionary.getSubFilter().equals(DSS_SUB_FILTER_PKCS7__SHA1)) { - return new Pkcs1Validator(signatureFieldDictionary); - } - - return null; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/Pkcs1Validator.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/Pkcs1Validator.java deleted file mode 100644 index bb9aebd04e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/Pkcs1Validator.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.jce.provider.X509CertParser; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.util.Utils; - -import javax.crypto.Cipher; -import java.io.ByteArrayInputStream; -import java.security.cert.X509Certificate; - -/** - * "adbe.x509.rsa_sha1" - * In this case, the Contents key contains a DER-encoded PKCS#1 [11] - * binary data object representing the signature obtained as the RSA - * encryption of the byte range SHA-1 digest with the signer's - * private key. When using PKCS#1, the certificate chain of the - * signer is included with other signature information in the signed - * document. - */ -public class Pkcs1Validator extends AbstractPkcsValidator { - - public Pkcs1Validator(SignatureFieldDictionary signatureFieldDictionary) throws SignatureIntegrityException { - super(signatureFieldDictionary); - } - - public void init() throws SignatureIntegrityException { - SignatureDictionary signatureDictionary = signatureFieldDictionary.getSignatureDictionary(); - announceSignatureType(signatureDictionary); - // start the decode of the raw type. - StringObject stringObject = signatureDictionary.getContents(); - // make sure we don't loose any bytes converting the string in the raw. - byte[] cmsData = Utils.convertByteCharSequenceToByteArray(stringObject.getLiteralString()); - // get the certificate - stringObject = signatureDictionary.getCertString(); - // make sure we don't loose any bytes converting the string in the raw. - byte[] certsKey = Utils.convertByteCharSequenceToByteArray(stringObject.getLiteralString()); - - try { - X509CertParser x509CertParser = new X509CertParser(); - x509CertParser.engineInit(new ByteArrayInputStream(certsKey)); - certificateChain = x509CertParser.engineReadAll(); - signerCertificate = (X509Certificate) certificateChain.iterator().next(); - - // content data is encrypted using the cert above. - ASN1InputStream asn1InputStream = new ASN1InputStream(new ByteArrayInputStream(cmsData)); - ASN1Primitive tmp = asn1InputStream.readObject(); - messageDigest = ((ASN1OctetString) tmp).getOctets(); - - String provider = signatureDictionary.getFilter().getName(); - digestAlgorithmIdentifier = OIWObjectIdentifiers.idSHA1.getId(); - signatureAlgorithmIdentifier = PKCSObjectIdentifiers.rsaEncryption.getId(); - // basic creation and public key check which should throw any format errors. - createSignature(signerCertificate.getPublicKey(), provider, - signatureAlgorithmIdentifier, digestAlgorithmIdentifier); - - // Use RSA/ECB/NoPadding do decrypt the message digest - Cipher asymmetricCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - // initialize your cipher - asymmetricCipher.init(Cipher.DECRYPT_MODE, signerCertificate.getPublicKey()); - // assuming, cipherText is a byte array containing your encrypted message - messageDigest = asymmetricCipher.doFinal(messageDigest); - // trim the padding bytes - if (messageDigest.length > 20) { - // You can create the ASN.1 BER encoding of an MD5, SHA-1, or SHA-256 value by prepending these strings to - // the 16-byte or 20-byte hash values, respectively: - // We always assume sha1 which is: - // ref: sha1 : X'30213009 06052B0E 03021A05 000414' - // ref: SHA-256: X'3031300D 06096086 48016503 04020105 000420' - // ref: MD5: X'3020300C 06082A86 4886F70D 02050500 0410' - byte[] trunkedMD = new byte[20]; - System.arraycopy(messageDigest, 15, trunkedMD, 0, 20); - messageDigest = trunkedMD; - } - } catch (Exception e) { - throw new SignatureIntegrityException(e); - } - initialized = true; - } - - @Override - public void validate() throws SignatureIntegrityException { - validateDocument(); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/Pkcs7Validator.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/Pkcs7Validator.java deleted file mode 100644 index 5ec3b35872..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/Pkcs7Validator.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature; - -import org.bouncycastle.asn1.ASN1Sequence; -import org.icepdf.core.pobjects.HexStringObject; -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.util.Utils; - -import java.util.logging.Logger; - -/** - * Pkcs7Validator is based on the RFC3852 specification for Cryptographic Message Syntax (CMS). The - * Digital SignatureFactory is responsible for creating any SignatureValidator implementation and does so based on the - * subFilter value of the SignatureFieldDictionary. In this particular cas the validation takes place when the - * subFilter is equal to "adbe.pkcs7.detached". - *

- * Also the subfilter "adbe.pkcs7.sha1". PKCS#7 The SHA1 digest of the document's byte range shall be encapsulated in - * the PKCS#7 SignedData field with ContentInfo of type Data. The digest of that SignedData shall be incorporated as - * the normal PKCS#7 digest. - */ -public class Pkcs7Validator extends AbstractPkcsValidator { - - private static final Logger logger = - Logger.getLogger(Pkcs7Validator.class.toString()); - - public Pkcs7Validator(SignatureFieldDictionary signatureFieldDictionary) throws SignatureIntegrityException { - super(signatureFieldDictionary); - } - - public void init() throws SignatureIntegrityException { - SignatureDictionary signatureDictionary = signatureFieldDictionary.getSignatureDictionary(); - announceSignatureType(signatureDictionary); - - // get the signature bytes. - HexStringObject hexStringObject = signatureDictionary.getContents(); - // make sure we don't loose any bytes converting the string in the raw. - byte[] cmsData = Utils.convertByteCharSequenceToByteArray(hexStringObject.getLiteralString()); - - // Signed-data content type -- start of parsing - ASN1Sequence signedData = captureSignedData(cmsData); - - // parse out the singer data. - parseSignerData(signedData, cmsData); - - /** - * End of signature validation checking and data gather; - * This section should be moved to a base class and extened for the SHA1 and 7Detatched. - */ - initialized = true; - } - - public void validate() throws SignatureIntegrityException { - validateDocument(); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/SignatureSigner.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/SignatureSigner.java deleted file mode 100644 index f32030c7fc..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/SignatureSigner.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature; - -/** - * Placeholder for singer interface. - */ -public interface SignatureSigner { - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/SignatureValidator.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/SignatureValidator.java deleted file mode 100644 index bee6624ff0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/SignatureValidator.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature; - -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; - -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.Collection; -import java.util.Date; - -/** - * Interface for Digital Signature validation. Singer certificate validity can be determined from this class. - */ -public interface SignatureValidator { - - void init() throws SignatureIntegrityException; - - /** - * Checks integrity of the signature and will set the boolean property defining isSignedDataModified. - * - * @throws SignatureIntegrityException occurs if there is an issue validating the public key against the cert. - */ - void validate() throws SignatureIntegrityException; - - /** - * Indicates if the singed data section specified by a signature has been modified. This indicates the document - * has been tampered with. - * - * @return true if singed data has been altered, false otherwise. - */ - boolean isSignedDataModified(); - - /** - * Indicates that data after the signature definition has been been modified. This is most likely do to another - * signature being added to the document or some form or page manipulation. However it is possible that - * an major update has been appended to the document. - * - * @return true if the document has been modified outside the byte range of the signature. - */ - boolean isDocumentDataModified(); - - /** - * Indicates that there are no unaccounted for bytes in the file that haven't been singed. This generally indicates - * if true that the document is unmodified as the signatures cover all teh bytes in the file. - * - * @return true if signatures cover length of file. - */ - boolean isSignaturesCoverDocumentLength(); - - /** - * Sets the signaturesCoverDocumentLength param to indicate that all signatures have been check and cover - * all the bytes in the document. - * - * @param signaturesCoverDocumentLength - */ - void setSignaturesCoverDocumentLength(boolean signaturesCoverDocumentLength); - - /** - * The certificate has been verified as trusted. - * - * @return true if the certificate is trusted, otherwise false. - */ - boolean isCertificateChainTrusted(); - - /** - * Indicates if the signing certificate or a certificate in the chain is on a revocation list. - * - * @return true if the certy have been revoked, false otherwise. - */ - boolean isRevocation(); - - /** - * Indicates the signature was self singed and the certificate can not be trusted. - * - * @return true if self signed, false otherwise. - */ - boolean isSelfSigned(); - - /** - * Indicates if a certificate data has been marked as invalid. This generally means that a certificate - * has expired. - * - * @return true if the certificate data is valid, otherwise false. - */ - boolean isCertificateDateValid(); - - /** - * The singer time stamp is valid. - * - * @return true if the signer time is valid. - */ - boolean isSignerTimeValid(); - - /** - * Validation time is valid. - * - * @return true if the validation time is valid. - */ - boolean isEmbeddedTimeStamp(); - - /** - * Gets the signers certificate. - * - * @return signers certificate. - */ - X509Certificate getSignerCertificate(); - - boolean checkByteRange() throws SignatureIntegrityException; - - /** - * CertificateChain. - * - * @return certificate chain. - */ - Collection getCertificateChain(); - - /** - * Gets the last time the signature was validation cycle was completed. - * - * @return date that validation last completed. - */ - Date getLastValidated(); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/certificates/CRLVerifier.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/certificates/CRLVerifier.java deleted file mode 100644 index 501bbe5c16..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/certificates/CRLVerifier.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature.certificates; - -import org.bouncycastle.asn1.ASN1InputStream; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.x509.*; -import org.bouncycastle.asn1.x509.Extension; -import org.icepdf.core.pobjects.acroform.signature.exceptions.CertificateVerificationException; -import org.icepdf.core.pobjects.acroform.signature.exceptions.RevocationVerificationException; - -import javax.naming.Context; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.InitialDirContext; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.security.cert.*; -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.List; - -/** - * Class that verifies CRLs for given X509 certificate. Extracts the CRL - * distribution points from the certificate (if available) and checks the - * certificate revocation status against the CRLs coming from the - * distribution points. Supports HTTP, HTTPS, FTP and LDAP based URLs. - * - * @author Svetlin Nakov - */ -public class CRLVerifier { - - /** - * Extracts the CRL distribution points from the certificate (if available) - * and checks the certificate revocation status against the CRLs coming from - * the distribution points. Supports HTTP, HTTPS, FTP and LDAP based URLs. - * - * @param cert the certificate to be checked for revocation - * @throws CertificateVerificationException if the certificate is revoked - */ - public static void verifyCertificateCRLs(X509Certificate cert) - throws CertificateVerificationException, RevocationVerificationException { - try { - List crlDistPoints = getCrlDistributionPoints(cert); - for (String crlDP : crlDistPoints) { - X509CRL crl = downloadCRL(crlDP); - if (crl.isRevoked(cert)) { - throw new RevocationVerificationException( - "The certificate is revoked by CRL: " + crlDP); - } - } - } catch (Exception ex) { - if (ex instanceof CertificateVerificationException) { - throw (CertificateVerificationException) ex; - } else { - throw new CertificateVerificationException( - "Can not verify CRL for certificate: " + - cert.getSubjectX500Principal()); - } - } - } - - /** - * Downloads CRL from given URL. Supports http, https, ftp and ldap based URLs. - */ - private static X509CRL downloadCRL(String crlURL) throws IOException, - CertificateException, CRLException, - CertificateVerificationException, NamingException { - if (crlURL.startsWith("http://") || crlURL.startsWith("https://") - || crlURL.startsWith("ftp://")) { - return downloadCRLFromWeb(crlURL); - } else if (crlURL.startsWith("ldap://")) { - return downloadCRLFromLDAP(crlURL); - } else { - throw new CertificateVerificationException( - "Can not download CRL from certificate " + - "distribution point: " + crlURL); - } - } - - /** - * Downloads a CRL from given LDAP url, e.g. - * ldap://ldap.infonotary.com/dc=identity-ca,dc=infonotary,dc=com - */ - private static X509CRL downloadCRLFromLDAP(String ldapURL) - throws CertificateException, NamingException, CRLException, - CertificateVerificationException { - Hashtable env = new Hashtable(); - env.put(Context.INITIAL_CONTEXT_FACTORY, - "com.sun.jndi.ldap.LdapCtxFactory"); - env.put(Context.PROVIDER_URL, ldapURL); - - DirContext ctx = new InitialDirContext(env); - Attributes avals = ctx.getAttributes(""); - Attribute aval = avals.get("certificateRevocationList;binary"); - byte[] val = (byte[]) aval.get(); - if ((val == null) || (val.length == 0)) { - throw new CertificateVerificationException( - "Can not download CRL from: " + ldapURL); - } else { - InputStream inStream = new ByteArrayInputStream(val); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - return (X509CRL) cf.generateCRL(inStream); - } - } - - /** - * Downloads a CRL from given HTTP/HTTPS/FTP URL, e.g. - * http://crl.infonotary.com/crl/identity-ca.crl - */ - private static X509CRL downloadCRLFromWeb(String crlURL) - throws IOException, CertificateException, - CRLException { - URL url = new URL(crlURL); - InputStream crlStream = url.openStream(); - try { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - return (X509CRL) cf.generateCRL(crlStream); - } finally { - crlStream.close(); - } - } - - /** - * Extracts all CRL distribution point URLs from the "CRL Distribution Point" - * extension in a X.509 certificate. If CRL distribution point extension is - * unavailable, returns an empty list. - */ - public static List getCrlDistributionPoints( - X509Certificate cert) throws CertificateParsingException, IOException { - byte[] crldpExt = cert.getExtensionValue(Extension.cRLDistributionPoints.getId()); - if (crldpExt == null) { - return new ArrayList(); - } - ASN1InputStream oAsnInStream = new ASN1InputStream( - new ByteArrayInputStream(crldpExt)); - ASN1Primitive derObjCrlDP = oAsnInStream.readObject(); - DEROctetString dosCrlDP = (DEROctetString) derObjCrlDP; - byte[] crldpExtOctets = dosCrlDP.getOctets(); - ASN1InputStream oAsnInStream2 = new ASN1InputStream( - new ByteArrayInputStream(crldpExtOctets)); - ASN1Primitive derObj2 = oAsnInStream2.readObject(); - CRLDistPoint distPoint = CRLDistPoint.getInstance(derObj2); - List crlUrls = new ArrayList(); - for (DistributionPoint dp : distPoint.getDistributionPoints()) { - DistributionPointName dpn = dp.getDistributionPoint(); - // Look for URIs in fullName - if (dpn != null) { - if (dpn.getType() == DistributionPointName.FULL_NAME) { - GeneralName[] genNames = GeneralNames.getInstance( - dpn.getName()).getNames(); - // Look for an URI - for (GeneralName genName : genNames) { - if (genName.getTagNo() == GeneralName.uniformResourceIdentifier) { - String url = DERIA5String.getInstance( - genName.getName()).getString(); - crlUrls.add(url); - } - } - } - } - } - return crlUrls; - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/certificates/CertificateVerifier.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/certificates/CertificateVerifier.java deleted file mode 100644 index eebc5274ef..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/certificates/CertificateVerifier.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature.certificates; - -import org.bouncycastle.jce.exception.ExtCertPathValidatorException; -import org.icepdf.core.pobjects.acroform.signature.exceptions.CertificateVerificationException; -import org.icepdf.core.pobjects.acroform.signature.exceptions.RevocationVerificationException; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SelfSignedVerificationException; - -import java.security.*; -import java.security.cert.*; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -/** - * Class for building a certification chain for given certificate and verifying - * it. Relies on a set of root CA certificates and intermediate certificates - * that will be used for building the certification chain. The verification - * process assumes that all self-signed certificates in the set are trusted - * root CA certificates and all other certificates in the set are intermediate - * certificates. - * - * @author Svetlin Nakov - */ -public class CertificateVerifier { - - /** - * Attempts to build a certification chain for given certificate and to verify - * it. Relies on a set of root CA certificates and intermediate certificates - * that will be used for building the certification chain. The verification - * process assumes that all self-signed certificates in the set are trusted - * root CA certificates and all other certificates in the set are intermediate - * certificates. - * - * @param cert - certificate for validation - * @param additionalCerts - set of trusted root CA certificates that will be - * used as "trust anchors" and intermediate CA certificates that will be - * used as part of the certification chain. All self-signed certificates - * are considered to be trusted root CA certificates. All the rest are - * considered to be intermediate CA certificates. - * @return the certification chain (if verification is successful) - * @throws CertificateVerificationException - if the certification is not - * successful (e.g. certification path cannot be built or some - * certificate in the chain is expired or CRL checks are failed) - */ - public static PKIXCertPathBuilderResult verifyCertificate(X509Certificate cert, - Collection additionalCerts) - throws CertificateVerificationException, CertificateExpiredException, SelfSignedVerificationException, - RevocationVerificationException { - try { - // Check for self-signed certificate - if (isSelfSigned(cert)) { - throw new SelfSignedVerificationException("The certificate is self-signed."); - } - - // Prepare a set of trusted root CA certificates - // and a set of intermediate certificates - Set trustedRootCerts = new HashSet(); - Set intermediateCerts = new HashSet(); - for (X509Certificate additionalCert : additionalCerts) { - if (isSelfSigned(additionalCert)) { - trustedRootCerts.add(additionalCert); - } else { - intermediateCerts.add(additionalCert); - } - } - - // Attempt to build the certification chain and verify it - PKIXCertPathBuilderResult verifiedCertChain = - verifyCertificate(cert, trustedRootCerts, intermediateCerts); - - // Check whether the certificate is revoked by the CRL - // given in its CRL distribution point extension - CRLVerifier.verifyCertificateCRLs(cert); - - // The chain is built and verified. Return it as a result - return verifiedCertChain; - } catch (CertPathBuilderException certPathEx) { - if (certPathEx.getCause() instanceof ExtCertPathValidatorException) { - if (certPathEx.getCause().getCause() instanceof CertificateExpiredException) { - throw (CertificateExpiredException) certPathEx.getCause().getCause(); - } - } - throw new CertificateVerificationException( - "Error building certification path: " + cert.getSubjectX500Principal(), certPathEx); - } catch (CertificateVerificationException cvex) { - throw cvex; - } catch (RevocationVerificationException e) { - throw e; - } catch (Exception ex) { - throw new CertificateVerificationException( - "Error verifying the certificate: " + cert.getSubjectX500Principal(), ex); - } - } - - /** - * Checks whether given X.509 certificate is self-signed. - */ - public static boolean isSelfSigned(X509Certificate cert) - throws CertificateException, NoSuchAlgorithmException, - NoSuchProviderException { - try { - // Try to verify certificate signature with its own public key - PublicKey key = cert.getPublicKey(); - cert.verify(key); - return true; - } catch (SignatureException sigEx) { - // Invalid signature, not self-signed - return false; - } catch (InvalidKeyException keyEx) { - // Invalid key, not self-signed - return false; - } - } - - /** - * Attempts to build a certification chain for given certificate and to verify - * it. Relies on a set of root CA certificates (trust anchors) and a set of - * intermediate certificates (to be used as part of the chain). - * - * @param cert - certificate for validation - * @param trustedRootCerts - set of trusted root CA certificates - * @param intermediateCerts - set of intermediate certificates - * @return the certification chain (if verification is successful) - * @throws GeneralSecurityException - if the verification is not successful - * (e.g. certification path cannot be built or some certificate in the - * chain is expired) - */ - private static PKIXCertPathBuilderResult verifyCertificate(X509Certificate cert, Set trustedRootCerts, - Set intermediateCerts) - throws GeneralSecurityException { - - // Create the selector that specifies the starting certificate - X509CertSelector selector = new X509CertSelector(); - selector.setCertificate(cert); - - // Create the trust anchors (set of root CA certificates) - Set trustAnchors = new HashSet(); - for (X509Certificate trustedRootCert : trustedRootCerts) { - trustAnchors.add(new TrustAnchor(trustedRootCert, null)); - } - - // Configure the PKIX certificate builder algorithm parameters - PKIXBuilderParameters pkixParams = - new PKIXBuilderParameters(trustAnchors, selector); - - // Disable CRL checks (this is done manually as additional step) - pkixParams.setRevocationEnabled(false); - - // Specify a list of intermediate certificates - CertStore intermediateCertStore = CertStore.getInstance("Collection", - new CollectionCertStoreParameters(intermediateCerts), "BC"); - pkixParams.addCertStore(intermediateCertStore); - - // Build and verify the certification chain - CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC"); - return (PKIXCertPathBuilderResult) builder.build(pkixParams); - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/CertificateVerificationException.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/CertificateVerificationException.java deleted file mode 100644 index 13aed5510e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/CertificateVerificationException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature.exceptions; - -/** - * This class wraps an exception that could be thrown during - * the certificate verification process. - * - * @author Svetlin Nakov - */ -public class CertificateVerificationException extends Exception { - - public CertificateVerificationException(String message, Throwable cause) { - super(message, cause); - } - - public CertificateVerificationException(String message) { - super(message); - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/RevocationVerificationException.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/RevocationVerificationException.java deleted file mode 100644 index c20a978ac7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/RevocationVerificationException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core. - pobjects.acroform.signature.exceptions; - -/** - * RevocationVerificationException is thrown if the certificate was found to be on a revocation list. - */ -public class RevocationVerificationException extends Exception { - - public RevocationVerificationException(String message, Throwable cause) { - super(message, cause); - } - - public RevocationVerificationException(String message) { - super(message); - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/SelfSignedVerificationException.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/SelfSignedVerificationException.java deleted file mode 100644 index 7fdc72cb3d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/SelfSignedVerificationException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature.exceptions; - -/** - * SelfSignedVerificationException is thrown if the certificate was self signed. - */ -public class SelfSignedVerificationException extends Exception { - - public SelfSignedVerificationException(String message, Throwable cause) { - super(message, cause); - } - - public SelfSignedVerificationException(String message) { - super(message); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/SignatureIntegrityException.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/SignatureIntegrityException.java deleted file mode 100644 index 00e3d3913e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/acroform/signature/exceptions/SignatureIntegrityException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.acroform.signature.exceptions; - -/** - * Basic Parsing of the signature dictionary could not take place. - */ -public class SignatureIntegrityException extends Exception { - - public SignatureIntegrityException(String message) { - super(message); - } - - public SignatureIntegrityException(Throwable cause) { - super(cause); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/Action.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/Action.java deleted file mode 100644 index 8693adcb39..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/Action.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - - -/** - *

The Action class represents an Action Dictionary which defines - * characteristics and behavior of an action. A PDF action can be a wide - * variety of standard action types. This class is designed to help users - * get needed attributes from the Action Dictionary. The Dictionary classes - * getEntries method can be used to find other attributes associated with this action.

- *

- *

ICEpdf currently only uses the "GoTo" action when working with document - * outlines. If your application is interpreting a page's Annotations then you - * can query the Annotation object to get its Action.

- * - * @since 1.0 - */ -public class Action extends Dictionary { - - public static final Name ACTION_TYPE = new Name("Action"); - - public static final Name ACTION_TYPE_KEY = new Name("S"); - - public static final Name NEXT_KEY = new Name("Next"); - - public static final Name ACTION_TYPE_GOTO = new Name("GoTo"); - - public static final Name ACTION_TYPE_GOTO_REMOTE = new Name("GoToR"); - - public static final Name ACTION_TYPE_LAUNCH = new Name("Launch"); - - public static final Name ACTION_TYPE_URI = new Name("URI"); - - public static final Name ACTION_TYPE_RESET_SUBMIT = new Name("ResetForm"); - - public static final Name ACTION_TYPE_SUBMIT_SUBMIT = new Name("SubmitForm"); - - public static final Name ACTION_TYPE_NAMED = new Name("Named"); - - public static final Name ACTION_TYPE_JAVA_SCRIPT = new Name("JavaScript"); - - // type of annotation - private String type; - - // todo implement next - // private Object Next - - /** - * Creates a new instance of a Action. - * - * @param l document library. - * @param h Action dictionary entries. - */ - public Action(Library l, HashMap h) { - super(l, h); - type = getObject(ACTION_TYPE_KEY).toString(); - } - - public static Action buildAction(Library library, HashMap hashMap) { - Name actionType = (Name) hashMap.get(Action.ACTION_TYPE_KEY); - if (actionType != null) { - if (actionType.equals(Action.ACTION_TYPE_GOTO)) { - return new GoToAction(library, hashMap); - } else if (actionType.equals(Action.ACTION_TYPE_GOTO_REMOTE)) { - return new GoToRAction(library, hashMap); - } else if (actionType.equals(Action.ACTION_TYPE_LAUNCH)) { - return new LaunchAction(library, hashMap); - } else if (actionType.equals(Action.ACTION_TYPE_URI)) { - return new URIAction(library, hashMap); - } else if (actionType.equals(Action.ACTION_TYPE_RESET_SUBMIT)) { - return new ResetFormAction(library, hashMap); - } else if (actionType.equals(Action.ACTION_TYPE_SUBMIT_SUBMIT)) { - return new SubmitFormAction(library, hashMap); - } else if (actionType.equals(Action.ACTION_TYPE_NAMED)) { - return new NamedAction(library, hashMap); - } else if (actionType.equals(Action.ACTION_TYPE_JAVA_SCRIPT)) { - return new JavaScriptAction(library, hashMap); - } - } - return new Action(library, hashMap); - } - - /** - *

Gets the type of action that this dictionary describes. The most - * common actions can be found in the PDF Reference 1.6 in section - * 8.5.3. ICEpdf currently only takes advantage of the "GoTo" action - * when a user clicks on a document outline.

- * - * @return The action type. - */ - public String getType() { - return type; - } - - public boolean similar(Action obj) { - // check if object references can be compared - if (this.getPObjectReference() != null && - obj.getPObjectReference() != null) { - return getPObjectReference().equals(obj.getPObjectReference()); - } else { - // compare type - return getType().equals(obj.getType()); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/ActionFactory.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/ActionFactory.java deleted file mode 100644 index 50b67096d9..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/ActionFactory.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * Factory for build actions - * - * @since 4.0 - */ -public class ActionFactory { - - public static final int GOTO_ACTION = 1; - public static final int URI_ACTION = 2; - public static final int LAUNCH_ACTION = 3; - - private ActionFactory() { - } - - /** - * Creates a new ACTION object of the type specified by the type constant. - * Currently there are only two supporte action types; GoTo, Launch and URI. - *

- * This call adds the new action object to the document library as well - * as the document StateManager. - * - * @param library library to register action with - * @param type type of action to create - * @return new action object of the specified type. - */ - public static Action buildAction(Library library, - int type) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - if (GOTO_ACTION == type) { - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Action.ACTION_TYPE); - entries.put(Action.ACTION_TYPE_KEY, Action.ACTION_TYPE_GOTO); - // add a null destination entry - entries.put(GoToAction.DESTINATION_KEY, new Destination(library, null)); - GoToAction action = new GoToAction(library, entries); - action.setPObjectReference(stateManager.getNewReferencNumber()); - return action; - } else if (URI_ACTION == type) { - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Action.ACTION_TYPE); - entries.put(Action.ACTION_TYPE_KEY, Action.ACTION_TYPE_URI); - // add a null uri string entry - Reference pObjectReference = stateManager.getNewReferencNumber(); - entries.put(URIAction.URI_KEY, new LiteralStringObject("", pObjectReference, library.getSecurityManager())); - URIAction action = new URIAction(library, entries); - action.setPObjectReference(stateManager.getNewReferencNumber()); - return action; - } else if (LAUNCH_ACTION == type) { - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Action.ACTION_TYPE); - entries.put(Action.ACTION_TYPE_KEY, Action.ACTION_TYPE_LAUNCH); - // add a null file string entry - Reference pObjectReference = stateManager.getNewReferencNumber(); - entries.put(LaunchAction.FILE_KEY, new LiteralStringObject("", pObjectReference, library.getSecurityManager())); - LaunchAction action = new LaunchAction(library, entries); - action.setPObjectReference(stateManager.getNewReferencNumber()); - return action; - } - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/FormAction.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/FormAction.java deleted file mode 100644 index 79388752c7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/FormAction.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * Execute interface for Form actions. - * - * @since 5.1 - */ -public abstract class FormAction extends Action { - - /** - * (Required) A URL file specification (see 7.11.5, "URL Specifications") giving the uniform resource locator - * (URL) of the script at the Web server that will process the submission. - */ - public static final Name F_KEY = new Name("F"); - - /** - * An array identifying which fields to reset or which to exclude from - * resetting, depending on the setting of the Include/Exclude flag in the - * Flags entry (see Table 239). Each element of the array shall be either - * an indirect reference to a field dictionary or (PDF 1.3) a text string - * representing the fully qualified name of a field. Elements of both kinds - * may be mixed in the same array. - *

- * If this entry is omitted, the Include/Exclude flag shall be ignored, and all - * fields in the document’s interactive form shall be submitted except those whose - * NoExport flag (see Table 221) is set. Fields with no values may also be excluded, - * as dictated by the value of the IncludeNoValueFields flag; see Table 237. - */ - public static final Name FIELDS_KEY = new Name("Fields"); - - /** - * (Optional; inheritable) A set of flags specifying various characteristics - * of the action (see Table 239). Default value: 0. - */ - public static final Name FLAGS_KEY = new Name("Flags"); - - public FormAction(Library l, HashMap h) { - super(l, h); - } - - /** - * (Optional; inheritable) A set of flags specifying various characteristics of the action (see Table 239). - * Default value: 0. - * - * @return flag value - */ - public int getFlags() { - // behaviour flags - return library.getInt(entries, FLAGS_KEY); - } - - /** - * Execute the form action and return the appropriate return code; - * - * @return determined by the implementation. - */ - public abstract int executeFormAction(int x, int y); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/GoToAction.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/GoToAction.java deleted file mode 100644 index 68884e069d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/GoToAction.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.Destination; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * The class GoToAction represents the Action type "GoTo". It's - * purpose when called to to navigate the a destination in the document - * specified by this action. - * - * @author ICEsoft Technologies, Inc. - * @since 2.6 - */ -public class GoToAction extends Action { - - public static final Name DESTINATION_KEY = new Name("D"); - - // Destination to jump to, name, sting or array. - private Destination destination; - - /** - * Creates a new instance of a GoTo Action. - * - * @param l document library. - * @param h Action dictionary entries. - */ - public GoToAction(Library l, HashMap h) { - super(l, h); - // get the Destination for this action - destination = new Destination(library, getObject(DESTINATION_KEY)); - } - - /** - * Set the destination and adds the new data to the action's dictionary - * - * @param destination new destionat, replace old values. - */ - public void setDestination(Destination destination) { - entries.put(DESTINATION_KEY, destination.getObject()); - this.destination = destination; - } - - /** - * Gets the Destination object which the "GoTo" action should jump to. - * - * @return Destination object specified in the action. - */ - public Destination getDestination() { - return destination; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/GoToRAction.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/GoToRAction.java deleted file mode 100644 index 01ad70059c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/GoToRAction.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.Destination; -import org.icepdf.core.pobjects.FileSpecification; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - *

A remote go-to action is similar to an ordinary go-to action but jumps to - * a destination in another PDF file instead of the current file.

- * - * @author ICEsoft Technologies, Inc. - * @since 2.6 - */ -public class GoToRAction extends Action { - - public static final Name F_KEY = new Name("F"); - public static final Name NEW_WINDOW_KEY = new Name("NewWindow"); - - // path to external file, see section 3.10.1 for more details on - // resolving paths - private String externalFile; - private FileSpecification fileSpecification; - - // location in document that should be loaded. - private Destination externalDestination; - - // new window? - private Boolean isNewWindow; - - /** - * Creates a new instance of a Action. - * - * @param l document library. - * @param h Action dictionary entries. - */ - public GoToRAction(Library l, HashMap h) { - super(l, h); - - externalDestination = - new Destination(library, library.getObject(entries, Destination.D_KEY)); - Object tmp = library.getObject(entries, F_KEY); - if (tmp instanceof HashMap) { - fileSpecification = - new FileSpecification(library, (HashMap) tmp); - } else if (tmp instanceof StringObject) { - externalFile = - ((StringObject) tmp) - .getDecryptedLiteralString( - library.getSecurityManager()); - } - - isNewWindow = library.getBoolean(entries, NEW_WINDOW_KEY); - - } - - /** - * Gets the destination associated with the external file path. - * - * @return destination object if any to be resolved. - */ - public Destination getDestination() { - return externalDestination; - } - - /** - * Gets the external file path - * - * @return file path of document to be opened. - */ - public String getFile() { - return externalFile; - } - - /** - * Gets the file specification of the destination file. This objects should - * be interigated to deside what should be done - * - * @return file specification, maybe nukll if external file was specified. - */ - public FileSpecification getFileSpecification() { - return fileSpecification; - } - - /** - * Indicates if the external document should be loaded in a new window or if - * it should be loaded in the current. - * - * @return true indicates a new windows should be launched for the remote - * document; otherwise, false. - */ - public Boolean isNewWindow() { - return isNewWindow; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/JavaScriptAction.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/JavaScriptAction.java deleted file mode 100644 index 7ec55e1364..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/JavaScriptAction.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.util.HashMap; - -/** - * Upon invocation of a JavaScript action, a conforming processor shall execute a script that is written in the - * JavaScript programming language. Depending on the nature of the script, various interactive form fields in the - * document may update their values or change their visual appearances. Mozilla Development Center's Client-Side - * JavaScript Reference and the Adobe JavaScript for Acrobat API Reference (see the Bibliography) give details on - * the contents and effects of JavaScript scripts. Table 217 shows the action dictionary entries specific to this - * type of action. - * - * @since 5.2 - */ -public class JavaScriptAction extends Action{ - - public static final Name JS_KEY = new Name("JS"); - - private String javaScript; - - public JavaScriptAction(Library l, HashMap h) { - super(l, h); - Object value = library.getObject(entries, JS_KEY); - if (value instanceof StringObject) { - StringObject text = (StringObject) value; - javaScript = Utils.convertStringObject(library, text); - }else if (value instanceof Stream){ - Stream jsStream = (Stream)value; - javaScript = new String(jsStream.getDecodedStreamBytes()); - } - } - - public String getJavaScript(){ - return javaScript; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/LaunchAction.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/LaunchAction.java deleted file mode 100644 index b09253ff7b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/LaunchAction.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.FileSpecification; -import org.icepdf.core.pobjects.LiteralStringObject; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - *

The launch action launches an applicaiton or opens or prints a - * document.

- *

- *

There are optional Win which allow for platform specific parameters for - * launching the designated application.

- * - * @author ICEsoft Technologies, Inc. - * @since 2.6 - */ -public class LaunchAction extends Action { - - // file specification or file name. - public static final Name FILE_KEY = new Name("F"); - // windows specific files properties. - public static final Name WIN_KEY = new Name("Win"); - // mac specific file properties. - public static final Name MAC_KEY = new Name("Mac"); - // unix specific file properties. - public static final Name UNIX_KEY = new Name("Unix"); - // if false the destination document replaces the current. - public static final Name NEW_WINDOW_KEY = new Name("NewWindow"); - - // path to external file, see section 3.10.1 for more details on - // resolving paths - private String externalFile; - private FileSpecification fileSpecification; - - // new window? - private Boolean isNewWindow; - - // launch parameters specific to Windows. - private WindowsLaunchParameters winLaunchParameters; - - // mac and unix are not defined by the specification and thus not here - // either. - - /** - * Creates a new instance of a Action. - * - * @param l document library. - * @param h Action dictionary entries. - */ - public LaunchAction(Library l, HashMap h) { - super(l, h); - winLaunchParameters = new WindowsLaunchParameters(); - } - - /** - * Gets the applicaiton to be launched or the document to be opened or - * printed. This value can either come from the F key entry of the - * launch action or the F key of the file specification. - * - * @return file specification - */ - public String getExternalFile() { - Object value = getObject(FILE_KEY); - if (value instanceof StringObject) { - externalFile = ((StringObject) value).getDecryptedLiteralString( - library.getSecurityManager()); - } else if (getFileSpecification() != null) { - externalFile = getFileSpecification().getFileSpecification(); - } - return externalFile; - } - - /** - * Sets the external file flag of the action. At this time it is not - * possible to set a FileSpecification object but could be added at a later - * date if deamed necessary. - * - * @param externalFile external file path and or name to be associated - * with this launch action. - */ - public void setExternalFile(String externalFile) { - StringObject tmp = new LiteralStringObject( - externalFile, getPObjectReference(), library.getSecurityManager()); - entries.put(FILE_KEY, tmp); - this.externalFile = externalFile; - } - - /** - * Specifies whether or not a new window should be opend. - * - * @return true indicates a new window should be used, false otherwise. - */ - public boolean getNewWindow() { - Object value = getObject(NEW_WINDOW_KEY); - if (value instanceof Boolean) { - isNewWindow = (Boolean) value; - } - return isNewWindow; - } - - /** - * Gets an object which hold the windows-specific launch parameters. - * - * @return window specific launch parameters. - */ - public WindowsLaunchParameters getWinLaunchParameters() { - return winLaunchParameters; - } - - /** - * Gets the file specification of the destination file. This objects should - * be interigated to deside what should be done - * - * @return file specification, maybe nukll if external file was specified. - */ - public FileSpecification getFileSpecification() { - Object value = getObject(FILE_KEY); - if (value instanceof HashMap) { - fileSpecification = new FileSpecification(library, (HashMap) value); - } - return fileSpecification; - } - - /** - *

Paramaters specific to launching files on windows. These parameters - * specify what application should load the file as well what any special - * load commands.

- * - * @since 2.6 - */ - public class WindowsLaunchParameters { - - private final Name FILE_KEY = new Name("F"); - private final Name DIRECTORY_KEY = new Name("D"); - private final Name OPEN_KEY = new Name("O"); - private final Name PARAMETER_KEY = new Name("P"); - - private FileSpecification launchFileSpecification; - - private String launchFile; - - // default directory in standard dos syntax - private String defaultDirectory; - - // open or print - private String operation; - - // launch parameters - private String parameters; - - /** - * Creates a new instance of a Action. - */ - public WindowsLaunchParameters() { - -// HashMap winLaunch = library.getDictionary(entries, "Win"); - Object value = getObject(FILE_KEY); - if (value instanceof HashMap) { - launchFileSpecification = new FileSpecification(library, - (HashMap) value); - } else if (value instanceof StringObject) { - launchFile = ((StringObject) value).getDecryptedLiteralString( - library.getSecurityManager()); - } - value = getObject(DIRECTORY_KEY); - if (value instanceof StringObject) { - defaultDirectory = ((StringObject) value) - .getDecryptedLiteralString(library.getSecurityManager()); - } - value = getObject(OPEN_KEY); - if (value instanceof StringObject) { - operation = ((StringObject) value) - .getDecryptedLiteralString(library.getSecurityManager()); - } - value = getObject(PARAMETER_KEY); - if (value instanceof StringObject) { - parameters = - ((StringObject) value) - .getDecryptedLiteralString(library.getSecurityManager()); - } - } - - /** - * Gets the file name of the application to be launched or the document - * to be opened or printed, in standard Windows pathname format. - * - * @return fiel or application to launch - */ - public String getLaunchFile() { - return launchFile; - } - - /** - * Gets a string specifying the default directory in standard DOS - * syntax(Optional). - * - * @return default directory. - */ - public String getDefaultDirectory() { - return defaultDirectory; - } - - /** - * Indicates the operation to perform (Optional). - * - * @return opertation to perform, either "open" or "print". - */ - public String getOperation() { - return operation; - } - - /** - * Gets a parameter string to be passed to the application designated by - * the fileName entry.(Optional). - * - * @return paramater string associated with this action - */ - public String getParameters() { - return parameters; - } - - /** - * Gets the file specification of the destination file. This objects should - * be interigated to deside what should be done - * - * @return file specification, maybe nukll if external file was specified. - */ - public FileSpecification getLaunchFileSpecification() { - return launchFileSpecification; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/NamedAction.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/NamedAction.java deleted file mode 100644 index e099a1b63a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/NamedAction.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * Named actions that the conformign reader shall support. Names can be but not limited too. - *
    - *
  • NextPage
  • - *
  • PrevPage
  • - *
  • FirstPage
  • - *
  • LastPage
  • - *
  • Print
  • - *
- * - * @since 5.2 - */ -public class NamedAction extends Action { - - /** - * Go to the next page of the document. - */ - public static final Name NEXT_PAGE_KEY = new Name("NextPage"); - - /** - * Go to the previous page of the document. - */ - public static final Name PREV_PAGE_KEY = new Name("PrevPage"); - - /** - * Go to the first page of the document. - */ - public static final Name FIRST_PAGE_KEY = new Name("FirstPage"); - - /** - * Print the document - */ - public static final Name LAST_PAGE_KEY = new Name("LastPage"); - - /** - * Print the current document - */ - public static final Name PRINT_KEY = new Name("Print"); - - /** - * Save document as command - */ - public static final Name SAVE_AS_KEY = new Name("SaveAs"); - - - public static final Name N_KEY = new Name("N"); - - private Name name; - - public NamedAction(Library library, HashMap entries) { - super(library, entries); - - Object tmp = library.getObject(entries, N_KEY); - if (tmp != null && tmp instanceof Name) { - name = (Name) tmp; - } - } - - public Name getNamedAction(){ - return name; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/ResetFormAction.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/ResetFormAction.java deleted file mode 100644 index 074a3ba2d1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/ResetFormAction.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.pobjects.acroform.InteractiveForm; -import org.icepdf.core.pobjects.annotations.AbstractWidgetAnnotation; -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; - -/** - * Upon invocation of a reset-form action, a conforming processor shall reset - * selected interactive form fields to their default values; that is, it shall - * set the value of the V entry in the field dictionary to that of the DV entry. - * If no default value is defined for a field, its V entry shall be removed. - * For fields that can have no value (such as pushButtons), the action has no - * effect. Table 238 shows the action dictionary entries specific to this type - * of action. - *

- * The value of the action dictionary’s Flags entry is a non-negative containing - * - * flags specifying various characteristics of the action. Bit positions within - * the flag word shall be numbered starting from 1 (low-order). Only one flag is - * defined for this type of action. All undefined flag bits shall be reserved - * and shall be set to 0. - * - * @since 5.1 - */ -public class ResetFormAction extends FormAction { - - /** - * If clear, the Fields array specifies which fields to reset. - * (All descendants of the specified fields in the field hierarchy are - * reset as well.) If set, the Fields array indicates which fields to - * exclude from resetting; that is, all fields in the document’s interactive - * form shall be reset except those listed in the Fields array. - */ - public int INCLUDE_EXCLUDE_BIT = 0X0000001; - - public ResetFormAction(Library l, HashMap h) { - super(l, h); - } - - /** - * Upon invocation of a reset-form action, a conforming processor shall reset - * selected interactive form fields to their default values; that is, it shall - * set the value of the V entry in the field dictionary to that of the DV entry. - * If no default value is defined for a field, its V entry shall be removed. - * For fields that can have no value (such as pushButtons), the action has no - * effect. Table 238 shows the action dictionary entries specific to this type - * of action. - * - * @param x x-coordinate of the mouse event that actuated the submit. - * @param y y-coordinate of the mouse event that actuated the submit. - * @return value of one if reset was successful, zero if not. - */ - public int executeFormAction(int x, int y) { - // get a reference to the form data - InteractiveForm interactiveForm = library.getCatalog().getInteractiveForm(); - ArrayList fields = interactiveForm.getFields(); - for (Object tmp : fields) { - descendFormTree(tmp); - } - // update the annotation an component values. - return 0; - } - - /** - * Recursively reset all the form fields. - * - * @param formNode root form node. - */ - protected void descendFormTree(Object formNode) { - if (formNode instanceof AbstractWidgetAnnotation) { - ((AbstractWidgetAnnotation) formNode).reset(); - } else if (formNode instanceof FieldDictionary) { - // iterate over the kid's array. - FieldDictionary child = (FieldDictionary) formNode; - formNode = child.getKids(); - if (formNode != null) { - ArrayList kidsArray = (ArrayList) formNode; - for (Object kid : kidsArray) { - if (kid instanceof Reference) { - kid = library.getObject((Reference) kid); - } - if (kid instanceof AbstractWidgetAnnotation) { - ((AbstractWidgetAnnotation) kid).reset(); - } else if (kid instanceof FieldDictionary) { - descendFormTree(kid); - } - } - } - - } - } - - /** - * @see #INCLUDE_EXCLUDE_BIT - */ - public boolean isIncludeExclude() { - return (getFlags() & INCLUDE_EXCLUDE_BIT) == INCLUDE_EXCLUDE_BIT; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/SubmitFormAction.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/SubmitFormAction.java deleted file mode 100644 index 0e8ca1a08b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/SubmitFormAction.java +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.FileSpecification; -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.pobjects.acroform.InteractiveForm; -import org.icepdf.core.pobjects.annotations.AbstractWidgetAnnotation; -import org.icepdf.core.util.Library; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Upon invocation of a submit-form action, a conforming processor shall transmit the names and values of selected - * interactive form fields to a specified uniform resource locator (URL). - *

- * The main function of this class is to interpret the F value against the submit bit flags and submit the form - * data and other data as needed. - *

- * Note: Some flagss are not yet supported, see flag _BIT constants for more information on support flags. - * - * @since 5.1 - */ -public class SubmitFormAction extends FormAction { - - private static final Logger logger = - Logger.getLogger(SubmitFormAction.class.toString()); - - private static final String USER_AGENT = "Mozilla/5.0"; - - // Table 236 flags, Additional entries specific to a submit-form action. - - /** - * If clear, the Fields array (see Table 236) specifies which fields to include in the submission. - * (All descendants of the specified fields in the field hierarchy shall be submitted as well.) - *

- * If set, the Fields array tells which fields to exclude. All fields in the document’s interactive form shall be - * submitted except those listed in the Fields array and those whose NoExport flag (see Table 221) - * is set and fields with no values if the IncludeNoValueFields flag is clear. - */ - public int INCLUDE_EXCLUDE_BIT = 0X0000001; // bit 1 - - /** - * If set, all fields designated by the Fields array and the Include/Exclude flag shall be submitted, regardless - * of whether they have a value (V entry in the field dictionary). For fields without a value, only the field name - * shall be transmitted. - *

- * If clear, fields without a value shall not be submitted. - */ - public int INCLUDE_NO_VALUE_FIELDS_BIT = 0X0000002; // bit 2 - - /** - * Meaningful only if the SubmitPDF and XFDF flags are clear. If set, field names and values shall be submitted in - * HTML Form format. If clear, they shall be submitted in Forms Data Format (FDF); see 12.7.7, “Forms Data Format.†- */ - public int EXPORT_FORMAT_BIT = 0X0000004; // bit 3 - - /** - * If set, field names and values shall be submitted using an HTTP GET request. If clear, they shall be submitted - * using a POST request. This flag is meaningful only when the ExportFormat flag is set; if ExportFormat is clear, - * this flag shall also be clear. - */ - public int GET_METHOD_BIT = 0X0000010; // bit 4 - - /** - * If set, the coordinates of the mouse click that caused the submit-form action shall be transmitted as part of - * the form data. The coordinate values are relative to the upper-left corner of the field’s widget annotation - * rectangle. They shall be represented in the data in the format - *

- * name.x=xval&name.y=yval - *

- * where name is the field’s mapping name (TM in the field dictionary) if present; otherwise, name is the field name. - * If the value of the TM entry is a single ASCII SPACE (20h) character, both the name and the ASCII PERIOD (2Eh) - * following it shall be suppressed, resulting in the format - *

- * x=xval&y=yval - *

- * This flag shall be used only when the ExportFormat flag is set. If ExportFormat is clear, this flag shall also - * be clear - */ - public int SUBMIT_COORDINATES_BIT = 0X0000004; // bit 5 - - /** - * (PDF 1.4) shall be used only if the SubmitPDF flags are clear. If set, field names and values shall be - * submitted as XFDF. - */ - public int XFDF_BIT = 0X0000020; // bit 6 - - /** - * (PDF 1.4) shall be used only when the form is being submitted in Forms Data Format (that is, when both the - * XFDF and ExportFormat flags are clear). If set, the submitted FDF file shall include the contents of all - * incremental updates to the underlying PDF document, as contained in the Differences entry in the FDF - * dictionary (see Table 243). If clear, the incremental updates shall not be included. - */ - public int INCLUDE_APPEND_SAVES_BIT = 0X0000040; // bit 7 - - /** - * (PDF 1.4) shall be used only when the form is being submitted in Forms Data Format (that is, when both the XFDF a - * nd ExportFormat flags are clear). If set, the submitted FDF file shall include includes all markup - * annotations in the underlying PDF document (see 12.5.6.2, “Markup Annotationsâ€). If clear, markup annotations - * shall not be included. - */ - public int INCLUDE_ANNOTATIONS_BIT = 0X0000040; // bit 8 - - /** - * (PDF 1.4) If set, the document shall be submitted as PDF, using the MIME content type application/pdf (described - * in Internet RFC 2045, Multipurpose Internet Mail Extensions (MIME), Part One: Format of Internet Message Bodies; - * see the Bibliography). If set, all other flags shall be ignored except GetMethod. - */ - public int SUBMIT_PDF_BIT = 0X0000100; // bit 9 - - /** - * (PDF 1.4) If set, any submitted field values representing dates shall be converted to the standard format - * described in 7.9.4, “Dates.†- *

- * NOTE
- * The interpretation of a form field as a date is not specified explicitly in the field itself but only in the - * JavaScript code that processes it. - */ - public int CANONICAL_FORMAT_BIT = 0X0000512; // bit 10 - - /** - * (PDF 1.4) shall be used only when the form is being submitted in Forms Data Format (that is, when both the XFDF - * and ExportFormat flags are clear) and the IncludeAnnotations flag is set. If set, it shall include only those - * markup annotations whose T entry (see Table 170) matches the name of the current user, as determined by the - * remote server to which the form is being submitted. - *

- * NOTE 1
The T entry for markup annotations specifies the text label that is displayed in the title bar - * of the annotation’s pop-up window and is assumed to represent the name of the user authoring the annotation. - *

- * NOTE 2
This allows multiple users to collaborate in annotating a single remote PDF document without - * affecting one another’s annotations. - */ - public int EXCL_NON_USER_ANNOTS_BIT = 0X0001024; // bit 11 - - /** - * (PDF 1.4) shall be used only when the form is being submitted in Forms Data Format (that is, when both the XFDF - * and ExportFormat flags are clear). If set, the submitted FDF shall exclude the F entry. - */ - public int EXCL_F_KEY_BIT = 0X0002048; // bit 12 - - /** - * (PDF 1.5) shall be used only when the form is being submitted in Forms Data Format (that is, when both the XFDF - * and ExportFormat flags are clear). If set, the F entry of the submitted FDF shall be a file specification - * containing an embedded file stream representing the PDF file from which the FDF is being submitted. - */ - public int EMBED_FORM_BIT = 0X0008192; // bit 14 - - public SubmitFormAction(Library l, HashMap h) { - super(l, h); - } - - - /** - * An array identifying which fields to reset or which to exclude from - * resetting, depending on the setting of the Include/Exclude flag in the - * Flags entry (see Table 239). Each element of the array shall be either - * an indirect reference to a field dictionary or (PDF 1.3) a text string - * representing the fully qualified name of a field. Elements of both kinds - * may be mixed in the same array. - *

- * If this entry is omitted, the Include/Exclude flag shall be ignored, and all - * fields in the document’s interactive form shall be submitted except those whose - * NoExport flag (see Table 221) is set. Fields with no values may also be excluded, - * as dictated by the value of the IncludeNoValueFields flag; see Table 237. - * - * @return list of fields if present otherwise null. - */ - public List getFields() { - Object tmp = library.getArray(entries, FIELDS_KEY); - if (tmp != null) { - return (List) tmp; - } - return null; - } - - public FileSpecification getFileSpecification() { - Object tmp = library.getObject(entries, F_KEY); - if (tmp instanceof HashMap) { - return new FileSpecification(library, (HashMap) tmp); - } - return null; - } - - /** - * Execute the form submission. The following formats are currently supported: - *

    - *
  • HTML Form format
  • - *
  • Forms Data Format(not supported)
  • - *
  • XFDF(not supported)
  • - *
  • PDF (not supported)
  • - *
- * - * @param x x-coordinate of the mouse event that actuated the submit. - * @param y y-coordinate of the mouse event that actuated the submit. - * @return value of one if submit was successful, zero if not. - */ - public int executeFormAction(int x, int y) { - if (isExportFormat() && !(isXFDF() && isSubmitPDF())) { - return executeHTMLSubmission(x, y); - } else if (isXFDF() && !isSubmitPDF()) { - return executeXFDFSubmission(x, y); - } else if (isSubmitPDF()) { - return executePDFSubmission(x, y); - } else if (isEmbedForm()) { - return executeFormsDatFormatSubmission(x, y); - } - return 0; - } - - /** - * Field names and values shall be submitted in HTML Form format. - * - * @param x x-coordinate of input action. - * @param y y-coordinate of input action. - * @return submit response code. - */ - private int executeHTMLSubmission(int x, int y) { - - - FileSpecification fileSpecification = getFileSpecification(); - if (fileSpecification != null) { - - if (logger.isLoggable(Level.FINEST)) { - logger.finest("HTML Submit form action: " + fileSpecification.getFileSpecification()); - } - - // value pairs to submit. - HashMap params = new HashMap(); - - // check for a fields entry -// List fields = getFields(); -// if (!isIncludeExclude() && fields != null){ -// // pick out the specified fields. -// if (logger.isLoggable(Level.FINEST)){ -// logger.finest("Specified Fields for submit. "); -// } -// }else{ - // NOTE we use them all have no examples yet of fields selection so we are going to submit all - // values for the time being. - InteractiveForm form = library.getCatalog().getInteractiveForm(); - ArrayList fields = form.getFields(); - for (Object field : fields) { - descendFormTree(field, params); - } -// } - - // append coordinates. - if (isSubmitCoordinates()) { - if (logger.isLoggable(Level.FINEST)) { - logger.finest("Including coordinates in submit."); - } - params.put("x", String.valueOf(x)); - params.put("y", String.valueOf(y)); - } - - // todo once we get an example: dates format - if (isCanonicalFormat()) { - if (logger.isLoggable(Level.FINEST)) { - logger.finest("Uses canonical date format."); - } - } - - // submit the data. - if (isGetMethod()){ - return sendGET(fileSpecification.getFileSpecification(), formatParams(params)); - }else{ - return sendPOST(fileSpecification.getFileSpecification(), formatParams(params)); - } - - } - return 0; - } - - // - private int executePDFSubmission(int x, int y) { - return 0; - } - - // currently not supported. - private int executeXFDFSubmission(int x, int y) { - return 0; - } - - // currently not supported. - private int executeFormsDatFormatSubmission(int x, int y) { - return 0; - } - - /** - * Dive into the hierarchy to get the name value pairs of the fields. Currently not recursive as - * we don't have any example to test against. - * - * @param formNode root form node. - * @param params name value pars of form fields. - */ - protected void descendFormTree(Object formNode, HashMap params) { - if (formNode instanceof AbstractWidgetAnnotation) { -// FieldDictionary fieldDictionary = ((AbstractWidgetAnnotation) formNode).getFieldDictionary(); - } else if (formNode instanceof FieldDictionary) { - // iterate over the kid's array. - FieldDictionary child = (FieldDictionary) formNode; - Object value = child.getFieldValue(); - if ((value == null || value.equals("")) && child.getKids() != null && child.getKids().size() == 1) { - value = child.getKids().get(0); - if (value instanceof AbstractWidgetAnnotation) { - value = ((AbstractWidgetAnnotation) value).getFieldDictionary().getFieldValue(); - } else if (value instanceof FieldDictionary) { - value = ((FieldDictionary) value).getFieldValue(); - } - } - if (value != null && !value.equals("")) { - params.put(child.getPartialFieldName(), value.toString()); - }else if(isIncludeNoValueFields()){ - params.put(child.getPartialFieldName(), value == null?null:value.toString()); - } - } - } - - // generates a HTTP get for submitting the form data. - private static int sendGET(String url, String params) { - int responseCode = HttpURLConnection.HTTP_SEE_OTHER; - try { - URL obj = new URL(url + "?" + params); - HttpURLConnection con = (HttpURLConnection) obj.openConnection(); - con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", USER_AGENT); - responseCode = con.getResponseCode(); - if (responseCode == HttpURLConnection.HTTP_OK) { - if (logger.isLoggable(Level.FINER)) { - BufferedReader in = new BufferedReader(new InputStreamReader( - con.getInputStream())); - String inputLine; - StringBuilder response = new StringBuilder(); - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - logger.finer("HTTP GET response: " + response.toString()); - }else { - if (logger.isLoggable(Level.FINER)){ - logger.finer("HTTP GET failed: " + url + ", response " + responseCode); - } - } - } - } catch (IOException e) { - logger.log(Level.WARNING, "Error processing GET: " + url, e); - } - return responseCode; - } - - // generates a HTTP post for submitting the form data. - private static int sendPOST(String url, String params) { - int responseCode = HttpURLConnection.HTTP_SEE_OTHER; - try { - URL urlObject = new URL(url); - HttpURLConnection urlConnection = (HttpURLConnection) urlObject.openConnection(); - urlConnection.setRequestMethod("POST"); - urlConnection.setRequestProperty("User-Agent", USER_AGENT); - - urlConnection.setDoOutput(true); - OutputStream outputStream = urlConnection.getOutputStream(); - outputStream.write(params.getBytes()); - outputStream.flush(); - outputStream.close(); - responseCode = urlConnection.getResponseCode(); - - if (responseCode == HttpURLConnection.HTTP_OK) { - if (logger.isLoggable(Level.FINER)){ - BufferedReader in = new BufferedReader(new InputStreamReader( - urlConnection.getInputStream())); - String inputLine; - StringBuilder response = new StringBuilder(); - - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - in.close(); - logger.finer("HTTP POST response: " + response.toString()); - } - }else { - if (logger.isLoggable(Level.FINER)){ - logger.finer("HTTP POST failed: " + url + ", response " + responseCode); - } - } - } catch (IOException e) { - logger.log(Level.WARNING, "Error processing POST: " + url, e); - } - return responseCode; - } - - private String formatParams(HashMap params){ - StringBuilder submitParams = new StringBuilder(); - for (String key : params.keySet()) { - submitParams.append(key).append("=").append(params.get(key)); - submitParams.append("&"); - } - if (submitParams.length() > 1) { - return submitParams.subSequence(0, submitParams.length() - 1).toString(); - }else{ - return ""; - } - } - - /** - * @see #INCLUDE_EXCLUDE_BIT - */ - public boolean isIncludeExclude() { - return (getFlags() & INCLUDE_EXCLUDE_BIT) == INCLUDE_EXCLUDE_BIT; - } - - /** - * @see #INCLUDE_NO_VALUE_FIELDS_BIT - */ - public boolean isIncludeNoValueFields() { - return (getFlags() & INCLUDE_NO_VALUE_FIELDS_BIT) == INCLUDE_NO_VALUE_FIELDS_BIT; - } - - /** - * @see #EXPORT_FORMAT_BIT - */ - public boolean isExportFormat() { - return (getFlags() & EXPORT_FORMAT_BIT) == EXPORT_FORMAT_BIT; - } - - /** - * @see #GET_METHOD_BIT - */ - public boolean isGetMethod() { - return (getFlags() & GET_METHOD_BIT) == GET_METHOD_BIT; - } - - /** - * @see #SUBMIT_COORDINATES_BIT - */ - public boolean isSubmitCoordinates() { - return (getFlags() & SUBMIT_COORDINATES_BIT) == SUBMIT_COORDINATES_BIT; - } - - /** - * @see #SUBMIT_COORDINATES_BIT - */ - public boolean isXFDF() { - return (getFlags() & XFDF_BIT) == XFDF_BIT; - } - - /** - * @see #INCLUDE_APPEND_SAVES_BIT - */ - public boolean isIncludeAppendSaves() { - return (getFlags() & INCLUDE_APPEND_SAVES_BIT) == INCLUDE_APPEND_SAVES_BIT; - } - - /** - * @see #INCLUDE_ANNOTATIONS_BIT - */ - public boolean isIncludeAnnotations() { - return (getFlags() & INCLUDE_ANNOTATIONS_BIT) == INCLUDE_ANNOTATIONS_BIT; - } - - /** - * @see #SUBMIT_PDF_BIT - */ - public boolean isSubmitPDF() { - return (getFlags() & SUBMIT_PDF_BIT) == SUBMIT_PDF_BIT; - } - - /** - * @see #CANONICAL_FORMAT_BIT - */ - public boolean isCanonicalFormat() { - return (getFlags() & CANONICAL_FORMAT_BIT) == CANONICAL_FORMAT_BIT; - } - - /** - * @see #EXCL_NON_USER_ANNOTS_BIT - */ - public boolean isExcludeNonUserAnnots() { - return (getFlags() & EXCL_NON_USER_ANNOTS_BIT) == EXCL_NON_USER_ANNOTS_BIT; - } - - /** - * @see #EXCL_F_KEY_BIT - */ - public boolean isExcludeFKey() { - return (getFlags() & EXCL_F_KEY_BIT) == EXCL_F_KEY_BIT; - } - - /** - * @see #EMBED_FORM_BIT - */ - public boolean isEmbedForm() { - return (getFlags() & EMBED_FORM_BIT) == EMBED_FORM_BIT; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/URIAction.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/URIAction.java deleted file mode 100644 index 0f63ef8b85..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/actions/URIAction.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.actions; - -import org.icepdf.core.pobjects.LiteralStringObject; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - *

The uniform resource identifier (URI) action represents destination - * that is a hypertext link

- *

- *

The URI can be extracted from this object so that the content can - * be loaded in a web browser. ICEpdf does not currently support image map - * URI's.

- * - * @author ICEsoft Technologies, Inc. - * @since 2.6 - */ -public class URIAction extends Action { - - public static final Name URI_KEY = new Name("URI"); - - // uniform resource identifier to be resolved. - private StringObject URI; - - // specifies whether to track the mouse position. - private boolean isMap; - - /** - * Creates a new instance of a Action. - * - * @param l document library. - * @param h Action dictionary entries. - */ - public URIAction(Library l, HashMap h) { - super(l, h); - } - - /** - * Sets the URI string associated witht this action. - * - * @param URI an string value except null. - */ - public void setURI(String URI) { - StringObject tmp = new LiteralStringObject( - URI, getPObjectReference(), library.getSecurityManager()); - // StringObject detection should allow writer to pick on encryption. - entries.put(URIAction.URI_KEY, tmp); - this.URI = tmp; - } - - /** - * Gets the Uniform resource identifier to resolve, encoded in 7-bit ASCII. - * - * @return uniform resouce. - */ - public String getURI() { - // URI should always be text, but there have been examples of - // Hex encoded uri values. - Object actionURI = getObject(URI_KEY); - if (actionURI instanceof StringObject) { - URI = (StringObject) actionURI; - } - return URI.getDecryptedLiteralString(library.getSecurityManager()); - } - - /** - * Gets a flag specifying whether to track thee mouse poisition when the - * URI is resolved. Default value is false. - * - * @return true if tmouse poiiin is to be called. - */ - public boolean isMap() { - return isMap; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/AbstractWidgetAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/AbstractWidgetAnnotation.java deleted file mode 100644 index b5d1aaf514..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/AbstractWidgetAnnotation.java +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.pobjects.acroform.InteractiveForm; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.HashMap; -import java.util.StringTokenizer; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Abstract base class for Widget annotations types, button, choice and text. - * - * @since 5.1 - */ -public abstract class AbstractWidgetAnnotation extends Annotation { - - /** - * Indicates that the annotation has no highlight effect. - */ - public static final Name HIGHLIGHT_NONE = new Name("N"); - - protected static final Logger logger = - Logger.getLogger(AbstractWidgetAnnotation.class.toString()); - - /** - * Transparency value used to simulate text highlighting. - */ - protected static float highlightAlpha = 0.1f; - - // text selection colour - protected static Color highlightColor; - - private boolean enableHighlightedWidget; - - static { - // sets the background colour of the annotation highlight - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.widget.highlight.color", "#CC00FF"); - int colorValue = ColorUtil.convertColor(color); - highlightColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("0077FF", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading widget highlight colour."); - } - } - - try { - highlightAlpha = (float) Defs.doubleProperty( - "org.icepdf.core.views.page.annotation.widget.highlight.alpha", 0.1f); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading widget highlight alpha."); - } - } - } - - protected Name highlightMode; - - public AbstractWidgetAnnotation(Library l, HashMap h) { - super(l, h); - Object possibleName = getObject(LinkAnnotation.HIGHLIGHT_MODE_KEY); - if (possibleName instanceof Name) { - Name name = (Name) possibleName; - if (HIGHLIGHT_NONE.equals(name.getName())) { - highlightMode = HIGHLIGHT_NONE; - } else if (LinkAnnotation.HIGHLIGHT_OUTLINE.equals(name.getName())) { - highlightMode = LinkAnnotation.HIGHLIGHT_OUTLINE; - } else if (LinkAnnotation.HIGHLIGHT_PUSH.equals(name.getName())) { - highlightMode = LinkAnnotation.HIGHLIGHT_PUSH; - } - } else { - highlightMode = LinkAnnotation.HIGHLIGHT_INVERT; - } - - } - - @Override - public void init() throws InterruptedException { - super.init(); - // check to make sure the field value matches the content stream. - InteractiveForm interactiveForm = library.getCatalog().getInteractiveForm(); - if (interactiveForm != null && interactiveForm.needAppearances()) { - resetAppearanceStream(new AffineTransform()); - } - // todo check if we have content value but no appearance stream. - } - - public abstract void reset(); - - @Override - public abstract void resetAppearanceStream(double dx, double dy, AffineTransform pageSpace); - - @Override - protected void renderAppearanceStream(Graphics2D g) { - - Appearance appearance = appearances.get(currentAppearance); - if (appearance != null) { - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - if (appearanceState != null && - appearanceState.getShapes() != null) { - // render the main annotation content - super.renderAppearanceStream(g); - } - } - // check the highlight widgetAnnotation field and if true we draw a light background colour to mark - // the widgets on a page. - if (enableHighlightedWidget) { - AffineTransform preHighLightTransform = g.getTransform(); - g.setColor(highlightColor); - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightAlpha)); - g.fill(getBbox() != null ? getBbox() : getRectangle()); - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); - g.setTransform(preHighLightTransform); - } - } - - private Rectangle2D getRectangle() { - Rectangle2D origRect = getBbox() != null ? getBbox() : getUserSpaceRectangle(); - Rectangle2D.Float jrect = new Rectangle2D.Float(0, 0, - (float) origRect.getWidth(), (float) origRect.getHeight()); - return jrect; - } - - public abstract T getFieldDictionary(); - - /** - * Generally immediately after the BMC there is a rectangle that defines the actual size of the annotation. If - * found we can use this to make many assumptions and regenerate the content stream. - * - * @param markedContent content stream of the marked content. - * @return a rectangle either way, if the q # # # # re isn't found then we use the bbox as a potential bound. - */ - protected Rectangle2D.Float findBoundRectangle(String markedContent) { - int selectionStart = markedContent.indexOf("q") + 1; - int selectionEnd = markedContent.indexOf("re"); - if (selectionStart < selectionEnd && selectionEnd > 0) { - String potentialNumbers = markedContent.substring(selectionStart, selectionEnd); - float[] points = parseRectanglePoints(potentialNumbers); - if (points != null) { - return new Rectangle2D.Float(points[0], points[1], points[2], points[3]); - } - } - // default to the bounding box. - Rectangle2D bbox = getBbox(); - return new Rectangle2D.Float(1, 1, (float) bbox.getWidth(), (float) bbox.getHeight()); - } - - /** - * Finds a rectangle in the marked content. - * - * @param markedContent content to search for a rectangle. - * @return rectangle if found, otherwise bbox is used. - */ - protected Rectangle2D.Float findRectangle(String markedContent) { - int selectionEnd = markedContent.indexOf("re"); - if (selectionEnd >= 0) { - String potentialNumbers = markedContent.substring(0, selectionEnd); - float[] points = parseRectanglePoints(potentialNumbers); - if (points != null) { - return new Rectangle2D.Float(points[0], points[1], points[2], points[3]); - } - // default to the bounding box. - Rectangle2D bbox = getBbox(); - return new Rectangle2D.Float(1, 1, (float) bbox.getWidth(), (float) bbox.getHeight()); - } else { - return null; - } - } - - /** - * Get the line height as specified by Th or the font size. - * - * @param defaultAppearance searchable stream - * @return line height, or 13.87 if no reasonable approximation can be found. - */ - protected double getLineHeight(String defaultAppearance) { - if (defaultAppearance != null && checkAppearance(defaultAppearance)) { - String sub = defaultAppearance.substring(0, defaultAppearance.indexOf("Tf")); - StringTokenizer toker = new StringTokenizer(sub); - while (toker.hasMoreTokens()) { - Object obj = toker.nextElement(); - if (obj instanceof String) { - try { - double tmp = Double.parseDouble((String) obj); - tmp *= 1.15; - if (tmp > 0) { - return tmp; - } - } catch (NumberFormatException e) { - // intentionally blank. - } - } - } - } - return 13.87; - } - - protected double getFontSize(String content) { - // try and find text size - double size = 12; - - if (content != null) { - Pattern pattern = Pattern.compile("\\d+(\\.\\d+)?\\s+Tf"); - Matcher matcher = pattern.matcher(content); - if (matcher.find()) { - String fontDef = content.substring(matcher.start(), matcher.end()); - fontDef = fontDef.split(" ")[0]; - try { - size = Double.parseDouble(fontDef); - } catch (NumberFormatException e) { - // ignore and move on - } - if (size < 2) { - size = 12; - } - } - } - return size; - } - - /** - * Encodes the given cotents string into a valid postscript string that is literal encoded. - * - * @param content current content stream to append literal string to. - * @param contents string to be encoded into '(...)' literal format. - * @return original content stream with contents encoded in the literal string format. - */ - protected StringBuilder encodeLiteralString(StringBuilder content, String contents) { - String[] lines = contents.split("\n|\r|\f"); - for (String line : lines) { - content.append('(').append(line.replaceAll("(?=[()\\\\])", "\\\\") - .replaceAll("ÿ", "")).append(")' "); - } - return content; - } - - /** - * Encodes the given contents string into a valid postscript hex string. - * - * @param content current content stream to append literal string to. - * @param contents string to be encoded into '<...>' hex format. - * @return original content stream with contents encoded in the hex string format. - */ - protected StringBuilder encodeHexString(StringBuilder content, String contents) { - String[] lines = contents.split("\n|\r|\f"); - for (String line : lines) { - char[] chars = line.toCharArray(); - StringBuffer hex = new StringBuffer(); - for (int i = 0; i < chars.length; i++) { - hex.append(Integer.toHexString((int) chars[i])); - } - content.append('<').append(hex).append(">' "); - } - return content; - } - - /** - * Utility to try and determine if the appearance is valid. - * - * @param appearance appearance ot test. - * @return true if valid, false otherwise. - */ - protected boolean checkAppearance(String appearance) { - // example of a bad appearance, /TiBo 0 Tf 0 g - // size is zero and the font can't be found. - StringTokenizer toker = new StringTokenizer(appearance); - if (toker.hasMoreTokens()) { - String fontName = toker.nextToken().substring(1); - String fontSize = toker.nextToken(); - Appearance appearance1 = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance1.getSelectedAppearanceState(); - org.icepdf.core.pobjects.fonts.Font font = null; - Resources resources = appearanceState.getResources(); - if (resources != null) { - font = resources.getFont(new Name(fontName)); - } - return !(font == null || library.getInteractiveFormFont(fontName) == null || - fontSize.equals("0")); - } - return false; - } - - - /** - * The selection rectangle if present will help define the line height of the text. If not present we can use - * the default value 13.87 later which seems to be very common in the samples. - * - * @param markedContent content to look for "rg # # # # re". - * @return selection rectangle, null if not found. - */ - protected Rectangle2D.Float findSelectionRectangle(String markedContent) { - int selectionStart = markedContent.indexOf("rg") + 2; - int selectionEnd = markedContent.lastIndexOf("re"); - if (selectionStart < selectionEnd && selectionEnd > 0) { - String potentialNumbers = markedContent.substring(selectionStart, selectionEnd); - float[] points = parseRectanglePoints(potentialNumbers); - if (points != null) { - return new Rectangle2D.Float(points[0], points[1], points[2], points[3]); - } - } - return null; - } - - /** - * Simple utility to write Rectangle2D.Float in postscript. - * - * @param rect Rectangle2D.Float to convert to postscript. Null value with throw null pointer exception. - * @return postscript representation of the rect. - */ - protected String generateRectangle(Rectangle2D.Float rect) { - return rect.x + " " + rect.y + " " + rect.width + " " + rect.height + " re "; - } - - /** - * Converts a given string of four numbers into an array of floats. If a conversion error is encountered - * null value is returned. - * - * @param potentialNumbers space separated string of four numbers. - * @return list of four numbers, null if string can not be converted. - */ - protected float[] parseRectanglePoints(String potentialNumbers) { - StringTokenizer toker = new StringTokenizer(potentialNumbers); - float[] points = new float[4]; - int max = toker.countTokens(); - Object[] tokens = new Object[max]; - for (int i = 0; i < max; i++) { - tokens[i] = toker.nextElement(); - } - boolean notFound = false; - for (int i = 3, j = 0; j < 4; j++, i--) { - try { - points[j] = Float.parseFloat((String) tokens[max - i - 1]); - } catch (NumberFormatException e) { - notFound = true; - } - } - if (!notFound) { - return points; - } else { - return null; - } - } - - /** - * Set the static highlight color used to highlight widget annotations. - * - * @param highlightColor colour of - */ - public static void setHighlightColor(Color highlightColor) { - AbstractWidgetAnnotation.highlightColor = highlightColor; - } - - /** - * Set enable highlight on an individual widget. - * - * @param enableHighlightedWidget true to enable highlight mode, otherwise false. - */ - public void setEnableHighlightedWidget(boolean enableHighlightedWidget) { - this.enableHighlightedWidget = enableHighlightedWidget; - } - - /** - * Set the static alpha value uses to paint a color over a widget annotation. - * - * @param highlightAlpha - */ - public static void setHighlightAlpha(float highlightAlpha) { - AbstractWidgetAnnotation.highlightAlpha = highlightAlpha; - } - - /** - * Is enable highlight enabled. - * - * @return return true if highlight is enabled, false otherwise. - */ - public boolean isEnableHighlightedWidget() { - return enableHighlightedWidget; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/Annotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/Annotation.java deleted file mode 100644 index 5af8323240..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/Annotation.java +++ /dev/null @@ -1,1910 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.pobjects.acroform.FieldDictionaryFactory; -import org.icepdf.core.pobjects.actions.Action; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.pobjects.security.SecurityManager; -import org.icepdf.core.util.GraphicsRenderingHints; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.awt.*; -import java.awt.geom.*; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.util.*; -import java.util.List; -import java.util.logging.Logger; - -/** - *

An Annotation class associates an object such as a note, sound, or movie with - * a location on a page of a PDF document, or provides a way to interact with - * the user by means of the mouse and keyboard.

- *

- *

This class allows direct access to the a Annotations dictionary. - * Developers can take advantage of this information as they see fit. It is - * important to note that an annotations' rectangle coordinates are defined - * in the PDF document space. In order to map the rectangle coordinates to - * a view, they must be converted from the Cartesian plain to the the Java2D - * plain. The PageView method getPageBounds() can be used to locate the position - * of a page within its parent component.

- *

- * Base class of all the specific Annotation types - *

- * Taken from the PDF 1.6 spec, here is some relevant documentation, - * along with some additional commentary - *

- *

8.4.1 Annotation Dictionaries

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
KeyTypeValue
Typename(Optional) The type of PDF object that this dictionary describes; - * if present, must be Annot for an annotation dictionary.
Subtypename(Required) The type of annotation that this dictionary describes.
Rectrectangle(Required) The annotation rectangle, defining the location of the - * annotation on the page in default user space units.getUserspaceLocation()
Contentstext string(Optional) Text to be displayed for the annotation or, if this type of annotation - * does not display text, an alternate description of the annotation's contents - * in human-readable form.'s contents in support of accessibility to users with - * disabilities or for other purposes (see Section 10.8.2, "Alternate Descriptions"). - * See Section 8.4.5, "Annotation Types" for more details on the meaning - * of this entry for each annotation type.
Pdictionary(Optional; PDF 1.3; not used in FDF files) An indirect reference to the page - * object with which this annotation is associated.
NMtext string(Optional; PDF 1.4) The annotation name, a text string uniquely identifying it - * among all the annotations on its page.
Mdate or string(Optional; PDF 1.1) The date and time when the annotation was most - * recently modified. The preferred format is a date string as described in Section - * 3.8.3, "Dates," but viewer applications should be prepared to accept and - * display a string in any format. (See implementation note 78 in Appendix H.)
Finteger(Optional; PDF 1.1) A set of flags specifying various characteristics of the annotation - * (see Section 8.4.2, "Annotation Flags"). Default value: 0.
BSdictionary(Optional; PDF 1.2) A border style dictionary specifying the characteristics of - * the annotation's border (see Section 8.4.3, "Border Styles"; see also implementation - * notes 79 and 86 in Appendix H).
- *
- * Note: This entry also specifies the width and dash pattern for the lines drawn by - * line, square, circle, and ink annotations. See the note under Border (below) for - * additional information.
- *
- * Table 8.13 summarizes the contents of the border style dictionary. If neither - * the Border nor the BS entry is present, the border is drawn as a solid line with a - * width of 1 point.
APdictionary(Optional; PDF 1.2) An appearance dictionary specifying how the annotation - * is presented visually on the page (see Section 8.4.4, "Appearance Streams" and - * also implementation notes 79 and 80 in Appendix H). Individual annotation - * handlers may ignore this entry and provide their own appearances.
- *
- * For convenience in managing appearance streams that are used repeatedly, the AP - * entry in a PDF document's name dictionary (see Section 3.6.3, "Name Dictionary") - * can contain a name tree mapping name strings to appearance streams. The - * name strings have no standard meanings; no PDF objects refer to appearance - * streams by name.
ASname(Required if the appearance dictionary AP contains one or more subdictionaries; - * PDF 1.2) The annotation's appearance state, which selects the applicable - * appearance stream from an appearance subdictionary (see Section 8.4.4, "Appearance - * Streams" and also implementation note 79 in Appendix H).
Borderarray(Optional) An array specifying the characteristics of the annotation's border. - * The border is specified as a rounded rectangle.
- *
- * In PDF 1.0, the array consists of three numbers defining the horizontal corner - * radius, vertical corner radius, and border width, all in default user space - * units. If the corner radii are 0, the border has square (not rounded) corners; if - * the border width is 0, no border is drawn. (See implementation note 81 in - * Appendix H.)
- *
- * In PDF 1.1, the array may have a fourth element, an optional dash array - * defining a pattern of dashes and gaps to be used in drawing the border. The - * dash array is specified in the same format as in the line dash pattern parameter - * of the graphics state (see "Line Dash Pattern" on page 187). For example, a - * Border value of [0 0 1 [3 2]] specifies a border 1 unit wide, with square corners, - * drawn with 3-unit dashes alternating with 2-unit gaps. Note that no - * dash phase is specified; the phase is assumed to be 0. (See implementation - * note 82 in Appendix H.)
- *
- * Note: In PDF 1.2 or later, this entry may be ignored in favor of the BS - * entry (see above); see implementation note 86 in Appendix H.
- *
- * Default value: [0 0 1].
BEdictionary(Optional; PDF 1.5) Some annotations (square, circle, and polygon) may - * have a BE entry, which is a border effect dictionary that specifies an effect - * to be applied to the border of the annotations. Its entries are listed in Table 8.14.
Carray(Optional; PDF 1.1) An array of three numbers in the range 0.0 to 1.0, representing - * the components of a color in the DeviceRGB color space. This color is - * used for the following purposes: - *
    - *
  • The background of the annotation's icon when closed - *
  • The title bar of the annotation's pop-up window - *
  • The border of a link annotation - *
Adictionary(Optional; PDF 1.1) An action to be performed when the annotation is activated - * (see Section 8.5, "Actions").
- *
- * Note: This entry is not permitted in link annotations if a Dest entry is present - * (see "Link Annotations" on page 587). Also note that the A entry in movie annotations - * has a different meaning (see "Movie Annotations" on page 601).
AAdictionary(Optional; PDF 1.2) An additional-actions dictionary defining the annotation's - * behavior in response to various trigger events (see Section 8.5.2, - * "Trigger Events"). At the time of publication, this entry is used only by widget - * annotations.
StructParentinteger((Required if the annotation is a structural content item; PDF 1.3) The integer - * key of the annotation's entry in the structural parent tree (see "Finding Structure - * Elements from Content Items" on page 797).
OCdictionary(Optional; PDF 1.5) An optional content group or optional content membership - * dictionary (see Section 4.10, "Optional Content") specifying the optional - * content properties for the annotation. Before the annotation is drawn, its visibility - * is determined based on this entry as well as the annotation flags specified - * in the F entry (see Section 8.4.2, "Annotation Flags"). If it is determined - * to be invisible, the annotation is skipped, as if it were not in the document.
- *

- *

- *

8.4.2 Annotation Flags

- * The value of the annotation dictionary's F entry is an unsigned 32-bit integer containing - * flags specifying various characteristics of the annotation. Bit positions - * within the flag word are numbered from 1 (low-order) to 32 (high-order). Table - * 8.12 shows the meanings of the flags; all undefined flag bits are reserved and must - * be set to 0. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Bit positionNameMeaning
1InvisibleIf set, do not display the annotation if it does not belong to one of the standard - * annotation types and no annotation handler is available. If clear, display such an - * unknown annotation using an appearance stream specified by its appearance - * dictionary, if any (see Section 8.4.4, "Appearance Streams").
2HiddenIf set, do not display or print the annotation or allow it to interact - * with the user, regardless of its annotation type or whether an annotation - * handler is available. In cases where screen space is limited, the ability to hide - * and show annotations selectively can be used in combination with appearance - * streams (see Section 8.4.4, "Appearance Streams") to display auxiliary pop-up - * information similar in function to online help systems. (See implementation - * note 83 in Appendix H.)
3PrintIf set, print the annotation when the page is printed. If clear, never - * print the annotation, regardless of whether it is displayed on the screen. This - * can be useful, for example, for annotations representing interactive pushbuttons, - * which would serve no meaningful purpose on the printed page. (See - * implementation note 83 in Appendix H.)
4NoZoomIf set, do not scale the annotation's appearance to match the magnification - * of the page. The location of the annotation on the page (defined by the - * upper-left corner of its annotation rectangle) remains fixed, regardless of the - * page magnification. See below for further discussion.
5NoRotateIf set, do not rotate the annotation's appearance to match the rotation - * of the page. The upper-left corner of the annotation rectangle remains in a fixed - * location on the page, regardless of the page rotation. See below for further discussion.
6NoViewIf set, do not display the annotation on the screen or allow it to - * interact with the user. The annotation may be printed (depending on the setting - * of the Print flag) but should be considered hidden for purposes of on-screen - * display and user interaction.
7ReadOnlyIf set, do not allow the annotation to interact with the user. The - * annotation may be displayed or printed (depending on the settings of the - * NoView and Print flags) but should not respond to mouse clicks or change its - * appearance in response to mouse motions.
- *
- * Note: This flag is ignored for widget annotations; its function is subsumed by the - * ReadOnly flag of the associated form field (see Table 8.66 on page 638).
8LockedIf set, do not allow the annotation to be deleted or its properties (including - * position and size) to be modified by the user. However, this flag does - * not restrict changes to the annotation's contents, such as the value of a form - * field. (See implementation note 84 in Appendix H.)
9ToggleNoViewIf set, invert the interpretation of the NoView flag for certain events. A - * typical use is to have an annotation that appears only when a mouse cursor is - * held over it; see implementation note 85 in Appendix H.
- * - * @author Mark Collette - * @since 2.5 - */ - -public abstract class Annotation extends Dictionary { - - private static final Logger logger = - Logger.getLogger(Annotation.class.toString()); - - public static final Name TYPE = new Name("Annot"); - public static final Name RESOURCES_VALUE = new Name("Resources"); - public static final Name BBOX_VALUE = new Name("BBox"); - public static final Name PARENT_KEY = new Name("Parent"); - /** - * Dictionary constants for Annotations. - */ - - public static final Name TYPE_VALUE = new Name("Annot"); - /** - * Annotation subtype and types. - */ - public static final Name SUBTYPE_LINK = new Name("Link"); - public static final Name SUBTYPE_LINE = new Name("Line"); - public static final Name SUBTYPE_SQUARE = new Name("Square"); - public static final Name SUBTYPE_CIRCLE = new Name("Circle"); - public static final Name SUBTYPE_POLYGON = new Name("Polygon"); - public static final Name SUBTYPE_POLYLINE = new Name("PolyLine"); - public static final Name SUBTYPE_HIGHLIGHT = new Name("Highlight"); - public static final Name SUBTYPE_POPUP = new Name("Popup"); - public static final Name SUBTYPE_WIDGET = new Name("Widget"); - public static final Name SUBTYPE_INK = new Name("Ink"); - public static final Name SUBTYPE_FREE_TEXT = new Name("FreeText"); - public static final Name SUBTYPE_TEXT = new Name("Text"); - /** - * If set, do not display the annotation if it does not belong to one of the - * standard annotation types and no annotation handler is available. If clear, - * display such an unknown annotation using an appearance stream specified - * by its appearance dictionary, if any - */ - public static final int FLAG_INVISIBLE = 0x0001; - /** - * If set, do not display or print the annotation or allow it to interact - * with the user, regardless of its annotation type or whether an annotation - * handler is available. - */ - public static final int FLAG_HIDDEN = 0x0002; - /** - * If set, print the annotation when the page is printed. If clear, never - * print the annotation, regardless of whether it is displayed on the screen. - */ - public static final int FLAG_PRINT = 0x0004; - /** - * If set, do not scale the annotation’s appearance to match the magnification - * of the page. The location of the annotation on the page (defined by the - * upper-left corner of its annotation rectangle) shall remain fixed, - * regardless of the page magnification. See further discussion following - * this Table. - */ - public static final int FLAG_NO_ZOOM = 0x0008; - /** - * If set, do not rotate the annotation’s appearance to match the rotation - * of the page. The upper-left corner of the annotation rectangle shall - * remain in a fixed location on the page, regardless of the page rotation. - * See further discussion following this Table. - */ - public static final int FLAG_NO_ROTATE = 0x0010; - /** - * If set, do not display the annotation on the screen or allow it to interact - * with the user. The annotation may be printed (depending on the setting of - * the Print flag) but should be considered hidden for purposes of on-screen - * display and user interaction. - */ - public static final int FLAG_NO_VIEW = 0x0020; - /** - * If set, do not allow the annotation to interact with the user. The - * annotation may be displayed or printed (depending on the settings of the - * NoView and Print flags) but should not respond to mouse clicks or change - * its appearance in response to mouse motions. - *

- * This flag shall be ignored for widget annotations; its function is - * subsumed by the ReadOnly flag of the associated form field. - */ - public static final int FLAG_READ_ONLY = 0x0040; - /** - * If set, do not allow the annotation to be deleted or its properties - * (including position and size) to be modified by the user. However, this - * flag does not restrict changes to the annotation’s contents, such as the - * value of a form field. - */ - public static final int FLAG_LOCKED = 0x0080; - /** - * If set, invert the interpretation of the NoView flag for certain events. - */ - public static final int FLAG_TOGGLE_NO_VIEW = 0x0100; - /** - * If set, do not allow the contents of the annotation to be modified by the - * user. This flag does not restrict deletion of the annotation or changes - * to other annotation properties, such as position and size. - */ - public static final int FLAG_LOCKED_CONTENTS = 0x0200; - /** - * Border style - */ - public static final Name BORDER_STYLE_KEY = new Name("BS"); - /** - * The annotation location on the page in user space units. - */ - public static final Name RECTANGLE_KEY = new Name("Rect"); - /** - * The action to be performed whenteh annotation is activated. - */ - public static final Name ACTION_KEY = new Name("A"); - /** - * Page that this annotation is associated with. - */ - public static final Name PARENT_PAGE_KEY = new Name("P"); - /** - * Annotation border characteristics. - */ - public static final Name BORDER_KEY = new Name("Border"); - /** - * Annotation border characteristics. - */ - public static final Name FLAG_KEY = new Name("F"); - /** - * RGB colour value for background, titlebars and link annotation borders - */ - public static final Name COLOR_KEY = new Name("C"); - /** - * Appearance dictionary specifying how the annotation is presented - * visually on the page. - */ - public static final Name APPEARANCE_STREAM_KEY = new Name("AP"); - /** - * Appearance state selecting default from multiple AP's. - */ - public static final Name APPEARANCE_STATE_KEY = new Name("AS"); - /** - * Appearance dictionary specifying how the annotation is presented - * visually on the page for normal display. - */ - public static final Name APPEARANCE_STREAM_NORMAL_KEY = new Name("N"); - /** - * Appearance dictionary specifying how the annotation is presented - * visually on the page for rollover display. - */ - public static final Name APPEARANCE_STREAM_ROLLOVER_KEY = new Name("R"); - /** - * Appearance dictionary specifying how the annotation is presented - * visually on the page for down display. - */ - public static final Name APPEARANCE_STREAM_DOWN_KEY = new Name("D"); - /** - * (Optional) Text that shall be displayed for the annotation or, if this - * type of annotation does not display text, an alternate description of the - * annotation’s contents in human-readable form. In either case, this text - * is useful when extracting the document’s contents in support of accessibility - * to users with disabilities or for other purposes (see 14.9.3, - * “Alternate Descriptionsâ€). See 12.5.6, “Annotation Types†for more details - * on the meaning of this entry for each annotation type. - */ - public static final Name CONTENTS_KEY = new Name("Contents"); - /** - * The date and time when the annotation was most recently modified. The - * format should be a date string as described in 7.9.4, “Dates,†but - * conforming readers shall accept and display a string in any format. - */ - public static final Name M_KEY = new Name("M"); - /** - * (Optional; PDF 1.4) The annotation name, a text string uniquely - * identifying it among all the annotations on its page. - */ - public static final Name NM_KEY = new Name("NM"); - /** - * Border property indexes for the border vector, only applicable - * if the border style has not been set. - */ - public static final int BORDER_HORIZONTAL_CORNER_RADIUS = 0; - public static final int BORDER_VERTICAL_CORNER_RADIUS = 1; - public static final int BORDER_WIDTH = 2; - public static final int BORDER_DASH = 3; - /** - * Annotion may or may not have a visible rectangle border - */ - public static final int VISIBLE_RECTANGLE = 1; - public static final int INVISIBLE_RECTANGLE = 0; - - protected PropertyChangeSupport changeSupport; - - /** - * Debug flag to turn off appearance stream compression for easier - * human file reading. - */ - protected static boolean compressAppearanceStream = true; - protected HashMap appearances = new HashMap(3); - protected Name currentAppearance; - - // modified date. - protected PDate modifiedDate; - protected boolean hasBlendingMode; - - // security manager need for decrypting strings. - protected SecurityManager securityManager; - - // type of annotation - protected Name subtype; - // content flag - protected String content; - // borders style of the annotation, can be null - protected BorderStyle borderStyle; - // border defined by vector - protected List border; - // border color of annotation. - protected Color color; - // annotation bounding rectangle in user space. - protected Rectangle2D.Float userSpaceRectangle; - // test for borderless annotation types - protected boolean canDrawBorder; - - /** - * Creates a new instance of an Annotation. - * - * @param l document library. - * @param h dictionary entries. - */ - public Annotation(Library l, HashMap h) { - super(l, h); - } - - /** - * Should only be called from Parser, Use AnnotationFactory if you - * creating a new annotation. - * - * @param library document library - * @param hashMap annotation properties. - * @return annotation instance. - */ - @SuppressWarnings("unchecked") - public static Annotation buildAnnotation(Library library, HashMap hashMap) { - Annotation annot = null; - Name subType = (Name) hashMap.get(SUBTYPE_KEY); - if (subType != null) { - if (subType.equals(Annotation.SUBTYPE_LINK)) { - annot = new LinkAnnotation(library, hashMap); - } - // highlight version of a TextMarkup annotation. - else if (subType.equals(TextMarkupAnnotation.SUBTYPE_HIGHLIGHT) || - subType.equals(TextMarkupAnnotation.SUBTYPE_STRIKE_OUT) || - subType.equals(TextMarkupAnnotation.SUBTYPE_UNDERLINE)) { - annot = new TextMarkupAnnotation(library, hashMap); - } else if (subType.equals(Annotation.SUBTYPE_LINE)) { - annot = new LineAnnotation(library, hashMap); - } else if (subType.equals(Annotation.SUBTYPE_SQUARE)) { - annot = new SquareAnnotation(library, hashMap); - } else if (subType.equals(Annotation.SUBTYPE_CIRCLE)) { - annot = new CircleAnnotation(library, hashMap); - } else if (subType.equals(Annotation.SUBTYPE_INK)) { - annot = new InkAnnotation(library, hashMap); - } else if (subType.equals(Annotation.SUBTYPE_FREE_TEXT)) { - annot = new FreeTextAnnotation(library, hashMap); - } else if (subType.equals(Annotation.SUBTYPE_TEXT)) { - annot = new TextAnnotation(library, hashMap); - } else if (subType.equals(Annotation.SUBTYPE_POPUP)) { - annot = new PopupAnnotation(library, hashMap); - } else if (subType.equals(Annotation.SUBTYPE_WIDGET)) { - Name fieldType = library.getName(hashMap, FieldDictionary.FT_KEY); - if (fieldType == null) { - // get type from parent object if we the widget and field dictionary aren't combined. - Object tmp = library.getObject(hashMap, FieldDictionary.PARENT_KEY); - if (tmp instanceof HashMap) { - fieldType = library.getName((HashMap) tmp, FieldDictionary.FT_KEY); - } - } - if (FieldDictionaryFactory.TYPE_BUTTON.equals(fieldType)) { - annot = new ButtonWidgetAnnotation(library, hashMap); - } else if (FieldDictionaryFactory.TYPE_CHOICE.equals(fieldType)) { - annot = new ChoiceWidgetAnnotation(library, hashMap); - } else if (FieldDictionaryFactory.TYPE_TEXT.equals(fieldType)) { - annot = new TextWidgetAnnotation(library, hashMap); - } else if (FieldDictionaryFactory.TYPE_SIGNATURE.equals(fieldType)) { - annot = new SignatureWidgetAnnotation(library, hashMap); - } else { - annot = new WidgetAnnotation(library, hashMap); - } - } - } - if (annot == null) { - annot = new GenericAnnotation(library, hashMap); - } -// annot.init(); - return annot; - } - - public static void setCompressAppearanceStream(boolean compressAppearanceStream) { - Annotation.compressAppearanceStream = compressAppearanceStream; - } - - @SuppressWarnings("unchecked") - public void init() throws InterruptedException { - super.init(); - // type of Annotation - subtype = (Name) getObject(SUBTYPE_KEY); - - securityManager = library.getSecurityManager(); - - content = getContents(); - - // no borders for the following types, not really in the - // spec for some reason, Acrobat doesn't render them. - // todo add other annotations types. - canDrawBorder = !( - SUBTYPE_LINE.equals(subtype) || - SUBTYPE_CIRCLE.equals(subtype) || - SUBTYPE_SQUARE.equals(subtype) || - SUBTYPE_POLYGON.equals(subtype) || - SUBTYPE_POLYLINE.equals(subtype)); - - // parse out border style if available - Object BS = getObject(BORDER_STYLE_KEY); - if (BS != null) { - if (BS instanceof HashMap) { - borderStyle = new BorderStyle(library, (HashMap) BS); - } else if (BS instanceof BorderStyle) { - borderStyle = (BorderStyle) BS; - } - } - // else build out a border style from the old B entry or create - // a default invisible border. - else { - HashMap borderMap = new HashMap(); - // get old school border - Object borderObject = getObject(BORDER_KEY); - if (borderObject != null && borderObject instanceof List) { - border = (List) borderObject; - // copy over the properties to border style. - if (border.size() == 3) { - borderMap.put(BorderStyle.BORDER_STYLE_KEY, BorderStyle.BORDER_STYLE_SOLID); - borderMap.put(BorderStyle.BORDER_WIDTH_KEY, border.get(2)); - } else if (border.size() == 4) { - borderMap.put(BorderStyle.BORDER_STYLE_KEY, BorderStyle.BORDER_STYLE_DASHED); - borderMap.put(BorderStyle.BORDER_WIDTH_KEY, border.get(2)); - borderMap.put(BorderStyle.BORDER_DASH_KEY, Arrays.asList(3f)); - } - } else { - // default to invisible border - borderMap.put(BorderStyle.BORDER_STYLE_KEY, BorderStyle.BORDER_STYLE_SOLID); - borderMap.put(BorderStyle.BORDER_WIDTH_KEY, 0f); - } - borderStyle = new BorderStyle(library, borderMap); - entries.put(BORDER_STYLE_KEY, borderStyle); - } - - // parse out border colour, specific to link annotations. - color = null; // null as some borders are set as transparent via no colour - List C = (List) getObject(COLOR_KEY); - // parse thought rgb colour. - if (C != null && C.size() >= 3) { - float red = ((Number) C.get(0)).floatValue(); - float green = ((Number) C.get(1)).floatValue(); - float blue = ((Number) C.get(2)).floatValue(); - red = Math.max(0.0f, Math.min(1.0f, red)); - green = Math.max(0.0f, Math.min(1.0f, green)); - blue = Math.max(0.0f, Math.min(1.0f, blue)); - color = new Color(red, green, blue); - } - - // if no creation date check for M or modified. - Object value = library.getObject(entries, M_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - modifiedDate = new PDate(securityManager, - text.getDecryptedLiteralString(securityManager)); - } - - // process the streams if available. - Object AP = getObject(APPEARANCE_STREAM_KEY); - if (AP instanceof HashMap) { - // assign the default AS key as the default appearance - currentAppearance = APPEARANCE_STREAM_NORMAL_KEY; - Name appearanceState = (Name) getObject(APPEARANCE_STATE_KEY); - if (appearanceState == null) { - appearanceState = APPEARANCE_STREAM_NORMAL_KEY; - } - // The annotations normal appearance. - Object appearance = library.getObject( - (HashMap) AP, APPEARANCE_STREAM_NORMAL_KEY); - if (appearance != null) { - appearances.put(APPEARANCE_STREAM_NORMAL_KEY, - parseAppearanceDictionary(APPEARANCE_STREAM_NORMAL_KEY, - appearance)); - appearances.get(APPEARANCE_STREAM_NORMAL_KEY).setSelectedName(appearanceState); - } - // (Optional) The annotation’s rollover appearance. - // Default value: the value of the N entry. - appearance = library.getObject( - (HashMap) AP, APPEARANCE_STREAM_ROLLOVER_KEY); - if (appearance != null) { - appearances.put(APPEARANCE_STREAM_ROLLOVER_KEY, - parseAppearanceDictionary(APPEARANCE_STREAM_ROLLOVER_KEY, - appearance)); - } - // (Optional) The annotation’s down appearance. - // Default value: the value of the N entry. - appearance = library.getObject( - (HashMap) AP, APPEARANCE_STREAM_DOWN_KEY); - if (appearance != null) { - appearances.put(APPEARANCE_STREAM_DOWN_KEY, - parseAppearanceDictionary(APPEARANCE_STREAM_DOWN_KEY, - appearance)); - } - } else { - // new annotation, so setup the default appearance states. - Appearance newAppearance = new Appearance(); - HashMap appearanceDictionary = new HashMap(); - Rectangle2D rect = getUserSpaceRectangle(); - if (rect == null) { - // we need a rect in order to render correctly, bail if not found. - throw new IllegalStateException("Annotation is missing required /rect value"); - } - if (rect.getWidth() <= 1) { - rect.setRect(rect.getX(), rect.getY(), 15, rect.getHeight()); - } - if (rect.getHeight() <= 1) { - rect.setRect(rect.getX(), rect.getY(), rect.getWidth(), 15); - } - appearanceDictionary.put(BBOX_VALUE, new Rectangle2D.Float( - 0, 0, (float) rect.getWidth(), (float) rect.getHeight())); - - newAppearance.addAppearance(APPEARANCE_STREAM_NORMAL_KEY, - new AppearanceState(library, appearanceDictionary)); - appearances.put(APPEARANCE_STREAM_NORMAL_KEY, newAppearance); - currentAppearance = APPEARANCE_STREAM_NORMAL_KEY; - } - } - - private Appearance parseAppearanceDictionary(Name appearanceDictionary, - Object streamOrDictionary) { - - Appearance appearance = new Appearance(); - - // iterate over all of the keys so we can index the various annotation - // state names. - if (streamOrDictionary instanceof HashMap) { - HashMap dictionary = (HashMap) streamOrDictionary; - Set keys = dictionary.keySet(); - Object value; - for (Object key : keys) { - value = dictionary.get(key); - if (value instanceof Reference) { - appearance.addAppearance((Name) key, - new AppearanceState(library, dictionary, - library.getObject((Reference) value))); - } - } - } - // single entry so assign is using the default key name - else { - appearance.addAppearance(appearanceDictionary, - new AppearanceState(library, entries, streamOrDictionary)); - } - return appearance; - } - - /** - * Gets the type of annotation that this dictionary describes. - * For compatibility with the old org.icepdf.core.pobjects.Annotation.getSubType() - * - * @return subtype of annotation - */ - public Name getSubType() { - return library.getName(entries, SUBTYPE_KEY); - } - - public void setSubtype(Name subtype) { - entries.put(SUBTYPE_KEY, subtype); - this.subtype = subtype; - } - - /** - * Gets the annotation rectangle, and defines the location of the annotation on - * the page in default user space units. - * For compatibility with the old org.icepdf.core.pobjects.Annotation.getRectangle() - * - * @return rectangle of annotation - */ - public Rectangle2D.Float getUserSpaceRectangle() { - if (userSpaceRectangle == null) { - Object tmp = getObject(RECTANGLE_KEY); - if (tmp instanceof List) { - userSpaceRectangle = library.getRectangle(entries, RECTANGLE_KEY); - } - } - return userSpaceRectangle; - } - - /** - * Sets the users page rectangle for this annotation action instance - */ - public void setUserSpaceRectangle(Rectangle2D.Float rect) { - if (userSpaceRectangle != null && rect != null) { - userSpaceRectangle = new Rectangle2D.Float(rect.x, rect.y, - rect.width, rect.height); - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(userSpaceRectangle)); - } - } - - public void setBBox(Rectangle bbox) { - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - appearanceState.setBbox(bbox); - } - - public Rectangle2D getBbox() { - Appearance appearance = appearances.get(currentAppearance); - if (appearance != null) { - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - if (appearanceState != null) { - return appearanceState.getBbox(); - } - } - return null; - } - - protected void resetNullAppearanceStream() { - // try and generate an appearance stream. - if (!hasAppearanceStream()) { - Object tmp = getObject(RECTANGLE_KEY); - Rectangle2D.Float rectangle = null; - if (tmp instanceof java.util.List) { - rectangle = library.getRectangle(entries, RECTANGLE_KEY); - } - if (rectangle != null) { - setBBox(rectangle.getBounds()); - } - resetAppearanceStream(new AffineTransform()); - } - } - - public Name getCurrentAppearance() { - return currentAppearance; - } - - public void setCurrentAppearance(Name currentAppearance) { - this.currentAppearance = currentAppearance; - } - - /** - * Creates a Java2D strok from the propties tht make up the BorderStyle object. - * - * @return dashed or solid stoke. - */ - public BasicStroke getBorderStyleStroke() { - if (borderStyle.isStyleDashed()) { - return new BasicStroke( - borderStyle.getStrokeWidth(), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, - borderStyle.getStrokeWidth() * 2.0f, borderStyle.getDashArray(), 0.0f); - } else { - return new BasicStroke(borderStyle.getStrokeWidth()); - } - } - - /** - * Gets the action to be performed when the annotation is activated. - * For compatibility with the old org.icepdf.core.pobjects.Annotation.getAction() - * - * @return action to be activated, if no action, null is returned. - */ - public org.icepdf.core.pobjects.actions.Action getAction() { - Object tmp = library.getDictionary(entries, ACTION_KEY); - // initial parse will likely have the action as a dictionary, so we - // create the new action object on the fly. However it is also possible - // that we are parsing an action that has no type specification and - // thus we can't use the parser to create the new action. - if (tmp != null) { - Action action = Action.buildAction(library, (HashMap) tmp); - // assign reference if applicable - if (action != null && - library.isReference(entries, ACTION_KEY)) { - action.setPObjectReference( - library.getReference(entries, ACTION_KEY)); - } - return action; - } - // subsequent new or edit actions will put in a reference and property - // dictionary entry. - tmp = getObject(ACTION_KEY); - if (tmp != null && tmp instanceof Action) { - return (Action) tmp; - } - return null; - } - - /** - * Adds the specified action to this annotation instance. If the annotation - * instance already has an action then this action replaces it. - *

- * todo: future enhancement add support of next/muliple action chains. - * - * @param action action to add to this annotation. This action must - * be created using the the ActionFactory in order to correctly setup - * the Pobject reference. - * @return action that was added to Annotation, null if it was not success - * fully added. - */ - public Action addAction(Action action) { - - // if no object ref we bail early. - if (action.getPObjectReference() == null) { - logger.severe("Addition of action was rejected null Object reference " - + action); - return null; - } - - // gen instance of state manager - StateManager stateManager = library.getStateManager(); - - // check if there is a 'dest' entry, if so we need to add this as a new - // action, flag it for later processing. - boolean isDestKey = getObject(LinkAnnotation.DESTINATION_KEY) != null; - - // check the annotation dictionary for an instance of an existing action - if (getObject(ACTION_KEY) != null) { - // if found we will add the new action at the beginning of the - // next chain. - boolean isReference = library.isReference(getEntries(), - ACTION_KEY); - // we have a next action that is an object, mark it for delete. - // Because its a reference no need to flag the annotation as changed. - if (isReference) { - // mark this action for delete. - Action oldAction = (Action) action.getObject(ACTION_KEY); - oldAction.setDeleted(true); - stateManager.addChange(new PObject(oldAction, - oldAction.getPObjectReference())); - } - // not a reference, we have an inline dictionary and we'll be - // clearing it later, so we only need to add this annotation - // to the state manager. - else { - getEntries().remove(ACTION_KEY); - stateManager.addChange(new PObject(this, getPObjectReference())); - } - } - // add the new action as per usual - getEntries().put(ACTION_KEY, action.getPObjectReference()); - stateManager.addChange(new PObject(this, getPObjectReference())); - - // if this is a link annotation and there is a dest, we need to remove - // as it is not allowed once an action has bee added. - if (isDestKey && this instanceof LinkAnnotation) { - // remove the dest key from the dictionary - this.getEntries().remove(LinkAnnotation.DESTINATION_KEY); - // mark the annotation as changed. - stateManager.addChange(new PObject(this, getPObjectReference())); - } - - // add the new action to the state manager. - action.setNew(true); - stateManager.addChange(new PObject(action, action.getPObjectReference())); - // add it to the library so we can get it again. - library.addObject(action, action.getPObjectReference()); - - return action; - } - - /** - * Deletes the annotation action specified as a paramater. If an instance - * of the specified action can not be found, no delete is make. - * - * @param action action to remove - * @return true if the delete was successful, false otherwise. - */ - public boolean deleteAction(Action action) { - - // gen instance of state manager - StateManager stateManager = library.getStateManager(); - - if (getObject(ACTION_KEY) != null) { - // mark this action for delete. - Action currentAction = getAction(); - if (currentAction.similar(action)) { - // clear the action key for the annotation and add it as changed. - // add the new action to the annotation - getEntries().remove(ACTION_KEY); - currentAction.setDeleted(true); - // mark the action as changed. - stateManager.addChange(new PObject(currentAction, - currentAction.getPObjectReference())); - // mark the action as change.d - stateManager.addChange(new PObject(this, getPObjectReference())); - return true; - } - } - return false; - } - - /** - * Update the current annotation action with this entry. This is very similar - * to add but this method will return false if there was no previous annotation. - * In such a case a call to addAction should be made. - * - * @param action action to update - * @return true if the update was successful, othere; false. - */ - public boolean updateAction(Action action) { - // get instance of state manager - StateManager stateManager = library.getStateManager(); - if (getObject(ACTION_KEY) != null) { - Action currentAction = getAction(); - // check if we are updating an existing instance - if (!currentAction.similar(action)) { - stateManager.addChange(new PObject(action, - action.getPObjectReference())); - currentAction.setDeleted(true); - stateManager.addChange(new PObject(currentAction, - currentAction.getPObjectReference())); - } - // add the action to the annotation - getEntries().put(ACTION_KEY, action.getPObjectReference()); - stateManager.addChange(new PObject(action, - action.getPObjectReference())); - - return true; - } - return false; - } - - public boolean allowScreenNormalMode() { - return allowScreenOrPrintRenderingOrInteraction() && !getFlagNoView(); - } - - public boolean allowScreenRolloverMode() { - return allowScreenOrPrintRenderingOrInteraction() && !(getFlagNoView() - && !getFlagToggleNoView()) && !getFlagReadOnly(); - } - - public boolean allowScreenDownMode() { - return allowScreenOrPrintRenderingOrInteraction() && !(getFlagNoView() && - !getFlagToggleNoView()) && !getFlagReadOnly(); - } - - public boolean allowPrintNormalMode() { - return allowScreenOrPrintRenderingOrInteraction() && getFlagPrint(); - } - - public boolean allowAlterProperties() { - return !getFlagLocked(); - } - - public BorderStyle getBorderStyle() { - return borderStyle; - } - - public void setBorderStyle(BorderStyle borderStyle) { - this.borderStyle = borderStyle; - entries.put(Annotation.BORDER_STYLE_KEY, this.borderStyle); - } - - @SuppressWarnings("unchecked") - public List getBorder() { - return border; - } - - public Object getParentAnnotation() { - Annotation parent = null; - - Object ob = getObject(PARENT_KEY); - if (ob instanceof Reference) - ob = library.getObject((Reference) ob); - if (ob instanceof Annotation) - parent = (Annotation) ob; - else if (ob instanceof HashMap) - return FieldDictionaryFactory.buildField(library, (HashMap) ob); - - return parent; - } - - public Page getPage() { - Page page = (Page) getObject(PARENT_PAGE_KEY); - if (page == null) { - Object annot = getParentAnnotation(); - if (annot instanceof Annotation) - page = ((Annotation) annot).getPage(); - } - return page; - } - - /** - * Gets the Link type, can be either VISIBLE_RECTANGLE or - * INVISIBLE_RECTANGLE, it all depends on the if the border or BS has - * border width > 0. - * - * @return VISIBLE_RECTANGLE if the annotation has a visible borde, otherwise - * INVISIBLE_RECTANGLE - */ - public int getBorderType() { - // border style has W value for border with - if (borderStyle != null) { - if (borderStyle.getStrokeWidth() > 0) { - return VISIBLE_RECTANGLE; - } - } - // look for a border, 0,0,1 has one, 0,0,0 doesn't - else if (border != null) { - if (border.size() >= 3 && ((Number) border.get(2)).floatValue() > 0) { - return VISIBLE_RECTANGLE; - } - } - // should never happen - return INVISIBLE_RECTANGLE; - } - - /** - * Gets the Annotation border style for the given annotation. If no - * annotation line style can be found the default value of BORDER_STYLE_SOLID - * is returned. Otherwise the bordStyle and border dictionaries are used - * to deduse a line style. - * - * @return BorderSTyle line constants. - */ - public Name getLineStyle() { - // check for border style - if (borderStyle != null) { - return borderStyle.getBorderStyle(); - } - // check the border entry, will be solid or dashed - else if (border != null) { - if (border.size() > 3) { - return BorderStyle.BORDER_STYLE_DASHED; - } else if (((Number) border.get(2)).floatValue() > 1) { - return BorderStyle.BORDER_STYLE_SOLID; - } - } - // default value - return BorderStyle.BORDER_STYLE_SOLID; - } - - /** - * Gets the line thickness assoicated with this annotation. - * - * @return point value used when drawing line thickness. - */ - public float getLineThickness() { - // check for border style - if (borderStyle != null) { - return borderStyle.getStrokeWidth(); - } - // check the border entry, will be solid or dashed - else if (border != null) { - if (border.size() >= 3) { - return ((Number) border.get(2)).floatValue(); - } - } - return 0; - } - - /** - * Checks to see if the annotation has defined a drawable border width. - * - * @return true if a border will be drawn; otherwise, false. - */ - public boolean isBorder() { - boolean borderWidth = false; - Object border = getObject(BORDER_KEY); - if (border != null && border instanceof List) { - List borderProps = (List) border; - if (borderProps.size() == 3) { - borderWidth = ((Number) borderProps.get(2)).floatValue() > 0; - } - } - return (getBorderStyle() != null && - getBorderStyle().getStrokeWidth() > 0) || borderWidth; - } - - public void render(Graphics2D origG, int renderHintType, - float totalRotation, float userZoom, - boolean tabSelected) { - if (!allowScreenOrPrintRenderingOrInteraction()) - return; - if (renderHintType == GraphicsRenderingHints.SCREEN && !allowScreenNormalMode()) - return; - if (renderHintType == GraphicsRenderingHints.PRINT && !allowPrintNormalMode()) - return; - -//System.out.println("render(-) " + this); - Rectangle2D.Float rect = getUserSpaceRectangle(); -// Show original ractangle, without taking into consideration NoZoom and NoRotate -//System.out.println("Original rectangle: " + rect); -//origG.setColor( Color.blue ); -//origG.draw( rect ); -//origG.setColor( Color.red ); -//Line2D.Double topLine = new Line2D.Double( rect.getMinX(), rect.getMaxY(), rect.getMaxX(), rect.getMaxY() ); -//origG.draw( topLine ); -//origG.setColor( Color.yellow ); -//Line2D.Double bottomLine = new Line2D.Double( rect.getMinX(), rect.getMinY(), rect.getMaxX(), rect.getMinY() ); -//origG.draw( bottomLine ); - - AffineTransform oldAT = origG.getTransform(); - Shape oldClip = origG.getClip(); - Composite oldComp = origG.getComposite(); - - // Simply uncomment the //// lines to use a different Graphics object - Graphics2D g = origG; - ////Graphics2D g = (Graphics2D) origG.create(); - - AffineTransform at = new AffineTransform(oldAT); - // translate to annotation location, as all coordinates "should" be relative to this point. - at.translate(rect.getMinX(), rect.getMinY()); - - boolean noRotate = getFlagNoRotate(); - if (noRotate) { - float unRotation = -totalRotation; - while (unRotation < 0.0f) - unRotation += 360.0f; - while (unRotation > 360.0f) - unRotation -= 360.0f; - if (unRotation == -0.0f) - unRotation = 0.0f; - - if (unRotation != 0.0) { - double radians = Math.toRadians(unRotation); // unRotation * Math.PI / 180.0 - AffineTransform rotationTransform = - AffineTransform.getRotateInstance(radians); - Point2D.Double origTopLeftCorner = new Point2D.Double(0.0, Math.abs(rect.getHeight())); - Point2D rotatedTopLeftCorner = rotationTransform.transform(origTopLeftCorner, null); - at.translate(origTopLeftCorner.getX() - rotatedTopLeftCorner.getX(), - origTopLeftCorner.getY() - rotatedTopLeftCorner.getY()); - at.rotate(radians); - } - } - - boolean noZoom = getFlagNoZoom(); - if (noZoom) { - double scaleY = Math.abs(at.getScaleY()); - if (scaleY != 1.0) { - double scaleX = Math.abs(at.getScaleX()); - double rectHeight = Math.abs(rect.getHeight()); - double resizedY = rectHeight * ((scaleY - 1.0) / scaleY); - at.translate(0.0, resizedY); - at.scale(1.0 / scaleX, 1.0 / scaleY); - } - } - - GraphicsRenderingHints grh = GraphicsRenderingHints.getDefault(); - g.setRenderingHints(grh.getRenderingHints(renderHintType)); - g.setTransform(at); - Shape preAppearanceStreamClip = g.getClip(); - g.clip(deriveDrawingRectangle()); - - renderAppearanceStream(g); - - g.setTransform(at); - g.setClip(preAppearanceStreamClip); - - if (tabSelected) { - renderBorderTabSelected(g); - } else { - renderBorder(g); - } - - g.setTransform(oldAT); - g.setClip(oldClip); - g.setComposite(oldComp); - - ////g.dispose(); - -// Show the top left corner, that NoZoom and NoRotate annotations cling to -//origG.setColor( Color.blue ); -//Rectangle2D.Double topLeft = new Rectangle2D.Double( -// rect.getMinX(), rect.getMaxY()-3, 3, 3 ); -//origG.fill( topLeft ); - } - - protected void renderAppearanceStream(Graphics2D g) { - Appearance appearance = appearances.get(currentAppearance); - if (appearance == null) return; - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - if (appearanceState.getShapes() != null) { - - AffineTransform matrix = appearanceState.getMatrix(); - Rectangle2D bbox = appearanceState.getBbox(); - -// g.setColor( Color.blue ); -// Rectangle2D.Float newRect = deriveDrawingRectangle(); -// g.draw( newRect ); - - // step 1. appearance bounding box (BBox) is transformed, using - // Matrix, to produce a quadrilateral with arbitrary orientation. - Rectangle2D tBbox = matrix.createTransformedShape(bbox).getBounds2D(); - - // Step 2. matrix a is computed that scales and translates the - // transformed appearance box (tBbox) to align with the edges of - // the annotation's rectangle (Ret). - Rectangle2D rect = getUserSpaceRectangle(); - AffineTransform tAs = AffineTransform.getScaleInstance( - (rect.getWidth() / tBbox.getWidth()), - (rect.getHeight() / tBbox.getHeight())); - - // check for identity transformation - // we have to be careful in such as case as the coordinates of the annotation may actually - // be in page space. If the rectangle in page pace is more or less the same location - // as the tbbox then we know the annotation coordinate space must also be in page space. - // Thus we shift back to page space. - if (rect.getMinX() == tBbox.getMinX() && rect.getMinY() == tBbox.getMinY()) { - tAs.setTransform(tAs.getScaleX(), tAs.getShearX(), tAs.getShearY(), - tAs.getScaleY(), -rect.getX(), -rect.getY()); - } else { - tAs.setTransform(tAs.getScaleX(), tAs.getShearX(), tAs.getShearY(), - tAs.getScaleY(), -tBbox.getX(), -tBbox.getY()); - } - // Step 3. matrix is concatenated with A to form a matrix AA - // that maps from the appearance's coordinate system to the - // annotation's rectangle in default user space. - tAs.concatenate(matrix); - g.transform(tAs); - - AffineTransform preAf = g.getTransform(); - // regular paint - try { - appearanceState.getShapes().paint(g); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Page Annotation Painting interrupted."); - } - - g.setTransform(preAf); - } - - } - - protected void renderBorder(Graphics2D g) { -// if( false ) { -// float width = 1.0f; -// Rectangle2D.Float jrect = deriveBorderDrawingRectangle( width ); -// g.setColor( Color.red ); -// g.setStroke( new BasicStroke(width) ); -// g.draw( jrect ); -// return; -// } - // we don't paint some borders as the BS has a different meanings. - if (this instanceof SquareAnnotation || - this instanceof CircleAnnotation || - this instanceof LineAnnotation || - this instanceof FreeTextAnnotation || - this instanceof InkAnnotation) { - return; - } - - Color borderColor = getColor(); - if (borderColor != null) { - g.setColor(borderColor); - } - - BorderStyle bs = getBorderStyle(); - if (bs != null) { - float width = bs.getStrokeWidth(); - if (width > 0.0f && borderColor != null && canDrawBorder) { - Rectangle2D.Float jrect = deriveBorderDrawingRectangle(width); - - if (bs.isStyleSolid()) { - g.setStroke(new BasicStroke(width)); - g.draw(jrect); - } else if (bs.isStyleDashed()) { - BasicStroke stroke = new BasicStroke( - width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, - width * 2.0f, bs.getDashArray(), 0.0f); - g.setStroke(stroke); - g.draw(jrect); - } else if (bs.isStyleBeveled()) { - jrect = deriveDrawingRectangle(); - - g.setStroke(new BasicStroke(1.0f)); - Line2D.Double line; - - // Upper top - g.setColor(BorderStyle.LIGHT); - line = new Line2D.Double( // Top line - jrect.getMinX() + 1.0, jrect.getMaxY() - 1.0, jrect.getMaxX() - 2.0, jrect.getMaxY() - 1.0); - g.draw(line); - line = new Line2D.Double( // Left line - jrect.getMinX() + 1.0f, jrect.getMinY() + 2.0, jrect.getMinX() + 1.0f, jrect.getMaxY() - 1.0); - g.draw(line); - - // Inner top - g.setColor(BorderStyle.LIGHTEST); - line = new Line2D.Double( // Top line - jrect.getMinX() + 2.0, jrect.getMaxY() - 2.0, jrect.getMaxX() - 3.0, jrect.getMaxY() - 2.0); - g.draw(line); - line = new Line2D.Double( // Left line - jrect.getMinX() + 2.0f, jrect.getMinY() + 3.0, jrect.getMinX() + 2.0f, jrect.getMaxY() - 2.0); - g.draw(line); - - // Inner bottom - g.setColor(BorderStyle.DARK); - line = new Line2D.Double( // Bottom line - jrect.getMinX() + 2.0, jrect.getMinY() + 2.0, jrect.getMaxX() - 2.0, jrect.getMinY() + 2.0); - g.draw(line); - line = new Line2D.Double( // Right line - jrect.getMaxX() - 2.0f, jrect.getMinY() + 2.0, jrect.getMaxX() - 2.0f, jrect.getMaxY() - 2.0); - g.draw(line); - - // Lower bottom - g.setColor(BorderStyle.DARKEST); - line = new Line2D.Double( // Bottom line - jrect.getMinX() + 1.0, jrect.getMinY() + 1.0, jrect.getMaxX() - 1.0, jrect.getMinY() + 1.0); - g.draw(line); - line = new Line2D.Double( // Right line - jrect.getMaxX() - 1.0f, jrect.getMinY() + 1.0, jrect.getMaxX() - 1.0f, jrect.getMaxY() - 1.0); - g.draw(line); - } else if (bs.isStyleInset()) { - jrect = deriveDrawingRectangle(); - - g.setStroke(new BasicStroke(1.0f)); - Line2D.Double line; - - // Upper top - g.setColor(BorderStyle.DARK); - line = new Line2D.Double( // Top line - jrect.getMinX() + 1.0, jrect.getMaxY() - 1.0, jrect.getMaxX() - 1.0, jrect.getMaxY() - 1.0); - g.draw(line); - line = new Line2D.Double( // Left line - jrect.getMinX() + 1.0f, jrect.getMinY() + 1.0, jrect.getMinX() + 1.0f, jrect.getMaxY() - 1.0); - g.draw(line); - - // Inner top - g.setColor(BorderStyle.DARKEST); - line = new Line2D.Double( // Top line - jrect.getMinX() + 2.0, jrect.getMaxY() - 2.0, jrect.getMaxX() - 2.0, jrect.getMaxY() - 2.0); - g.draw(line); - line = new Line2D.Double( // Left line - jrect.getMinX() + 2.0f, jrect.getMinY() + 2.0, jrect.getMinX() + 2.0f, jrect.getMaxY() - 2.0); - g.draw(line); - - // Inner bottom - g.setColor(BorderStyle.LIGHTEST); - line = new Line2D.Double( // Bottom line - jrect.getMinX() + 3.0, jrect.getMinY() + 2.0, jrect.getMaxX() - 2.0, jrect.getMinY() + 2.0); - g.draw(line); - line = new Line2D.Double( // Right line - jrect.getMaxX() - 2.0f, jrect.getMinY() + 2.0, jrect.getMaxX() - 2.0f, jrect.getMaxY() - 3.0); - g.draw(line); - - // Lower bottom - g.setColor(BorderStyle.LIGHT); - line = new Line2D.Double( // Bottom line - jrect.getMinX() + 2.0, jrect.getMinY() + 1.0, jrect.getMaxX() - 1.0, jrect.getMinY() + 1.0); - g.draw(line); - line = new Line2D.Double( // Right line - jrect.getMaxX() - 1.0f, jrect.getMinY() + 1.0, jrect.getMaxX() - 1.0f, jrect.getMaxY() - 2.0); - g.draw(line); - } else if (bs.isStyleUnderline()) { - g.setStroke(new BasicStroke(width)); - Line2D.Double line = new Line2D.Double( - jrect.getMinX(), jrect.getMinY(), jrect.getMaxX(), jrect.getMinY()); - g.draw(line); - } - } - } else { - List borderVector = (List) getObject(BORDER_KEY); - if (borderVector != null) { - if (borderColor != null) { - float horizRadius = 0.0f; - float vertRadius = 0.0f; - float width = 1.0f; - float[] dashArray = null; - if (borderVector.size() >= 1) - horizRadius = ((Number) borderVector.get(0)).floatValue(); - if (borderVector.size() >= 2) - vertRadius = ((Number) borderVector.get(1)).floatValue(); - if (borderVector.size() >= 3) - width = ((Number) borderVector.get(2)).floatValue(); - if (borderVector.size() >= 4) { - Object dashObj = borderVector.get(3); - // I guess some encoders like having fun with us, - // and feed a number when a number-array is appropriate. The problem - // is that for the specific PDF given, apparently no border is to be - // drawn, especially not the hugely thinck one described. So, - // instead of interpretting the 4th element (Number) into a Vector, - // I'm just not going to do the border if it's the Number. I know, hack. - // The only theory I have is that LinkAnnotation defaults the border - // color to black, when maybe it should be to null, but that could - // change a _lot_ of stuff, so I won't touch it now. - if (dashObj instanceof Number) { - // Disable border drawing - width = 0.0f; - } else if (dashObj instanceof List) { - List dashVector = (List) borderVector.get(3); - int sz = dashVector.size(); - dashArray = new float[sz]; - for (int i = 0; i < sz; i++) { - Number num = (Number) dashVector.get(i); - dashArray[i] = num.floatValue(); - } - } - } - - if (width > 0.0f) { - Rectangle2D.Float jrect = deriveBorderDrawingRectangle(width); - RoundRectangle2D.Double roundRect = new RoundRectangle2D.Double( - jrect.getX(), jrect.getY(), jrect.getWidth(), jrect.getHeight(), - horizRadius, vertRadius); - BasicStroke stroke = new BasicStroke( - width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, - 10.0f, dashArray, 0.0f); - g.setStroke(stroke); - g.draw(roundRect); - } - } - } else { - // Draw a solid rectangle, 1 pixel wide - if (borderColor != null && SUBTYPE_LINK.equals(subtype)) { - float width = 1.0f; - Rectangle2D.Float jrect = deriveBorderDrawingRectangle(width); - g.setStroke(new BasicStroke(width)); - g.draw(jrect); - } - } - } - } - - protected void renderBorderTabSelected(Graphics2D g) { - float width = 1.0f; - Rectangle2D.Float jrect = deriveBorderDrawingRectangle(width); - g.setColor(Color.black); - float[] dashArray = new float[]{2.0f}; - BasicStroke stroke = new BasicStroke( - width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, - 10.0f, dashArray, 0.0f); - g.setStroke(stroke); - g.draw(jrect); - } - - /** - * Gest the RGB colour of the annotation used for the following purposes: - *

    - *
  • the background of the annotaiton's icon when closed
  • - *
  • the title bar of the anntoation's pop-up window
  • - *
  • the border of a link annotation
  • - *
- * - * @return A Color for the border, or null if none is to be used - */ - public Color getColor() { - return color; - } - - /** - * Sets the Annotation colour and underlying - * - * @param color new colour value - */ - public void setColor(Color color) { - this.color = new Color(color.getRGB()); - // put colour back in to the dictionary - float[] compArray = new float[3]; - this.color.getColorComponents(compArray); - List colorValues = new ArrayList(compArray.length); - for (float comp : compArray) { - colorValues.add(comp); - } - entries.put(Annotation.COLOR_KEY, colorValues); - } - - protected Rectangle2D.Float deriveDrawingRectangle() { - Rectangle2D.Float origRect = getUserSpaceRectangle(); - Rectangle2D.Float jrect = new Rectangle2D.Float(origRect.x, origRect.y, - origRect.width, origRect.height); - jrect.x = 0.0f; - jrect.y = 0.0f; - return jrect; - } - - private Rectangle2D.Float deriveBorderDrawingRectangle(float borderWidth) { - Rectangle2D.Float jrect = deriveDrawingRectangle(); - - float halfBorderWidth = borderWidth / 2.0f; - double minX = jrect.getMinX() + halfBorderWidth; - double minY = jrect.getMinY() + halfBorderWidth; - double maxX = jrect.getMaxX() - halfBorderWidth; - double maxY = jrect.getMaxY() - halfBorderWidth; - jrect.setFrameFromDiagonal(minX, minY, maxX, maxY); - return jrect; - } - - /** - * @return Whether this annotation may be shown in any way to the user - */ - public boolean allowScreenOrPrintRenderingOrInteraction() { - // Based off of the annotation flags' Invisible and Hidden values - if (getFlagHidden()) - return false; - return !(getFlagInvisible() && isSupportedAnnotationType()); - } - - /** - * The PDF spec defines rules for displaying annotation subtypes that the viewer - * does not recognise. But, from a product point of view, we may or may not - * wish to make a best attempt at showing an unsupported annotation subtype, - * as that may make users think we're quality deficient, instead of - * feature deficient. - * Subclasses should override this, and return true, indicating that that - * particular annotation is supported. - * - * @return true, if this annotation is supported; else, false. - */ - protected boolean isSupportedAnnotationType() { - return true; - } - - public boolean getFlagInvisible() { - return ((getInt(FLAG_KEY) & FLAG_INVISIBLE) != 0); - } - - public boolean getFlagHidden() { - return ((getInt(FLAG_KEY) & FLAG_HIDDEN) != 0); - } - - public boolean getFlagPrint() { - return ((getInt(FLAG_KEY) & FLAG_PRINT) != 0); - } - - public boolean getFlagNoZoom() { - return ((getInt(FLAG_KEY) & FLAG_NO_ZOOM) != 0); - } - - public boolean getFlagNoRotate() { - return ((getInt(FLAG_KEY) & FLAG_NO_ROTATE) != 0); - } - - public boolean getFlagNoView() { - return ((getInt(FLAG_KEY) & FLAG_NO_VIEW) != 0); - } - - public boolean getFlagReadOnly() { - return ((getInt(FLAG_KEY) & FLAG_READ_ONLY) != 0); - } - - public boolean getFlagToggleNoView() { - return ((getInt(FLAG_KEY) & FLAG_TOGGLE_NO_VIEW) != 0); - } - - public boolean getFlagLockedContents() { - return ((getInt(FLAG_KEY) & FLAG_LOCKED_CONTENTS) != 0); - } - - public boolean getFlagLocked() { - return ((getInt(FLAG_KEY) & FLAG_LOCKED) != 0); - } - - /** - * Set the specified flag key to either enabled or disabled. - * - * @param flagKey flag key to set. - * @param enable true or false key value. - */ - public void setFlag(final int flagKey, boolean enable) { - int flag = getInt(FLAG_KEY); - boolean isEnabled = (flag & flagKey) != 0; - if (!enable && isEnabled) { - flag = flag ^ flagKey; - entries.put(FLAG_KEY, flag); - } else if (enable && !isEnabled) { - flag = flag | flagKey; - entries.put(FLAG_KEY, flag); - } - } - - public void setModifiedDate(String modifiedDate) { - setString(M_KEY, modifiedDate); - this.modifiedDate = new PDate(securityManager, modifiedDate); - } - - public boolean hasAppearanceStream() { - return library.getObject(entries, APPEARANCE_STREAM_KEY) != null; - } - - /** - * Returns the appearance stream as defined by the AP dictionary key N - * - * @return N appearance stream or null. - */ - public Stream getAppearanceStream() { - Object AP = getObject(APPEARANCE_STREAM_KEY); - if (AP instanceof HashMap) { - Object N = library.getObject( - (HashMap) AP, APPEARANCE_STREAM_NORMAL_KEY); - if (N instanceof HashMap) { - Object AS = getObject(APPEARANCE_STATE_KEY); - if (AS != null && AS instanceof Name) - N = library.getObject((HashMap) N, (Name) AS); - } - // n should be a Form but we have a few cases of Stream - if (N instanceof Stream) { - return (Stream) N; - } - } - return null; - } - - /** - * Gets the Appearance Form object associated with the annotation's appearances. Many encoders do no create - * the stream if there is no data in the widget. This method insure that an appearance XObject/Form is - * created. The object new object is not added to the state manager. - * - * @return appearance for annotation. - */ - public Form getOrGenerateAppearanceForm() { - StateManager stateManager = library.getStateManager(); - Form form = null; - if (hasAppearanceStream()) { - Stream stream = getAppearanceStream(); - if (stream instanceof Form) { - form = (Form) stream; - } else if (stream != null) { - // build out an appearance stream, corner case iText 2.1 - // didn't correctly set type = form on the appearance stream obj. - form = new Form(library, stream.getEntries(), null); - form.setPObjectReference(stream.getPObjectReference()); - form.setRawBytes(stream.getDecodedStreamBytes()); - form.init(); - } - }// else a stream, we won't support this for annotations. - else { - // create a new xobject/form object - HashMap formEntries = new HashMap(); - formEntries.put(Form.TYPE_KEY, Form.TYPE_VALUE); - formEntries.put(Form.SUBTYPE_KEY, Form.SUB_TYPE_VALUE); - form = new Form(library, formEntries, null); - form.setPObjectReference(stateManager.getNewReferencNumber()); - library.addObject(form, form.getPObjectReference()); - } - return form; - } - - /** - * Create or update a Form's content stream. - * - * @param shapes shapes to associate with the appearance stream. - * @param bbox bound box. - * @param matrix form space. - * @param rawBytes raw bytes of string data making up the content stream. - * @return - */ - public Form updateAppearanceStream(Shapes shapes, Rectangle2D bbox, AffineTransform matrix, byte[] rawBytes) { - // update the appearance stream - // create/update the appearance stream of the xObject. - StateManager stateManager = library.getStateManager(); - Form form; - if (hasAppearanceStream() && getAppearanceStream() instanceof Form) { - form = (Form) getAppearanceStream(); - // else a stream, we won't support this for annotations. - } else { - // create a new xobject/form object - HashMap formEntries = new HashMap(); - formEntries.put(Form.TYPE_KEY, Form.TYPE_VALUE); - formEntries.put(Form.SUBTYPE_KEY, Form.SUB_TYPE_VALUE); - form = new Form(library, formEntries, null); - form.setPObjectReference(stateManager.getNewReferencNumber()); - library.addObject(form, form.getPObjectReference()); - } - - if (form != null && shapes != null && rawBytes != null) { - Rectangle2D formBbox = new Rectangle2D.Float((float) bbox.getX(), (float) bbox.getY(), - (float) bbox.getWidth(), (float) bbox.getHeight()); - form.setAppearance(shapes, matrix, formBbox); - - stateManager.addChange(new PObject(form, form.getPObjectReference())); - // update the AP's stream bytes so contents can be written out - form.setRawBytes(rawBytes); - HashMap appearanceRefs = new HashMap(); - appearanceRefs.put(APPEARANCE_STREAM_NORMAL_KEY, form.getPObjectReference()); - entries.put(APPEARANCE_STREAM_KEY, appearanceRefs); - - // compress the form object stream. - if (compressAppearanceStream) { - form.getEntries().put(Stream.FILTER_KEY, new Name("FlateDecode")); - } else { - form.getEntries().remove(Stream.FILTER_KEY); - } - } - return form; - } - - - public String getContents() { - content = getString(CONTENTS_KEY); - return content; - } - - public void setContents(String content) { - this.content = setString(CONTENTS_KEY, content); - } - - /** - * Gets a known string value from the annotation dictionary, decryption will be applied as needed. - * - * @param key dictionary key value to fine. - * @return value of key if any, empty string if null; - */ - protected String getString(final Name key) { - Object value = library.getObject(entries, key); - if (value instanceof StringObject) { - StringObject text = (StringObject) value; - return Utils.convertStringObject(library, text); - } else if (value instanceof String) { - return (String) value; - } else { - return ""; - } - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("ANNOTATION= {"); - Set keys = entries.keySet(); - for (Object key : keys) { - Object value = entries.get(key); - sb.append(key.toString()); - sb.append('='); - if (value == null) - sb.append("null"); - else if (value instanceof StringObject) - sb.append(((StringObject) value).getDecryptedLiteralString(library.getSecurityManager())); - else - sb.append(value.toString()); - sb.append(','); - } - sb.append('}'); - if (getPObjectReference() != null) { - sb.append(" "); - sb.append(getPObjectReference()); - } - for (int i = sb.length() - 1; i >= 0; i--) { - if (sb.charAt(i) < 32 || sb.charAt(i) >= 127) - sb.deleteCharAt(i); - } - return sb.toString(); - } - - public void syncBBoxToUserSpaceRectangle(Rectangle2D bbox) { - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - - Rectangle2D tBbox = appearanceState.getMatrix().createTransformedShape(bbox).getBounds2D(); - setUserSpaceRectangle(new Rectangle2D.Float( - (float) tBbox.getX(), (float) tBbox.getY(), - (float) tBbox.getWidth(), (float) tBbox.getHeight())); - } - - public abstract void resetAppearanceStream(double dx, double dy, AffineTransform pageSpace); - - public void resetAppearanceStream(AffineTransform pageSpace) { - resetAppearanceStream(0, 0, pageSpace); - } - - public Shapes getShapes() { - Appearance appearance = appearances.get(currentAppearance); - if (appearance != null) { - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - if (appearanceState != null) { - return appearanceState.getShapes(); - } - } - return null; - } - - public HashMap getAppearances() { - return appearances; - } - - public void addPropertyChangeListener( - PropertyChangeListener listener) { - synchronized (this) { - if (listener == null) { - return; - } - if (changeSupport == null) { - changeSupport = new PropertyChangeSupport(this); - } - changeSupport.addPropertyChangeListener(listener); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/AnnotationFactory.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/AnnotationFactory.java deleted file mode 100644 index bc95fa1b54..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/AnnotationFactory.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.logging.Logger; - -/** - * Factory for build annotations. - *

- * Note: Currently only Link annotations are supported. - * - * @since 4.0 - */ -public class AnnotationFactory { - - private static final Logger logger = - Logger.getLogger(AnnotationFactory.class.toString()); - - /** - * Creates a new Annotation object using properties from the annotationState - * paramater. If no annotaitonState is provided a LinkAnnotation is returned - * with with a black border. The rect specifies where the annotation should - * be located in user space. - *

- * This call adds the new Annotation object to the document library as well - * as the document StateManager. - * - * @param library library to register annotation with - * @param subType type of annotation to create - * @param rect bounds of new annotation specified in user space. - * @return new annotation object with the same properties as the one - * specified in annotaiton state. - */ - public static Annotation buildAnnotation(Library library, - final Name subType, - Rectangle rect) { - // build up a link annotation - if (subType.equals(Annotation.SUBTYPE_LINK)) { - return LinkAnnotation.getInstance(library, rect); - } - // highlight version of a TextMarkup annotation. - else if (subType.equals(TextMarkupAnnotation.SUBTYPE_HIGHLIGHT) || - subType.equals(TextMarkupAnnotation.SUBTYPE_STRIKE_OUT) || - subType.equals(TextMarkupAnnotation.SUBTYPE_UNDERLINE)) { - return TextMarkupAnnotation.getInstance(library, rect, - subType); - } else if (subType.equals(Annotation.SUBTYPE_LINE)) { - return LineAnnotation.getInstance(library, rect); - } else if (subType.equals(Annotation.SUBTYPE_SQUARE)) { - return SquareAnnotation.getInstance(library, rect); - } else if (subType.equals(Annotation.SUBTYPE_CIRCLE)) { - return CircleAnnotation.getInstance(library, rect); - } else if (subType.equals(Annotation.SUBTYPE_INK)) { - return InkAnnotation.getInstance(library, rect); - } else if (subType.equals(Annotation.SUBTYPE_FREE_TEXT)) { - return FreeTextAnnotation.getInstance(library, rect); - } else if (subType.equals(Annotation.SUBTYPE_TEXT)) { - return TextAnnotation.getInstance(library, rect); - } else if (subType.equals(Annotation.SUBTYPE_POPUP)) { - return PopupAnnotation.getInstance(library, rect); - } else { - logger.warning("Unsupported Annotation type. "); - return null; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/Appearance.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/Appearance.java deleted file mode 100644 index 687b9248ed..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/Appearance.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.Name; - -import java.util.HashMap; - -/** - * An appearance dictionary dictionary entry for N, R or D can be associated - * with one or more appearance streams. For example a Widget btn annotation - * can have an /ON an /Off state. This class sill store one or more - * named appearance streams for a dictionary entry. - * - * @since 5.1 - */ -public class Appearance { - - private HashMap appearance; - - private Name selectedName = Annotation.APPEARANCE_STREAM_NORMAL_KEY; - private Name offName = new Name("Off"); - private Name onName = new Name("Yes"); - - /** - * Create a new instance of an Appearance stream. - */ - public Appearance() { - appearance = new HashMap(2); - } - - public boolean hasAlternativeAppearance() { - return offName != null || onName != null; - } - - public void addAppearance(Name name, AppearanceState appearanceState) { - appearance.put(name, appearanceState); - if (name.getName().toLowerCase().equals("off")) { - offName = name; - } else { - onName = name; - } - } - - public Name getOffName() { - return offName; - } - - public Name getOnName() { - return onName; - } - - public Name getSelectedName() { - return selectedName; - } - - public void setSelectedName(Name selectedName) { - this.selectedName = selectedName; - } - - public AppearanceState getSelectedAppearanceState() { - AppearanceState state = appearance.get(selectedName); - return state; - } - - public AppearanceState getAppearanceState(Name name) { - AppearanceState state = appearance.get(name); - return state; - } - - /** - * Updates or adds the APPEARANCE_STATE_KEY with the currently selected state. - * - * @param entries parent annotation dictionary to update. - */ - protected void updateAppearanceDictionary(HashMap entries) { - entries.put(Annotation.APPEARANCE_STATE_KEY, selectedName); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/AppearanceState.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/AppearanceState.java deleted file mode 100644 index d5543a6cba..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/AppearanceState.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.acroform.InteractiveForm; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.content.ContentParser; -import org.icepdf.core.util.content.ContentParserFactory; - -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * An appearance dictionary dictionary entry for N, R or D can be associated - * with one or more appearance streams. For example a Widget btn annotation - * can have an /ON and /Off state. This class represents one of the named states. - * The class Appearance stores these named Appearance states. - * - * @since 5.1 - */ -public class AppearanceState extends Dictionary { - - private static final Logger logger = - Logger.getLogger(AppearanceState.class.toString()); - - // shapes form appearance stream - protected Shapes shapes; - protected AffineTransform matrix; - protected Rectangle2D bbox; - protected String originalContentStream; - protected Resources resources; - - public AppearanceState(Library library, HashMap entries, Object streamOrDictionary) { - super(library, entries); - if (streamOrDictionary instanceof Reference) { - streamOrDictionary = library.getObject((Reference) streamOrDictionary); - } - // gather the state info for the appearance. - if (streamOrDictionary instanceof Form) { - Form form = (Form) streamOrDictionary; - form.init(); - originalContentStream = new String(((Form) streamOrDictionary).getDecodedStreamBytes()); - resources = form.getResources(); - shapes = form.getShapes(); - matrix = form.getMatrix(); - bbox = form.getBBox(); - } else if (streamOrDictionary instanceof Stream) { - Stream stream = (Stream) streamOrDictionary; - resources = library.getResources(stream.getEntries(), Annotation.RESOURCES_VALUE); - bbox = library.getRectangle(stream.getEntries(), Annotation.BBOX_VALUE); - if (bbox == null) { - bbox = library.getRectangle(entries, Annotation.RECTANGLE_KEY); - bbox.setRect(0, 0, bbox.getWidth(), bbox.getHeight()); - } - matrix = new AffineTransform(); - originalContentStream = new String(stream.getDecodedStreamBytes()); - try { - ContentParser cp = ContentParserFactory.getInstance() - .getContentParser(library, resources); - shapes = cp.parse(new byte[][]{stream.getDecodedStreamBytes()}, null).getShapes(); - } catch (Exception e) { - shapes = new Shapes(); - logger.log(Level.FINE, "Error initializing Page.", e); - } - } - } - - public AppearanceState(Library library, HashMap entries) { - super(library, entries); - matrix = new AffineTransform(); - bbox = (Rectangle2D) library.getObject(entries, Annotation.BBOX_VALUE); - InteractiveForm form = library.getCatalog().getInteractiveForm(); - // assign parent resource if not found in current appearance. - if (form != null){ - resources = form.getResources(); - } - } - - public Shapes getShapes() { - return shapes; - } - - public void setShapes(Shapes shapes) { - this.shapes = shapes; - } - - public AffineTransform getMatrix() { - return matrix; - } - - public void setMatrix(AffineTransform matrix) { - this.matrix = matrix; - } - - public Rectangle2D getBbox() { - return bbox; - } - - public void setBbox(Rectangle2D bbox) { - this.bbox = bbox; - entries.put(Annotation.BBOX_VALUE, PRectangle.getPRectangleVector(bbox)); - } - - public Resources getResources() { - return resources; - } - - /** - * Gets the original unaltered content stream. When the annotation is initialized the content stream is cached - * and use used in some instances as the base to any content stream editing during an annotation edit. - * - * @return original unaltered content stream. - */ - public String getOriginalContentStream() { - return originalContentStream; - } - - public void setContentStream(byte[] contentBytes){ - try { - ContentParser cp = ContentParserFactory.getInstance() - .getContentParser(library, resources); - shapes = cp.parse(new byte[][]{contentBytes}, null).getShapes(); - } catch (Exception e) { - shapes = new Shapes(); - logger.log(Level.FINE, "Error initializing Page.", e); - } - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/BorderEffect.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/BorderEffect.java deleted file mode 100644 index 6e9730d951..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/BorderEffect.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - *

Refer to: 8.4.3 Border Styles

- *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
KeyTypeValue
Sname(Optional) A name representing the border effect to apply. Possible values are: - * - * - * - * - * - * - * - * - * - *
SNo effect: the border is as described by the annotation dictionary's BS entry.
CThe border should appear "cloudy". The width and dash array specified by BS - * are honored.
- * Default value: S.
Inumber(Optional; valid only if the value of S is C) A number describing the intensity of the effect. - * Suggested values range from 0 to 2. Default value: 0.
- * - * @author Mark Collette - * @since 2.5 - */ -public class BorderEffect extends Dictionary { - /** - * Creates a new instance of a BorderEffect. - * - * @param l document library. - * @param h dictionary entries. - */ - public BorderEffect(Library l, HashMap h) { - super(l, h); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/BorderStyle.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/BorderStyle.java deleted file mode 100644 index 998ec3ed17..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/BorderStyle.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; - -/** - * BorderStyle state of a PDF annotation. Some values of this class are - * mutable and do not change the value of the underlying PDF in any way. They - * are only keep in memory for the duration that the PDF document is open. - *

- *

Refer to: 8.4.3 Border Styles

- *

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
KeyTypeValue
Typename(Optional) The type of PDF object that this dictionary describes; if present, must be - * Border for a border style dictionary.
Wnumber(Optional) The border width in points. If this value is 0, no border is drawn. Default - * value: 1.
Sname(Optional) The border style: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
S(Solid) A solid rectangle surrounding the annotation.
D(Dashed) A dashed rectangle surrounding the annotation. The dash pattern - * is specified by the D entry (see below).
B(Beveled) A simulated embossed rectangle that appears to be raised above the - * surface of the page.
I(Inset) A simulated engraved rectangle that appears to be recessed below the - * surface of the page.
U(Underline) A single line along the bottom of the annotation rectangle.
Default value: S.
Darray(Optional) A dash array defining a pattern of dashes and gaps to be used in drawing a - * dashed border (border style D above). The dash array is specified in the same format - * as in the line dash pattern parameter of the graphics state (see "Line Dash Pattern" on - * page 187). The dash phase is not specified and is assumed to be 0. For example, a D - * entry of [3 2] specifies a border drawn with 3-point dashes alternating with 2-point - * gaps. Default value: [3].
- * - * @author Mark Collette - * @since 2.5 - */ -public class BorderStyle extends Dictionary { - - //todo fill out with valid numbers... - private static final float[] DEFAULT_DASH_ARRAY = new float[]{3.0f}; - - public static final Name BORDER_STYLE_KEY = new Name("S"); - public static final Name BORDER_WIDTH_KEY = new Name("W"); - public static final Name BORDER_DASH_KEY = new Name("D"); - public static final Color DARKEST = Color.black; - public static final Color DARK = new Color(0xFF606060); - public static final Color LIGHT = new Color(0xFF909090); - public static final Color LIGHTEST = new Color(0xFFE5E5E5); - /** - * Solid rectangle border style surrounding the annotation - */ - public static final Name BORDER_STYLE_SOLID = new Name("S"); - /** - * Dashed rectangle border style surrounding the annotation - */ - public static final Name BORDER_STYLE_DASHED = new Name("D"); - /** - * Beveled rectangle border style surrounding the annotation - */ - public static final Name BORDER_STYLE_BEVELED = new Name("B"); - /** - * Inset rectangle border style surrounding the annotation - */ - public static final Name BORDER_STYLE_INSET = new Name("I"); - /** - * Underline rectangle border style surrounding the annotation - */ - public static final Name BORDER_STYLE_UNDERLINE = new Name("U"); - - // stroke width - private float strokeWidth = 1.0f; - - // border style, default is solid - private Name borderStyle; - - // dash array - private float[] dashArray = DEFAULT_DASH_ARRAY; - - /** - * Creates a new instance of a BorderStyle. - * - * @param l document library. - * @param h dictionary entries. - */ - public BorderStyle(Library l, HashMap h) { - super(l, h); - // parse out stroke width - Number value = (Number) getObject(BORDER_WIDTH_KEY); - if (value != null) { - strokeWidth = value.floatValue(); - } - // parse the default style. - Object style = getObject(BORDER_STYLE_KEY); - if (style != null) { - borderStyle = (Name) style; - } - // parse dash array. - List dashVector = (List) getObject(BORDER_STYLE_DASHED); - if (dashVector != null) { - int sz = dashVector.size(); - float[] dashArray = new float[sz]; - for (int i = 0; i < sz; i++) { - Number num = (Number) dashVector.get(i); - dashArray[i] = num.floatValue(); - } - this.dashArray = dashArray; - } - } - - public BorderStyle() { - super(null, null); - } - - public float getStrokeWidth() { - return strokeWidth; - } - - public Name getBorderStyle() { - return borderStyle; - } - - /** - * Sets the stroke width of the border style. Default value 1.0. - * - * @param strokeWidth float value representing width. - */ - public void setStrokeWidth(float strokeWidth) { - this.strokeWidth = strokeWidth; - entries.put(BORDER_WIDTH_KEY, this.strokeWidth); - } - - /** - * Sets the borderStyle type for this instance. - * - * @param lineStyle border style type as defined by, BORDER_STYLE_SOLID, - * BORDER_STYLE_DASHED, BORDER_STYLE_BEVELED, BORDER_STYLE_INSET, - * BORDER_STYLE_UNDERLINE - */ - public void setBorderStyle(final Name lineStyle) { - this.borderStyle = lineStyle; - entries.put(BORDER_STYLE_KEY, this.borderStyle); - if (this.borderStyle.equals(BorderStyle.BORDER_STYLE_DASHED)) { - entries.put(BorderStyle.BORDER_DASH_KEY, Arrays.asList(3f)); - } else { - entries.remove(BorderStyle.BORDER_DASH_KEY); - } - } - - public boolean isStyleSolid() { - return BORDER_STYLE_SOLID.equals(borderStyle); - } - - public boolean isStyleDashed() { - return BORDER_STYLE_DASHED.equals(borderStyle); - } - - public boolean isStyleBeveled() { - return BORDER_STYLE_BEVELED.equals(borderStyle); - } - - public boolean isStyleInset() { - return BORDER_STYLE_INSET.equals(borderStyle); - } - - public boolean isStyleUnderline() { - return BORDER_STYLE_UNDERLINE.equals(borderStyle); - } - - public void setDashArray(float[] dashArray) { - if (dashArray != null) { - this.dashArray = dashArray; - int sz = dashArray.length; - List dashVector = new ArrayList(sz); - for (int i = 0; i < sz; i++) { - dashVector.add(dashArray[i]); - } - this.dashArray = dashArray; - entries.put(BORDER_STYLE_DASHED, dashVector); - } - } - - public float[] getDashArray() { - return dashArray; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/ButtonWidgetAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/ButtonWidgetAnnotation.java deleted file mode 100644 index c0f1ce8ac4..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/ButtonWidgetAnnotation.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.PObject; -import org.icepdf.core.pobjects.StateManager; -import org.icepdf.core.pobjects.acroform.ButtonFieldDictionary; -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.util.Library; - -import java.awt.geom.AffineTransform; -import java.util.HashMap; - -/** - * Represents a Acroform Button widget and manages the appearance streams - * for the various appearance states. - * - * @since 5.1 - */ -public class ButtonWidgetAnnotation extends AbstractWidgetAnnotation { - - private ButtonFieldDictionary fieldDictionary; - - protected Name originalAppearance; - - public ButtonWidgetAnnotation(Library l, HashMap h) { - super(l, h); - fieldDictionary = new ButtonFieldDictionary(library, entries); - } - - public ButtonWidgetAnnotation(Annotation widgetAnnotation){ - super(widgetAnnotation.getLibrary(), widgetAnnotation.getEntries()); - fieldDictionary = new ButtonFieldDictionary(library, entries); - // copy over the reference number. - setPObjectReference(widgetAnnotation.getPObjectReference()); - } - - /** - * Button appearance streams are fixed, all that is done in this method is appearance selected state - * is set and the change persisted to the StateManager. - * @param dx current location of the annotation - * @param dy current location of the annotation - * @param pageSpace current page space. - */ - public void resetAppearanceStream(double dx, double dy, AffineTransform pageSpace) { - // update the appearanceState in the state manager so the change will persist. - Appearance appearance = appearances.get(currentAppearance); - if (appearance != null) { - appearance.updateAppearanceDictionary(entries); - } - // add this annotation to the state manager. - StateManager stateManager = library.getStateManager(); - stateManager.addChange(new PObject(this, this.getPObjectReference())); - - Name selectedName = appearance.getSelectedName(); - // check boxes will have a V entry which - if (getFieldDictionary().hasFieldValue()){ - // update the value - entries.put(FieldDictionary.V_KEY, selectedName); - // object already in state manager, nothing further to to. - } // radio buttons will store the value in the parent. - else if (getFieldDictionary().getParent() != null && - getFieldDictionary().getParent().hasFieldValue()){ - // update the value - //getFieldDictionary().getParent().getEntries().put(FieldDictionary.V_KEY, selectedName); - // add to state manager. - stateManager.addChange(new PObject(getFieldDictionary().getParent(), - getFieldDictionary().getParent().getPObjectReference())); - } - - if (originalAppearance == null){ - originalAppearance = currentAppearance; - } - } - - public void reset() { - Object oldValue = fieldDictionary.getFieldValue(); - Object defaultFieldValue = fieldDictionary.getDefaultFieldValue(); - FieldDictionary parentFaultFieldValue = fieldDictionary.getParent(); - if (defaultFieldValue != null) { - // apply the default value - changeSupport.firePropertyChange("valueFieldReset", oldValue, defaultFieldValue); - }else if (parentFaultFieldValue != null) { - // apply the default value - changeSupport.firePropertyChange("valueFieldReset", oldValue, - parentFaultFieldValue.getDefaultFieldValue()); - }else{ - // otherwise we remove the key - changeSupport.firePropertyChange("valueFieldReset", oldValue, ""); - } - } - - public void turnOff() { - Appearance appearance = appearances.get(currentAppearance); - if (appearance != null && appearance.hasAlternativeAppearance()) { - appearance.setSelectedName(appearance.getOffName()); - } - } - - public boolean isOn() { - Appearance appearance = appearances.get(currentAppearance); - Name selectedNormalAppearance = appearance.getSelectedName(); - return !selectedNormalAppearance.equals(appearance.getOffName()); - } - - public Name toggle() { - Appearance appearance = appearances.get(currentAppearance); - Name selectedNormalAppearance = appearance.getSelectedName(); - if (appearance.hasAlternativeAppearance()) { - if (!selectedNormalAppearance.equals(appearance.getOffName())) { - appearance.setSelectedName(appearance.getOffName()); - } else { - appearance.setSelectedName(appearance.getOnName()); - } - } - return appearance.getSelectedName(); - } - - - public void turnOn() { - // first check if there are more then one normal streams. - Appearance appearance = appearances.get(currentAppearance); - if (appearance.hasAlternativeAppearance()) { - appearance.setSelectedName(appearance.getOnName()); - } - } - - @Override - public ButtonFieldDictionary getFieldDictionary() { - return fieldDictionary; - } -} - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/ChoiceWidgetAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/ChoiceWidgetAnnotation.java deleted file mode 100644 index 053ab639c0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/ChoiceWidgetAnnotation.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.acroform.ChoiceFieldDictionary; -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.pobjects.graphics.text.LineText; -import org.icepdf.core.pobjects.graphics.text.WordText; -import org.icepdf.core.util.Library; - -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.StringTokenizer; - -import static org.icepdf.core.pobjects.acroform.ChoiceFieldDictionary.ChoiceFieldType; - -/** - * Represents a Acroform Choice widget and manages the appearance streams - * for the various appearance states. This class can generate a postscript - * stream that represents it current state. - * - * @since 5.1 - */ -public class ChoiceWidgetAnnotation extends AbstractWidgetAnnotation { - - private ChoiceFieldDictionary fieldDictionary; - - public ChoiceWidgetAnnotation(Library l, HashMap h) { - super(l, h); - fieldDictionary = new ChoiceFieldDictionary(library, entries); - } - - /** - * Some choices lists are lacking the /opt key so we need to do our best to generate the list from the shapes. - * - * @return list of potential options. - */ - public ArrayList generateChoices() { - Shapes shapes = getShapes(); - if (shapes != null) { - ArrayList options = new ArrayList(); - String tmp; - ArrayList pageLines = shapes.getPageText().getPageLines(); - for (LineText lines : pageLines) { - for (WordText word : lines.getWords()) { - tmp = word.toString(); - if (!(tmp.equals("") || tmp.equals(" "))) { - options.add(fieldDictionary.buildChoiceOption(tmp, tmp)); - } - } - } - return options; - } - return new ArrayList(); - } - - /** - * Resets the appearance stream for this instance using the current state. The mark content section of the stream - * is found and the edit it make to best of our ability. - * - * @param dx x offset of the annotation - * @param dy y offset of the annotation - * @param pageTransform current page transform. - */ - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - ChoiceFieldType choiceFieldType = - fieldDictionary.getChoiceFieldType(); - - // get at the original postscript as well alter the marked content - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - Rectangle2D bbox = appearanceState.getBbox(); - AffineTransform matrix = appearanceState.getMatrix(); - String currentContentStream = appearanceState.getOriginalContentStream(); - - // alterations vary by choice type. - if (choiceFieldType == ChoiceFieldType.CHOICE_COMBO || - choiceFieldType == ChoiceFieldType.CHOICE_EDITABLE_COMBO) { - // relatively straight forward replace with new selected value. - if (currentContentStream != null) { - currentContentStream = buildChoiceComboContents(currentContentStream); - } else { - // todo no stream and we will need to build one. - currentContentStream = ""; - } - } else { - // build out the complex choice list content stream - if (currentContentStream != null) { - currentContentStream = buildChoiceListContents(currentContentStream); - } else { - // todo no stream and we will need to build one. - currentContentStream = ""; - } - } - // finally create the shapes from the altered stream. - if (currentContentStream != null) { - appearanceState.setContentStream(currentContentStream.getBytes()); - } - - // some widgets don't have AP dictionaries in such a case we need to create the form object - // and build out the default properties. - Form appearanceStream = getOrGenerateAppearanceForm(); - - if (appearanceStream != null) { - // update the content stream with the new stream data. - appearanceStream.setRawBytes(currentContentStream.getBytes()); - // add the appearance stream - StateManager stateManager = library.getStateManager(); - stateManager.addChange(new PObject(appearanceStream, appearanceStream.getPObjectReference())); - // add an AP entry for the - HashMap appearanceRefs = new HashMap(); - appearanceRefs.put(APPEARANCE_STREAM_NORMAL_KEY, appearanceStream.getPObjectReference()); - entries.put(APPEARANCE_STREAM_KEY, appearanceRefs); - Rectangle2D formBbox = new Rectangle2D.Float(0, 0, - (float) bbox.getWidth(), (float) bbox.getHeight()); - appearanceStream.setAppearance(null, matrix, formBbox); - // add link to resources on forum, if no resources exist. - if (library.getResources(appearanceStream.getEntries(), Form.RESOURCES_KEY) == null) { - appearanceStream.getEntries().put(Form.RESOURCES_KEY, - library.getCatalog().getInteractiveForm().getResources().getEntries()); - } - // add the annotation as changed as T entry has also been updated to reflect teh changed content. - stateManager.addChange(new PObject(this, this.getPObjectReference())); - - // compress the form object stream. - if (false && compressAppearanceStream) { - appearanceStream.getEntries().put(Stream.FILTER_KEY, new Name("FlateDecode")); - } else { - appearanceStream.getEntries().remove(Stream.FILTER_KEY); - } - appearanceStream.init(); - } - } - - - public void reset() { - Object oldValue = fieldDictionary.getFieldValue(); - Object tmp = fieldDictionary.getDefaultFieldValue(); - if (tmp == null) { - FieldDictionary parentFieldDictionary = fieldDictionary.getParent(); - if (parentFieldDictionary != null) { - tmp = parentFieldDictionary.getDefaultFieldValue(); - } - } - if (tmp != null) { - // apply the default value - fieldDictionary.setFieldValue(tmp, getPObjectReference()); - changeSupport.firePropertyChange("valueFieldReset", oldValue, tmp); - } else { - // otherwise we remove the key - fieldDictionary.getEntries().remove(FieldDictionary.V_KEY); - fieldDictionary.setIndexes(null); - // check the parent as well. - FieldDictionary parentFieldDictionary = fieldDictionary.getParent(); - if (parentFieldDictionary != null) { - parentFieldDictionary.getEntries().remove(FieldDictionary.V_KEY); - if (parentFieldDictionary instanceof ChoiceFieldDictionary) { - ((ChoiceFieldDictionary) parentFieldDictionary).setIndexes(null); - } - } - changeSupport.firePropertyChange("valueFieldReset", oldValue, null); - } - } - - @Override - public ChoiceFieldDictionary getFieldDictionary() { - return fieldDictionary; - } - - public String buildChoiceComboContents(String currentContentStream) { - ArrayList choices = fieldDictionary.getOptions(); - // double check we have some choices to work with. - if (choices == null) { - // generate them from the content stream. - choices = generateChoices(); - fieldDictionary.setOptions(choices); - } - String selectedField = (String) fieldDictionary.getFieldValue(); - int btStart = currentContentStream.indexOf("BT"); - int btEnd = currentContentStream.lastIndexOf("ET"); - int bmcStart = currentContentStream.indexOf("BMC"); - int bmcEnd = currentContentStream.lastIndexOf("EMC"); - // grab the pre post marked content postscript. - String preBmc = btStart >= 0 ? currentContentStream.substring(0, btStart + 2) : - currentContentStream.substring(0, bmcStart + 3); - String postEmc = btEnd >= 0 ? currentContentStream.substring(btEnd) : - currentContentStream.substring(0, bmcEnd + 3); - - // marked content which we will use to try and find some data points. - //String markedContent = currentContentStream.substring(bmcStart, bmcEnd); - - // check for a bounding box definition - //Rectangle2D.Float bounds = findBoundRectangle(markedContent); - - // finally build out the new content stream - StringBuilder content = new StringBuilder(); - // apply font - if (fieldDictionary.getDefaultAppearance() != null) { - String markedContent = fieldDictionary.getDefaultAppearance(); - Page page = getPage(); - markedContent = fieldDictionary.generateDefaultAppearance(markedContent, - page != null ? page.getResources() : null); - content.append(markedContent).append(' '); - } else { // common font and colour layout for most form elements. - content.append("/Helv 12 Tf 0 g "); - } - // apply the text offset, 4 is just a generic padding. - content.append(4).append(' ').append(4).append(" Td "); - // hex encode the text so that we better handle character codes > 127 - content = encodeHexString(content, selectedField).append(" Tj "); - // build the final content stream. - if (btStart >= 0) { - currentContentStream = preBmc + "\n" + content + "\n" + postEmc; - } else { - currentContentStream = preBmc + " BT\n" + content + "\n ET EMC"; - } - - return currentContentStream; - } - - public String buildChoiceListContents(String currentContentStream) { - - ArrayList choices = fieldDictionary.getOptions(); - // double check we have some choices to work with. - if (choices == null) { - // generate them from the content stream. - choices = generateChoices(); - fieldDictionary.setOptions(choices); - } - ArrayList selections = fieldDictionary.getIndexes(); - // mark the indexes of the mark content. - int bmcStart = currentContentStream.indexOf("BMC") + 3; - int bmcEnd = currentContentStream.indexOf("EMC"); - // grab the pre post marked content postscript. - String preBmc = currentContentStream.substring(0, bmcStart); - String postEmc = currentContentStream.substring(bmcEnd); - // marked content which we will use to try and find some data points. - String markedContent = currentContentStream.substring(bmcStart, bmcEnd); - - // check for a bounding box definition - Rectangle2D.Float bounds = findBoundRectangle(markedContent); - - // check to see if there is a selection box colour defined. - float[] selectionColor = findSelectionColour(markedContent); - - // and finally look for a previous selection box, this can be null, no default value - Rectangle2D.Float selectionRectangle = findSelectionRectangle(markedContent); - float lineHeight = 13.87f; - if (selectionRectangle != null) { - lineHeight = selectionRectangle.height; - } - - // we need to plot out where the opt text is going to go as well as the background colour and text colour - // for any selected items. So we update the choices model to reflect the current selection state. - boolean isSelection = false; - if (selections != null) { - for (int i = 0, max = choices.size(); i < max; i++) { - for (int selection : selections) { - if (selection == i) { - choices.get(i).setIsSelected(true); - isSelection = true; - } else { - choices.get(i).setIsSelected(false); - } - } - } - } - // figure out offset range to insure a single selection is always visible - int startIndex = 0, endIndex = choices.size(); - if (selections != null && selections.size() == 1) { - int numberLines = (int) Math.floor(bounds.height / lineHeight); - // check if list is smaller then number of lines - int selectedIndex = selections.get(0); - if (choices.size() < numberLines) { - // nothing to do. - } else if (selectedIndex < numberLines) { - endIndex = numberLines + 1; - } - // check for bottom out range - else if (endIndex - selectedIndex <= numberLines) { - startIndex = endIndex - numberLines; - } - // else mid range just need to start the index. - else { - startIndex = selectedIndex; - endIndex = numberLines + 1; - - } - // we have a single line - if (startIndex > endIndex) { - endIndex = startIndex + 1; - } - } - - // finally build out the new content stream - StringBuilder content = new StringBuilder(); - // bounding rectangle. - content.append("q ").append(generateRectangle(bounds)).append("W n "); - // apply selection highlight background. - if (isSelection) { - // apply colour - content.append(selectionColor[0]).append(' ').append(selectionColor[1]).append(' ') - .append(selectionColor[2]).append(" rg "); - // apply selection - Rectangle2D.Float firstSelection; - if (selectionRectangle == null) { - firstSelection = new Rectangle2D.Float(bounds.x, bounds.y + bounds.height - lineHeight, bounds.width, lineHeight); - } else { - firstSelection = new Rectangle2D.Float(selectionRectangle.x, bounds.y + bounds.height - lineHeight, - selectionRectangle.width, lineHeight); - } - ChoiceFieldDictionary.ChoiceOption choice; - for (int i = startIndex; i < endIndex; i++) { - choice = choices.get(i); - // check if a selection rectangle was defined, if not we might have a custom style and we - // avoid the selection background (only have one test case for this) - if (choice.isSelected() && selectionRectangle != null) { - content.append(generateRectangle(firstSelection)).append("f "); - } - firstSelection.y -= lineHeight; - } - } - // apply the ext. - content.append("BT "); - // apply font - if (fieldDictionary.getDefaultAppearance() != null) { - content.append(fieldDictionary.getDefaultAppearance()); - } else { // common font and colour layout for most form elements. - content.append("/Helv 12 Tf 0 g "); - } - // apply the line height - content.append(lineHeight).append(" TL "); - // apply the text offset, 4 is just a generic padding. - content.append(4).append(' ').append(bounds.height + 4).append(" Td "); - // print out text - ChoiceFieldDictionary.ChoiceOption choice; - for (int i = startIndex; i < endIndex; i++) { - choice = choices.get(i); - if (choice.isSelected() && selectionRectangle != null) { - content.append("1 g "); - } else { - content.append("0 g "); - } - content.append('(').append(choice.getLabel()).append(")' "); - } - content.append("ET Q"); - // build the final content stream. - currentContentStream = preBmc + "\n" + content + "\n" + postEmc; - return currentContentStream; - } - - /** - * The selection colour is generally defined in DeviceRGB and occurs after the bounding box has been defined. - * This utility method tries to parse out the colour information and return it in float[3]. If the data can't - * be found then we return the default colour of new float[]{0.03922f, 0.14118f, 0.41569f}. - * - * @param markedContent content to look for colour info. - * @return found colour data or new float[]{0.03922f, 0.14118f, 0.41569f}. - */ - private float[] findSelectionColour(String markedContent) { - int selectionStart = markedContent.indexOf("n") + 1; - int selectionEnd = markedContent.lastIndexOf("rg"); - if (selectionStart < selectionEnd && selectionEnd > 0) { - String potentialNumbers = markedContent.substring(selectionStart, selectionEnd); - StringTokenizer toker = new StringTokenizer(potentialNumbers); - float[] points = new float[3]; - int i = 0; - while (toker.hasMoreTokens()) { - try { - float tmp = Float.parseFloat(toker.nextToken()); - points[i] = tmp; - i++; - } catch (NumberFormatException e) { - break; - } - } - if (i == 3) { - return points; - } - } - // default selection colour. - return new float[]{0.03922f, 0.14118f, 0.41569f}; - } - -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/CircleAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/CircleAnnotation.java deleted file mode 100644 index fc09771311..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/CircleAnnotation.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright 2006-2016 ICEsoft Technologies Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.pobjects.graphics.commands.*; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * Circle annotations (PDF 1.3) shall display, respectively, a - * rectangle or an ellipse on the page. When opened, they shall display a - * pop-up window containing the text of the associated note. The rectangle or - * ellipse shall be inscribed within the annotation rectangle defined by the - * annotation dictionary’s Rect entry (see Table 168). - *

- * Figure 63 shows two annotations, each with a border width of 18 points. Despite - * the names square and circle, the width and height of the annotation rectangle - * need not be equal. Table 177 shows the annotation dictionary entries specific - * to these types of annotations. - * - * @since 5.0 - */ -public class CircleAnnotation extends MarkupAnnotation { - - private static final Logger logger = - Logger.getLogger(CircleAnnotation.class.toString()); - - /** - * (Optional; PDF 1.4) An array of numbers in the range 0.0 to 1.0 specifying - * the interior color that shall be used to fill the annotation’s line endings - * (see Table 176). The number of array elements shall determine the colour - * space in which the colour is defined: - * 0 - No colour; transparent - * 1 - DeviceGray - * 3 - DeviceRGB - * 4 - DeviceCMYK - */ - public static final Name IC_KEY = new Name("IC"); - - // state properties for generate the content stream and shapes representation. - // of the annnotation state. - private Color fillColor; - private boolean isFillColor; - private Rectangle rectangle; - - public CircleAnnotation(Library l, HashMap h) { - super(l, h); - } - - public void init() throws InterruptedException { - super.init(); - // parse out interior colour, specific to link annotations. - fillColor = Color.WHITE; // we default to black but probably should be null - java.util.List C = (java.util.List) getObject(IC_KEY); - // parse thought rgb colour. - if (C != null && C.size() >= 3) { - float red = ((Number) C.get(0)).floatValue(); - float green = ((Number) C.get(1)).floatValue(); - float blue = ((Number) C.get(2)).floatValue(); - red = Math.max(0.0f, Math.min(1.0f, red)); - green = Math.max(0.0f, Math.min(1.0f, green)); - blue = Math.max(0.0f, Math.min(1.0f, blue)); - fillColor = new Color(red, green, blue); - isFillColor = true; - } - // try and generate an appearance stream. - resetNullAppearanceStream(); - } - - /** - * Gets an instance of a CircleAnnotation that has valid Object Reference. - * - * @param library document library - * @param rect bounding rectangle in user space - * @return new CircleAnnotation Instance. - */ - public static CircleAnnotation getInstance(Library library, - Rectangle rect) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE); - entries.put(Dictionary.SUBTYPE_KEY, Annotation.SUBTYPE_CIRCLE); - // coordinates - if (rect != null) { - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(rect)); - } else { - entries.put(Annotation.RECTANGLE_KEY, new Rectangle(10, 10, 50, 100)); - } - - // create the new instance - CircleAnnotation circleAnnotation = null; - try { - circleAnnotation = new CircleAnnotation(library, entries); - circleAnnotation.init(); - circleAnnotation.setPObjectReference(stateManager.getNewReferencNumber()); - circleAnnotation.setNew(true); - - // set default flags. - circleAnnotation.setFlag(Annotation.FLAG_READ_ONLY, false); - circleAnnotation.setFlag(Annotation.FLAG_NO_ROTATE, false); - circleAnnotation.setFlag(Annotation.FLAG_NO_ZOOM, false); - circleAnnotation.setFlag(Annotation.FLAG_PRINT, true); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("CircletAnnotation initialization interrupted."); - } - - return circleAnnotation; - } - - /** - * Resets the annotations appearance stream. - */ - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - // grab the current appearance stream as we'll be updating the shapes. - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - // clean identity matrix (nothing fancy) and new empty shapes. - appearanceState.setMatrix(new AffineTransform()); - appearanceState.setShapes(new Shapes()); - - // grab references so so we can bass them to the update appearance method. - AffineTransform matrix = appearanceState.getMatrix(); - Shapes shapes = appearanceState.getShapes(); - - // we paint everythign in annotation space which is relative to the bbox. - Rectangle2D bbox = appearanceState.getBbox(); - bbox.setRect(0, 0, bbox.getWidth(), bbox.getHeight()); - - // setup the AP stream. - setModifiedDate(PDate.formatDateTime(new Date())); - // refresh /rect entry to match bbox of the appearance stream. - rectangle = getUserSpaceRectangle().getBounds(); - - // check the stroke width - if (borderStyle.getStrokeWidth() == 0) { - borderStyle.setStrokeWidth(1); - } - - BasicStroke stroke = getBorderStyleStroke(); - int strokeWidth = (int) stroke.getLineWidth(); - - // setup the space for the AP content stream. - Rectangle rectangleToDraw = new Rectangle( - strokeWidth, - strokeWidth, - (int) userSpaceRectangle.getWidth() - strokeWidth * 2, - (int) userSpaceRectangle.getHeight() - strokeWidth * 2); - - Ellipse2D.Double circle = new Ellipse2D.Double( - strokeWidth, strokeWidth, - rectangleToDraw.getWidth(), - rectangleToDraw.getHeight()); - - // add external graphics state for transparency support. - shapes.add(new GraphicsStateCmd(EXT_GSTATE_NAME)); - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity))); - shapes.add(new StrokeDrawCmd(stroke)); - shapes.add(new ShapeDrawCmd(circle)); - if (isFillColor) { - shapes.add(new ColorDrawCmd(fillColor)); - shapes.add(new FillDrawCmd()); - } - if (borderStyle.getStrokeWidth() > 0) { - shapes.add(new ColorDrawCmd(color)); - shapes.add(new DrawDrawCmd()); - } - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))); - - // update the appearance stream - // create/update the appearance stream of the xObject. - Form form = updateAppearanceStream(shapes, bbox, matrix, - PostScriptEncoder.generatePostScript(shapes.getShapes())); - generateExternalGraphicsState(form, opacity); - } - - public Color getFillColor() { - return fillColor; - } - - public void setFillColor(Color fillColor) { - this.fillColor = fillColor; - float[] compArray = new float[3]; - this.fillColor.getColorComponents(compArray); - java.util.List colorValues = new ArrayList(compArray.length); - for (float comp : compArray) { - colorValues.add(comp); - } - entries.put(IC_KEY, colorValues); - } - - public Rectangle getRectangle() { - return rectangle; - } - - public void setRectangle(Rectangle rectangle) { - this.rectangle = rectangle; - } - - public boolean isFillColor() { - return isFillColor; - } - - public void setFillColor(boolean fillColor) { - isFillColor = fillColor; - if (!isFillColor) { - entries.remove(IC_KEY); - } - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/FreeTextAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/FreeTextAnnotation.java deleted file mode 100644 index 8f2271c4d3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/FreeTextAnnotation.java +++ /dev/null @@ -1,759 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.fonts.FontFile; -import org.icepdf.core.pobjects.fonts.FontManager; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.pobjects.graphics.TextSprite; -import org.icepdf.core.pobjects.graphics.TextState; -import org.icepdf.core.pobjects.graphics.commands.*; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; - -import javax.swing.text.DefaultStyledDocument; -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.StringTokenizer; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * A free text annotation (PDF 1.3) displays text directly on the page. Unlike - * an ordinary text annotation (see 12.5.6.4, “Text Annotationsâ€), a free text - * annotation has no open or closed state; instead of being displayed in a pop-up - * window, the text shall be always visible. Table 174 shows the annotation - * dictionary entries specific to this type of annotation. 12.7.3.3, - * “Variable Text†describes the process of using these entries to generate the - * appearance of the text in these annotations. - * - * @since 5.0 - */ -public class FreeTextAnnotation extends MarkupAnnotation { - - private static final Logger logger = - Logger.getLogger(FreeTextAnnotation.class.toString()); - - /** - * (Required) The default appearance string that shall be used in formatting - * the text (see 12.7.3.3, “Variable Textâ€). - *

- * The annotation dictionary’s AP entry, if present, shall take precedence - * over the DA entry; see Table 168 and 12.5.5, “Appearance Streams.†- */ - public static final Name DA_KEY = new Name("DA"); - /** - * (Optional; PDF 1.4) A code specifying the form of quadding - * (justification) that shall be used in displaying the annotation’s text: - * 0 - Left-justified - * 1 - Centered - * 2 - Right-justified - * Default value: 0 (left-justified). - */ - public static final Name Q_KEY = new Name("Q"); - /** - * (Optional; PDF 1.5) A default style string, as described in 12.7.3.4, - * “Rich Text Strings.†- */ - public static final Name DS_KEY = new Name("DS"); - /** - * (Optional; meaningful only if IT is FreeTextCallout; PDF 1.6) An array of - * four or six numbers specifying a callout line attached to the free text - * annotation. Six numbers [ x1 y1 x2 y2 x3 y3 ] represent the starting, - * knee point, and ending coordinates of the line in default user space, as - * shown in Figure 8.4. Four numbers [ x1 y1 x2 y2 ] represent the starting - * and ending coordinates of the line. - */ - public static final Name CL_KEY = new Name("CL"); - - /** - * (Optional; PDF 1.6) A name describing the intent of the free text - * annotation (see also the IT entry in Table 170). The following values - * shall be valid: - *

- * FreeTextThe annotation is intended to function as a plain free-text - * annotation. A plain free-text annotation is also known as a text box comment. - * FreeTextCallout The annotation is intended to function as a callout. The - * callout is associated with an area on the page through the callout line - * specified in CL. - *

- * FreeTextTypeWriterThe annotation is intended to function as a click-to-type - * or typewriter object and no callout line is drawn. - * Default value: FreeText - */ -// public static final Name IT_KEY = new Name("IT"); - - /** - * (Optional; PDF 1.6) A border effect dictionary (see Table 167) used in - * conjunction with the border style dictionary specified by the BS entry. - */ - public static final Name BE_KEY = new Name("BE"); - - /** - * (Optional; PDF 1.6) A set of four numbers describing the numerical - * differences between two rectangles: the Rect entry of the annotation and - * a rectangle contained within that rectangle. The inner rectangle is where - * the annotation’s text should be displayed. Any border styles and/or border - * effects specified by BS and BE entries, respectively, shall be applied to - * the border of the inner rectangle. - *

- * The four numbers correspond to the differences in default user space - * between the left, top, right, and bottom coordinates of Rect and those - * of the inner rectangle, respectively. Each value shall be greater than - * or equal to 0. The sum of the top and bottom differences shall be less - * than the height of Rect, and the sum of the left and right differences - * shall be less than the width of Rect. - */ - public static final Name RD_KEY = new Name("RD"); - /** - * (Optional; PDF 1.6) A border style dictionary (see Table 166) specifying - * the line width and dash pattern that shall be used in drawing the - * annotation’s border. - *

- * The annotation dictionary’s AP entry, if present, takes precedence over - * the BS entry; see Table 164 and 12.5.5, “Appearance Streamsâ€. - */ - public static final Name BS_KEY = new Name("BS"); - /** - * (Optional; meaningful only if CL is present; PDF 1.6) A name specifying - * the line ending style that shall be used in drawing the callout line - * specified in CL. The name shall specify the line ending style for the - * endpoint defined by the pairs of coordinates (x1, y1). Table 176 shows - * the possible line ending styles. - *

- * Default value: None. - */ - public static final Name LE_KEY = new Name("LE"); - /** - * Left-justified quadding - */ - public static final int QUADDING_LEFT_JUSTIFIED = 0; - /** - * Right-justified quadding - */ - public static final int QUADDING_CENTER_JUSTIFIED = 1; - /** - * Center-justified quadding - */ - public static final int QUADDING_RIGHT_JUSTIFIED = 2; - public static final Name EMBEDDED_FONT_NAME = new Name("ice1"); - - public static Color defaultFontColor; - public static Color defaultFillColor; - public static Color defaultBorderColor; - public static int defaultFontSize; - static { - - // sets annotation free text font colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.freeText.font.color", "#000000"); - int colorValue = ColorUtil.convertColor(color); - defaultFontColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("000000", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading free text annotation font colour"); - } - } - - // sets annotation free text fill colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.freeText.fill.color", "#ffffff"); - int colorValue = ColorUtil.convertColor(color); - defaultFillColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("ffffff", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading free text annotation fill colour"); - } - } - - // sets annotation free text fill colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.freeText.border.color", "#cccccc"); - int colorValue = ColorUtil.convertColor(color); - defaultBorderColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("000000", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading free text annotation fill colour"); - } - } - - // sets annotation free text fill colour - try { - defaultFontSize = Defs.sysPropertyInt( - "org.icepdf.core.views.page.annotation.freeText.font.size", 24); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading free text annotation fill colour"); - } - } - - } - protected String defaultAppearance; - protected int quadding = QUADDING_LEFT_JUSTIFIED; - protected String defaultStylingString; - protected boolean hideRenderedOutput; - protected String richText; - - // appearance properties not to be confused with annotation properties, - // this properties are updated by the UI components and used to regenerate - // the annotations appearance stream and other needed properties on edits. - private String fontName = "Helvetica"; - private int fontStyle = Font.PLAIN; - private int fontSize = defaultFontSize; - private Color fontColor = defaultFontColor; - // fill - private boolean fillType = false; - private Color fillColor = defaultFillColor; - // stroke - private boolean strokeType = false; - - // editing placeholder - protected DefaultStyledDocument document; - - // font file is cached to avoid expensive lookups. - protected FontFile fontFile; - protected boolean fontPropertyChanged; - - public FreeTextAnnotation(Library l, HashMap h) { - super(l, h); - } - - public void init() throws InterruptedException{ - super.init(); - - Appearance appearance = appearances.get(APPEARANCE_STREAM_NORMAL_KEY); - Shapes shapes = null; - if (appearance != null) { - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - shapes = appearanceState.getShapes(); - } - // re-get colour so we can check for a null entry - if (library.getObject(entries, COLOR_KEY) != null && - getObject(APPEARANCE_STREAM_KEY) != null) { - // iterate over shapes and try and find the fill and stroke colors. - if (shapes != null) { - Color currentColor = Color.BLACK; - for (DrawCmd drawCmd : shapes.getShapes()) { - if (drawCmd instanceof ColorDrawCmd) { - currentColor = ((ColorDrawCmd) drawCmd).getColor(); - } else if (drawCmd instanceof FillDrawCmd) { - fillType = true; - fillColor = new Color(currentColor.getRGB()); - } else if (drawCmd instanceof DrawDrawCmd) { - strokeType = true; - color = new Color(currentColor.getRGB()); - } - } - } - } else { - color = Color.BLACK; - } - - defaultAppearance = library.getString(entries, DA_KEY); - - if (library.getObject(entries, Q_KEY) != null) { - quadding = library.getInt(entries, Q_KEY); - } - // find rich text string - Object tmp = library.getObject(entries, RC_KEY); - if (tmp != null && tmp instanceof StringObject) { - StringObject tmpRichText = (StringObject) tmp; - richText = tmpRichText.getDecryptedLiteralString(library.getSecurityManager()); - } - - // default style string - if (library.getObject(entries, DS_KEY) != null) { - defaultStylingString = getString(DS_KEY); - } - - // set the default quadding value - if (library.getObject(entries, Q_KEY) == null) { - entries.put(Q_KEY, 0); - } - // free text. - if (library.getObject(entries, IT_KEY) == null) { - entries.put(IT_KEY, new Name("FreeText")); - } - - // check for defaultStylingString and if so parse out the - // font style, weight and name. - if (defaultStylingString != null) { - StringTokenizer toker = new StringTokenizer(defaultStylingString, ";"); - while (toker.hasMoreElements()) { - String cssProperty = (String) toker.nextElement(); - if (cssProperty != null && cssProperty.contains("font-family")) { - fontName = cssProperty.substring(cssProperty.indexOf(":") + 1).trim(); - } else if (cssProperty != null && cssProperty.contains("color")) { - String colorString = cssProperty.substring(cssProperty.indexOf(":") + 1).trim(); - fontColor = new Color(ColorUtil.convertColor(colorString)); - } else if (cssProperty != null && cssProperty.contains("font-weight")) { - String fontStyle = cssProperty.substring(cssProperty.indexOf(":") + 1).trim(); - if (fontStyle.equals("normal")) { - this.fontStyle = Font.PLAIN; - } else if (fontStyle.equals("italic")) { - this.fontStyle = Font.ITALIC; - } else if (fontStyle.equals("bold")) { - this.fontStyle = Font.BOLD; - } - } else if (cssProperty != null && cssProperty.contains("font-size")) { - String fontSize = cssProperty.substring(cssProperty.indexOf(":") + 1).trim(); - fontSize = fontSize.substring(0, fontSize.indexOf('p')); - try { - this.fontSize = (int) Float.parseFloat(fontSize); - } catch (NumberFormatException e) { - logger.finer("Error parsing font size: " + fontSize); - } - } - } - } - // try and generate an appearance stream. - resetNullAppearanceStream(); - } - - /** - * Gets an instance of a FreeTextAnnotation that has valid Object Reference. - * - * @param library document library - * @param rect bounding rectangle in user space - * @return new FreeTextAnnotation Instance. - */ - public static FreeTextAnnotation getInstance(Library library, - Rectangle rect) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE); - entries.put(Dictionary.SUBTYPE_KEY, Annotation.SUBTYPE_FREE_TEXT); - // coordinates - if (rect != null) { - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(rect)); - } else { - entries.put(Annotation.RECTANGLE_KEY, new Rectangle(10, 10, 50, 100)); - } - - // create the new instance - FreeTextAnnotation freeTextAnnotation = null; - try { - freeTextAnnotation = new FreeTextAnnotation(library, entries); - freeTextAnnotation.init(); - freeTextAnnotation.setPObjectReference(stateManager.getNewReferencNumber()); - freeTextAnnotation.setNew(true); - - // set default flags. - freeTextAnnotation.setFlag(Annotation.FLAG_READ_ONLY, false); - freeTextAnnotation.setFlag(Annotation.FLAG_NO_ROTATE, false); - freeTextAnnotation.setFlag(Annotation.FLAG_NO_ZOOM, false); - freeTextAnnotation.setFlag(Annotation.FLAG_PRINT, true); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("FreeTextAnnotation initialization interrupted."); - } - return freeTextAnnotation; - } - - @Override - public void render(Graphics2D origG, int renderHintType, float totalRotation, float userZoom, boolean tabSelected) { - // suspend the rendering when the UI tools are present. - if (!hideRenderedOutput) { - super.render(origG, renderHintType, totalRotation, userZoom, tabSelected); - } - } - - @Override - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - appearanceState.setMatrix(new AffineTransform()); - appearanceState.setShapes(new Shapes()); - - Rectangle2D bbox = appearanceState.getBbox(); - bbox.setRect(0, 0, bbox.getWidth(), bbox.getHeight()); - - AffineTransform matrix = appearanceState.getMatrix(); - Shapes shapes = appearanceState.getShapes(); - - if (shapes == null) { - shapes = new Shapes(); - appearanceState.setShapes(shapes); - } else { - // remove any previous text - appearanceState.getShapes().getShapes().clear(); - } - - // remove any previous text - shapes.getShapes().clear(); - - // setup the space for the AP content stream. - AffineTransform af = new AffineTransform(); - af.scale(1, -1); - af.translate(0, -bbox.getHeight()); - // adjust of the border offset, offset is define in viewer, - // so we can't use the constant because of dependency issues. - double insets = 5;// * pageTransform.getScaleX(); - af.translate(insets, insets); - shapes.add(new TransformDrawCmd(af)); - - // iterate over each line of text painting the strings. - if (content == null) { - setContents(""); - } - - // create the new font to draw with - if (fontFile == null || fontPropertyChanged) { - fontFile = FontManager.getInstance().initialize().getInstance(fontName, 0); - fontPropertyChanged = false; - } - fontFile = fontFile.deriveFont(fontSize); - // init font's metrics - fontFile.echarAdvance(' '); - TextSprite textSprites = - new TextSprite(fontFile, - content.length(), - new AffineTransform(), null); - textSprites.setRMode(TextState.MODE_FILL); - textSprites.setStrokeColor(fontColor); - textSprites.setFontName(EMBEDDED_FONT_NAME.toString()); - textSprites.setFontSize(fontSize); - - // iterate over each line of text painting the strings. - StringBuilder contents = new StringBuilder(content); - - float lineHeight = (float) (Math.floor(fontFile.getAscent()) + Math.floor(fontFile.getDescent())); - - float borderOffsetX = borderStyle.getStrokeWidth() / 2 + 1; // 1 pixel padding - float borderOffsetY = borderStyle.getStrokeWidth() / 2; - // is generally going to be zero, and af takes care of the offset for inset. - float advanceX = (float) bbox.getMinX() + borderOffsetX; - float advanceY = (float) bbox.getMinY() + borderOffsetY; - - float currentX; - // we don't want to shift the whole line width just the ascent - float currentY = advanceY + (float) fontFile.getAscent(); - - float lastx = 0; - float newAdvanceX; - char currentChar; - for (int i = 0, max = contents.length(); i < max; i++) { - - currentChar = contents.charAt(i); - - newAdvanceX = (float) fontFile.echarAdvance(currentChar).getX(); - currentX = advanceX + lastx; - lastx += newAdvanceX; - - // get normalized from from text sprite - if (!(currentChar == '\n' || currentChar == '\r')) { - textSprites.addText( - String.valueOf(currentChar), // cid - String.valueOf(currentChar), // unicode value - currentX, currentY, newAdvanceX); - } else { - // move back to start of next line - currentY += lineHeight; - advanceX = (float) bbox.getMinX() + borderOffsetX; - lastx = 0; - } - } - BasicStroke stroke; - if (strokeType && borderStyle.isStyleDashed()) { - stroke = new BasicStroke( - borderStyle.getStrokeWidth(), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, - borderStyle.getStrokeWidth() * 2.0f, borderStyle.getDashArray(), 0.0f); - } else { - stroke = new BasicStroke(borderStyle.getStrokeWidth()); - } - - // apply opacity graphics state. - shapes.add(new GraphicsStateCmd(EXT_GSTATE_NAME)); - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity))); - - // background colour - shapes.add(new ShapeDrawCmd(new Rectangle2D.Double(bbox.getX(), bbox.getY(), - bbox.getWidth() - insets * 2, bbox.getHeight() - insets * 2))); - if (fillType) { - shapes.add(new ColorDrawCmd(fillColor)); - shapes.add(new FillDrawCmd()); - } - // border - if (strokeType) { - shapes.add(new StrokeDrawCmd(stroke)); - shapes.add(new ColorDrawCmd(color)); - shapes.add(new DrawDrawCmd()); - } - // actual font. - shapes.add(new ColorDrawCmd(fontColor)); - shapes.add(new TextSpriteDrawCmd(textSprites)); - - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))); - - // update the appearance stream - // create/update the appearance stream of the xObject. - StateManager stateManager = library.getStateManager(); - Form form = updateAppearanceStream(shapes, bbox, matrix, - PostScriptEncoder.generatePostScript(shapes.getShapes())); - generateExternalGraphicsState(form, opacity); - - if (form != null) { - Rectangle2D formBbox = new Rectangle2D.Float(0, 0, - (float) bbox.getWidth(), (float) bbox.getHeight()); - form.setAppearance(shapes, matrix, formBbox); - stateManager.addChange(new PObject(form, form.getPObjectReference())); - // update the AP's stream bytes so contents can be written out - form.setRawBytes( - PostScriptEncoder.generatePostScript(shapes.getShapes())); - HashMap appearanceRefs = new HashMap(); - appearanceRefs.put(APPEARANCE_STREAM_NORMAL_KEY, form.getPObjectReference()); - entries.put(APPEARANCE_STREAM_KEY, appearanceRefs); - - // compress the form object stream. - if (compressAppearanceStream) { - form.getEntries().put(Stream.FILTER_KEY, new Name("FlateDecode")); - } else { - form.getEntries().remove(Stream.FILTER_KEY); - } - - // create the font - HashMap fontDictionary = new HashMap(); - fontDictionary.put(org.icepdf.core.pobjects.fonts.Font.TYPE_KEY, - org.icepdf.core.pobjects.fonts.Font.SUBTYPE_KEY); - fontDictionary.put(org.icepdf.core.pobjects.fonts.Font.SUBTYPE_KEY, - new Name("Type1")); - fontDictionary.put(org.icepdf.core.pobjects.fonts.Font.NAME_KEY, - EMBEDDED_FONT_NAME); - fontDictionary.put(org.icepdf.core.pobjects.fonts.Font.BASEFONT_KEY, - new Name(fontName)); - fontDictionary.put(org.icepdf.core.pobjects.fonts.Font.ENCODING_KEY, - new Name("WinAnsiEncoding")); - fontDictionary.put(new Name("FirstChar"), 32); - fontDictionary.put(new Name("LastChar"), 255); - - org.icepdf.core.pobjects.fonts.Font newFont; - if (form.getResources() == null || - form.getResources().getFont(EMBEDDED_FONT_NAME) == null) { - newFont = new org.icepdf.core.pobjects.fonts.ofont.Font( - library, fontDictionary); - newFont.setPObjectReference(stateManager.getNewReferencNumber()); - // create font entry - HashMap fontResources = new HashMap(); - fontResources.put(EMBEDDED_FONT_NAME, newFont.getPObjectReference()); - // add the font resource entry. - HashMap resources = new HashMap(); - resources.put(new Name("Font"), fontResources); - // and finally add it to the form. - form.getEntries().put(new Name("Resources"), resources); - form.setRawBytes("".getBytes()); - form.init(); - } else { - form.init(); - newFont = form.getResources().getFont(EMBEDDED_FONT_NAME); - Reference reference = newFont.getPObjectReference(); - newFont = new org.icepdf.core.pobjects.fonts.ofont.Font(library, fontDictionary); - newFont.setPObjectReference(reference); - } - // update hard reference to state manager and weak library reference. - stateManager.addChange(new PObject(newFont, newFont.getPObjectReference())); - library.addObject(newFont, newFont.getPObjectReference()); - } - - // build out a few backwards compatible strings. - StringBuilder dsString = new StringBuilder("font-size:") - .append(fontSize).append("pt;") - .append("font-family:").append(fontName).append(";") - .append("color:").append(ColorUtil.convertColorToRGB(fontColor)) - .append(";"); - if (fontStyle == Font.BOLD) { - dsString.append("font-weight:bold;"); - } - if (fontStyle == Font.ITALIC) { - dsString.append("font-style:italic;"); - } - if (fontStyle == Font.PLAIN) { - dsString.append("font-style:normal;"); - } - setString(DS_KEY, dsString.toString()); - - // write out the color - if (fillType) { - Color color = this.color; - // no AP stream then we need to set color as the fillColor, just the - // way it is. spec is a bit weak for FreeText. - if (entries.get(APPEARANCE_STREAM_KEY) == null) { - color = fillColor; - } - float[] compArray = new float[3]; - color.getColorComponents(compArray); - java.util.List colorValues = new ArrayList(compArray.length); - for (float comp : compArray) { - colorValues.add(comp); - } - entries.put(COLOR_KEY, colorValues); - } else { - entries.remove(COLOR_KEY); - } - - // write out the default content test. - setContents(content); - - // build out the rich text string. - Object[] colorArgument = new Object[]{dsString}; - MessageFormat formatter = new MessageFormat(BODY_START); - StringBuilder rcString = new StringBuilder(formatter.format(colorArgument)); - String[] lines = content.split("[\\r\\n]+"); - for (String line : lines) { - rcString.append("

").append(line).append("

"); - } - rcString.append(BODY_END); - setString(RC_KEY, rcString.toString()); - } - - public String getDefaultStylingString() { - return defaultStylingString; - } - - public void clearShapes() { - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - appearanceState.setShapes(null); - } - - public void setDocument(DefaultStyledDocument document) { - this.document = document; - } - - public boolean isHideRenderedOutput() { - return hideRenderedOutput; - } - - // print. Consider making it static. - public void setHideRenderedOutput(boolean hideRenderedOutput) { - this.hideRenderedOutput = hideRenderedOutput; - } - - public String getDefaultAppearance() { - return defaultAppearance; - } - - public void setDefaultAppearance(String defaultAppearance) { - this.defaultAppearance = defaultAppearance; - } - - public int getQuadding() { - return quadding; - } - - public void setQuadding(int quadding) { - this.quadding = quadding; - } - - public String getRichText() { - return richText; - } - - public void setRichText(String richText) { - this.richText = richText; - } - - public Color getFontColor() { - return fontColor; - } - - public void setFontColor(Color fontColor) { - this.fontColor = new Color(fontColor.getRGB()); - } - - public Color getFillColor() { - return fillColor; - } - - public void setFillColor(Color fillColor) { - this.fillColor = new Color(fillColor.getRGB()); - } - - public String getFontName() { - return fontName; - } - - public void setFontName(String fontName) { - this.fontName = fontName; - fontPropertyChanged = true; - } - - public int getFontStyle() { - return fontStyle; - } - - public void setFontStyle(int fontStyle) { - this.fontStyle = fontStyle; - } - - public int getFontSize() { - return fontSize; - } - - public void setFontSize(int fontSize) { - this.fontSize = fontSize; - fontPropertyChanged = true; - } - - public boolean isFillType() { - return fillType; - } - - public boolean isFontPropertyChanged() { - return fontPropertyChanged; - } - - public void setFillType(boolean fillType) { - this.fillType = fillType; - } - - public boolean isStrokeType() { - return strokeType; - } - - public void setStrokeType(boolean strokeType) { - this.strokeType = strokeType; - } - - public static final String BODY_START = - ""; - - public static final String BODY_END = ""; - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/GenericAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/GenericAnnotation.java deleted file mode 100644 index ca7c05e91d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/GenericAnnotation.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.util.Library; - -import java.awt.geom.AffineTransform; -import java.util.HashMap; - -/** - * Generic annotation that instantiated when an annotation subtype is not - * recognized. - * - * @since 5.0 - */ -public class GenericAnnotation extends Annotation { - - /** - * Creates a new instance of an Annotation. - * - * @param l document library. - * @param h dictionary entries. - */ - public GenericAnnotation(Library l, HashMap h) { - super(l, h); - } - - @Override - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/InkAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/InkAnnotation.java deleted file mode 100644 index 6a5acdb89b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/InkAnnotation.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.pobjects.graphics.commands.*; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -/** - * An ink annotation (PDF 1.3) represents a freehand “scribble†composed of one - * or more disjoint paths. When opened, it shall display a pop-up window - * containing the text of the associated note. Table 182 shows the annotation - * dictionary entries specific to this type of annotation. - * - * @since 5.0 - */ -public class InkAnnotation extends MarkupAnnotation { - - private static final Logger logger = - Logger.getLogger(InkAnnotation.class.toString()); - - /** - * (Required) An array of n arrays, each representing a stroked path. Each - * array shall be a series of alternating horizontal and vertical coordinates - * in default user space, specifying points along the path. When drawn, the - * points shall be connected by straight lines or curves in an - * implementation-dependent way - */ - public static final Name INK_LIST_KEY = new Name("InkList"); - - protected Shape inkPath; - - public InkAnnotation(Library l, HashMap h) { - super(l, h); - } - - @SuppressWarnings("unchecked") - public void init() throws InterruptedException{ - super.init(); - // look for an ink list - List> inkLists = library.getArray(entries, INK_LIST_KEY); - GeneralPath inkPaths = new GeneralPath(); - if (inkLists != null) { - inkPath = new GeneralPath(); - for (List inkList : inkLists) { - GeneralPath inkPath = null; - for (int i = 0, max = inkList.size() - 1; i < max; i += 2) { - if (inkPath == null) { - inkPath = new GeneralPath(); - inkPath.moveTo(inkList.get(i).floatValue(), inkList.get(i + 1).floatValue()); - } else { - inkPath.lineTo(inkList.get(i).floatValue(), inkList.get(i + 1).floatValue()); - } - } - inkPaths.append(inkPath, false); - } - } - this.inkPath = inkPaths; - if (!hasAppearanceStream() && inkPath != null) { - Object tmp = getObject(RECTANGLE_KEY); - Rectangle2D.Float rectangle = null; - if (tmp instanceof List) { - rectangle = library.getRectangle(entries, RECTANGLE_KEY); - } - if (rectangle != null) { - setBBox(rectangle.getBounds()); - } - resetAppearanceStream(new AffineTransform()); - } - - // try and generate an appearance stream. - resetNullAppearanceStream(); - } - - /** - * Converts the ink path back to an array of points. - * - * @param inkPath path to translate to an array - * @return an array of an array of points. - */ - private List> convertPathToArray(Shape inkPath) { - List> inkLists = new ArrayList>(); - List segment = null; - if (inkPath != null) { - PathIterator pathIterator = inkPath.getPathIterator(null); - float[] inkSegment = new float[6]; - int segmentType; - while (!pathIterator.isDone()) { - segmentType = pathIterator.currentSegment(inkSegment); - if (segmentType == PathIterator.SEG_MOVETO) { - segment = new ArrayList(); - segment.add(inkSegment[0]); - segment.add(inkSegment[1]); - inkLists.add(segment); - } else if (segmentType == PathIterator.SEG_LINETO) { - segment.add(inkSegment[0]); - segment.add(inkSegment[1]); - } - pathIterator.next(); - } - } - return inkLists; - } - - - /** - * Gets an instance of a InkAnnotation that has valid Object Reference. - * - * @param library document library - * @param rect bounding rectangle in user space - * @return new InkAnnotation Instance. - */ - public static InkAnnotation getInstance(Library library, - Rectangle rect) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE); - entries.put(Dictionary.SUBTYPE_KEY, Annotation.SUBTYPE_INK); - // coordinates - if (rect != null) { - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(rect)); - } else { - entries.put(Annotation.RECTANGLE_KEY, new Rectangle(10, 10, 50, 100)); - } - - // create the new instance - InkAnnotation inkAnnotation = null; - try { - inkAnnotation = new InkAnnotation(library, entries); - inkAnnotation.setPObjectReference(stateManager.getNewReferencNumber()); - inkAnnotation.init(); - inkAnnotation.setNew(true); - - // set default flags. - inkAnnotation.setFlag(Annotation.FLAG_READ_ONLY, false); - inkAnnotation.setFlag(Annotation.FLAG_NO_ROTATE, false); - inkAnnotation.setFlag(Annotation.FLAG_NO_ZOOM, false); - inkAnnotation.setFlag(Annotation.FLAG_PRINT, true); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Ink annotation instance creation was interrupted"); - } - - - return inkAnnotation; - } - - /** - * Resets the annotations appearance stream. - */ - public void resetAppearanceStream(double dx, double dy, AffineTransform pageSpace) { - - // setup clean shapes - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - appearanceState.setMatrix(new AffineTransform()); - appearanceState.setShapes(new Shapes()); - - // update the circle for any dx/dy moves. - AffineTransform af = new AffineTransform(); - af.setToTranslation(dx * pageSpace.getScaleX(), -dy * pageSpace.getScaleY()); - inkPath = af.createTransformedShape(inkPath); - entries.put(INK_LIST_KEY, convertPathToArray(inkPath)); - - Rectangle2D bbox = appearanceState.getBbox(); - bbox.setRect(userSpaceRectangle.x, userSpaceRectangle.y, userSpaceRectangle.width, userSpaceRectangle.height); - setUserSpaceRectangle(userSpaceRectangle); - - // setup the AP stream. - setModifiedDate(PDate.formatDateTime(new Date())); - - // save the stroke. - if (borderStyle.getStrokeWidth() == 0) { - borderStyle.setStrokeWidth(1); - } - Stroke stroke = getBorderStyleStroke(); - - Shapes shapes = appearanceState.getShapes(); - // setup the space for the AP content stream. - shapes.add(new GraphicsStateCmd(EXT_GSTATE_NAME)); - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity))); - shapes.add(new StrokeDrawCmd(stroke)); - shapes.add(new ColorDrawCmd(color)); - shapes.add(new ShapeDrawCmd(inkPath)); - shapes.add(new DrawDrawCmd()); - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))); - - // remove appearance stream if it exists on an existing edit. - entries.remove(APPEARANCE_STREAM_KEY); - - // we don't write out an appearance stream for ink annotation, we just regenerate it from properties - - // mark the change. - StateManager stateManager = library.getStateManager(); - stateManager.addChange(new PObject(this, this.getPObjectReference())); - - } - - public Shape getInkPath() { - return inkPath; - } - - public void setInkPath(Shape inkPath) { - this.inkPath = inkPath; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/LineAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/LineAnnotation.java deleted file mode 100644 index 2f47180c71..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/LineAnnotation.java +++ /dev/null @@ -1,713 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.pobjects.graphics.commands.*; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.*; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -/** - * The purpose of a line annotation (PDF 1.3) is to display a single straight - * line on the page. When opened, it shall display a pop-up window containing - * the text of the associated note. Table 175 shows the annotation dictionary - * entries specific to this type of annotation. - * - * @since 5.0 - */ -public class LineAnnotation extends MarkupAnnotation { - - private static final Logger logger = - Logger.getLogger(LineAnnotation.class.toString()); - - /** - * (Required) An array of four numbers, [x1 y1 x2 y2], specifying the starting - * and ending coordinates of the line in default user space. - *

- * If the LL entry is present, this value shall represent the endpoints of - * the leader lines rather than the endpoints of the line itself; see Figure 60. - */ - public static final Name L_KEY = new Name("L"); - /** - * (Optional; PDF 1.4) An array of two names specifying the line ending styles - * that shall be used in drawing the line. The first and second elements of - * the array shall specify the line ending styles for the endpoints defined, - * respectively, by the first and second pairs of coordinates, (x1, y1) and - * (x2, y2), in the L array. Table 176 shows the possible values. - *

- * Default value: [/None /None]. - */ - public static final Name LE_KEY = new Name("LE"); - /** - * (Required if LLE is present, otherwise optional; PDF 1.6) The length of - * leader lines in default user space that extend from each endpoint of the - * line perpendicular to the line itself, as shown in Figure 60. A positive - * value shall mean that the leader lines appear in the direction that is - * clockwise when traversing the line from its starting point to its ending - * point (as specified by L); a negative value shall indicate the opposite - * direction. - *

- * Default value: 0 (no leader lines). - */ - public static final Name LL_KEY = new Name("LL"); - /** - * (Optional; PDF 1.6) A non-negative number that shall represents the - * length of leader line extensions that extend from the line proper 180 - * degrees from the leader lines, as shown in Figure 60. - *

- * Default value: 0 (no leader line extensions). - */ - public static final Name LLE_KEY = new Name("LLE"); - /** - * (Optional; PDF 1.4) An array of numbers in the range 0.0 to 1.0 specifying - * the interior color that shall be used to fill the annotation’s line endings - * (see Table 176). The number of array elements shall determine the colour - * space in which the colour is defined: - * 0 - No colour; transparent - * 1 - DeviceGray - * 3 - DeviceRGB - * 4 - DeviceCMYK - */ - public static final Name IC_KEY = new Name("IC"); - /** - * (Optional; PDF 1.6) If true, the text specified by the Contents or RC - * entries shall be replicated as a caption in the appearance of the line, - * as shown in Figure 61 and Figure 62. The text shall be rendered in a - * manner appropriate to the content, taking into account factors such as - * writing direction. - *

- * Default value: false. - */ - public static final Name CAP_KEY = new Name("Cap"); - /** - * (Optional; PDF 1.7) A non-negative number that shall represent the length - * of the leader line offset, which is the amount of empty space between the - * endpoints of the annotation and the beginning of the leader lines. - */ - public static final Name LLO_KEY = new Name("LLO"); - - /** - * (Optional; PDF 1.6) A name describing the intent of the line annotation - * (see also Table 170). Valid values shall be LineArrow, which means that - * the annotation is intended to function as an arrow, and LineDimension, - * which means that the annotation is intended to function as a dimension line. - */ -// public static final Name IT_KEY = new Name("IT"); - /** - * (Optional; meaningful only if Cap is true; PDF 1.7) A name describing the - * annotation’s caption positioning. Valid values are Inline, meaning the - * caption shall be centered inside the line, and Top, meaning the caption - * shall be on top of the line. - *

- * Default value: Inline - */ - public static final Name CP_KEY = new Name("CP"); - /** - * (Optional; PDF 1.7) A measure dictionary (see Table 261) that shall - * specify the scale and units that apply to the line annotation. - */ - public static final Name MEASURE_KEY = new Name("Measure"); - /** - * (Optional; meaningful only if Cap is true; PDF 1.7) An array of two numbers - * that shall specify the offset of the caption text from its normal position. - * The first value shall be the horizontal offset along the annotation line - * from its midpoint, with a positive value indicating offset to the right - * and a negative value indicating offset to the left. The second value shall - * be the vertical offset perpendicular to the annotation line, with a - * positive value indicating a shift up and a negative value indicating a - * shift down. - *

- * Default value: [0, 0] (no offset from normal positioning) - */ - public static final Name CO_KEY = new Name("CO"); - /** - * A square filled with the annotation’s interior color, if any - */ - public static final Name LINE_END_NONE = new Name("None"); - /** - * A circle filled with the annotation’s interior color, if any - */ - public static final Name LINE_END_SQUARE = new Name("Square"); - /** - * A diamond shape filled with the annotation’s interior color, if any - */ - public static final Name LINE_END_CIRCLE = new Name("Circle"); - /** - * Two short lines meeting in an acute angle to form an open arrowhead - */ - public static final Name LINE_END_DIAMOND = new Name("Diamond"); - /** - * Two short lines meeting in an acute angle as in the OpenArrow style and - * connected by a third line to form a triangular closed arrowhead filled - * with the annotation’s interior color, if any - */ - public static final Name LINE_END_OPEN_ARROW = new Name("OpenArrow"); - /** - * No line ending - */ - public static final Name LINE_END_CLOSED_ARROW = new Name("ClosedArrow"); - - protected Point2D startOfLine; - protected Point2D endOfLine; - protected Color interiorColor; - - // default line caps. - protected Name startArrow = LINE_END_NONE; - protected Name endArrow = LINE_END_NONE; - - public LineAnnotation(Library l, HashMap h) { - super(l, h); - } - - /** - * Gets an instance of a LineAnnotation that has valid Object Reference. - * - * @param library document library - * @param rect bounding rectangle in user space - * @return new LineAnnotation Instance. - */ - public static LineAnnotation getInstance(Library library, - Rectangle rect) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE); - entries.put(Dictionary.SUBTYPE_KEY, Annotation.SUBTYPE_LINE); - // coordinates - if (rect != null) { - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(rect)); - } else { - entries.put(Annotation.RECTANGLE_KEY, new Rectangle(10, 10, 50, 100)); - } - // create the new instance - LineAnnotation lineAnnotation = null; - try { - lineAnnotation = new LineAnnotation(library, entries); - lineAnnotation.init(); - lineAnnotation.setPObjectReference(stateManager.getNewReferencNumber()); - lineAnnotation.setNew(true); - } catch (InterruptedException e) { - logger.fine("Line annotation instance creation was interrupted"); - } - return lineAnnotation; - } - - public static Logger getLogger() { - return logger; - } - - public static void drawLineStart(Graphics2D g, Name lineEnding, - Point2D startOfLine, Point2D endOfLine, - Color lineColor, Color interiorColor) { - if (lineEnding.equals(LineAnnotation.LINE_END_OPEN_ARROW)) { - drawOpenArrowStart(g, startOfLine, endOfLine, lineColor, interiorColor); - } else if (lineEnding.equals(LineAnnotation.LINE_END_CLOSED_ARROW)) { - drawClosedArrowStart(g, startOfLine, endOfLine, lineColor, interiorColor); - } else if (lineEnding.equals(LineAnnotation.LINE_END_CIRCLE)) { - drawCircle(g, startOfLine, startOfLine, endOfLine, lineColor, interiorColor); - } else if (lineEnding.equals(LineAnnotation.LINE_END_DIAMOND)) { - drawDiamond(g, startOfLine, startOfLine, endOfLine, lineColor, interiorColor); - } else if (lineEnding.equals(LineAnnotation.LINE_END_SQUARE)) { - drawSquare(g, startOfLine, startOfLine, endOfLine, lineColor, interiorColor); - } - } - - public static void drawLineEnd(Graphics2D g, Name lineEnding, - Point2D startOfLine, Point2D endOfLine, - Color lineColor, Color interiorColor) { - if (lineEnding.equals(LineAnnotation.LINE_END_OPEN_ARROW)) { - drawOpenArrowEnd(g, startOfLine, endOfLine, lineColor, interiorColor); - } else if (lineEnding.equals(LineAnnotation.LINE_END_CLOSED_ARROW)) { - drawClosedArrowEnd(g, startOfLine, endOfLine, lineColor, interiorColor); - } else if (lineEnding.equals(LineAnnotation.LINE_END_CIRCLE)) { - drawCircle(g, endOfLine, startOfLine, endOfLine, lineColor, interiorColor); - } else if (lineEnding.equals(LineAnnotation.LINE_END_DIAMOND)) { - drawDiamond(g, endOfLine, startOfLine, endOfLine, lineColor, interiorColor); - } else if (lineEnding.equals(LineAnnotation.LINE_END_SQUARE)) { - drawSquare(g, endOfLine, startOfLine, endOfLine, lineColor, interiorColor); - } - } - - public static void circleDrawOps(Shapes shapes, - Point2D point, Point2D start, - Point2D end, Color lineColor, - Color internalColor) { - AffineTransform af = createRotation(point, start, end); - shapes.add(new TransformDrawCmd(af)); - shapes.add(new ColorDrawCmd(lineColor)); - shapes.add(new ShapeDrawCmd(createCircleEnd())); - shapes.add(new FillDrawCmd()); - } - - private static Shape createCircleEnd() { - return new Ellipse2D.Double(-4, -4, 8, 8); - } - - private static void drawCircle(Graphics2D g, Point2D point, - Point2D startOfLine, Point2D endOfLine, - Color lineColor, Color interiorColor) { - AffineTransform oldAf = g.getTransform(); - AffineTransform af = createRotation(point, startOfLine, endOfLine); - AffineTransform gAf = g.getTransform(); - gAf.concatenate(af); - g.setTransform(gAf); - g.setColor(lineColor); - g.fill(createCircleEnd()); - g.setTransform(oldAf); - } - - public static void diamondDrawOps(Shapes shapes, - Point2D point, Point2D start, - Point2D end, Color lineColor, - Color internalColor) { - AffineTransform tx = new AffineTransform(); - Line2D.Double line = new Line2D.Double(start, end); - tx.setToIdentity(); - double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1); - tx.translate(point.getX(), point.getY()); - tx.rotate(angle - (Math.PI / 4)); - - AffineTransform af = createRotation(point, start, end); - shapes.add(new TransformDrawCmd(af)); - shapes.add(new ColorDrawCmd(lineColor)); - shapes.add(new ShapeDrawCmd(createSquareEnd())); - shapes.add(new FillDrawCmd()); - } - - private static void drawDiamond(Graphics2D g, Point2D point, - Point2D startOfLine, Point2D endOfLine, - Color lineColor, Color interiorColor) { - AffineTransform oldAf = g.getTransform(); - AffineTransform tx = new AffineTransform(); - Line2D.Double line = new Line2D.Double(startOfLine, endOfLine); - tx.setToIdentity(); - double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1); - tx.translate(point.getX(), point.getY()); - // quarter rotation - tx.rotate(angle - (Math.PI / 4)); - AffineTransform gAf = g.getTransform(); - gAf.concatenate(tx); - g.setTransform(gAf); - g.setColor(lineColor); - g.fill(createSquareEnd()); - g.setTransform(oldAf); - } - - public static void squareDrawOps(Shapes shapes, - Point2D point, Point2D start, - Point2D end, Color lineColor, - Color internalColor) { - AffineTransform af = createRotation(point, start, end); - shapes.add(new TransformDrawCmd(af)); - shapes.add(new ColorDrawCmd(lineColor)); - shapes.add(new ShapeDrawCmd(createSquareEnd())); - shapes.add(new FillDrawCmd()); - } - - private static Shape createSquareEnd() { - return new Rectangle2D.Double(-4, -4, 8, 8); - } - - private static void drawSquare(Graphics2D g, Point2D point, - Point2D startOfLine, Point2D endOfLine, - Color lineColor, Color interiorColor) { - AffineTransform oldAf = g.getTransform(); - AffineTransform af = createRotation(point, startOfLine, endOfLine); - AffineTransform gAf = g.getTransform(); - gAf.concatenate(af); - g.setTransform(gAf); - g.setColor(lineColor); - g.fill(createSquareEnd()); - g.setTransform(oldAf); - } - - public static void openArrowEndDrawOps(Shapes shapes, - Point2D start, Point2D end, - Color lineColor, Color internalColor) { - AffineTransform af = createRotation(end, start, end); - shapes.add(new TransformDrawCmd(af)); - shapes.add(new ColorDrawCmd(lineColor)); - shapes.add(new ShapeDrawCmd(createOpenArrowEnd())); - shapes.add(new DrawDrawCmd()); - } - - private static Shape createOpenArrowEnd() { - GeneralPath arrowHead = new GeneralPath(); - arrowHead.moveTo(0, 0); - arrowHead.lineTo(5, -10); - arrowHead.moveTo(0, 0); - arrowHead.lineTo(-5, -10); - arrowHead.closePath(); - return arrowHead; - } - - private static void drawOpenArrowEnd(Graphics2D g, - Point2D startOfLine, Point2D endOfLine, - Color lineColor, Color interiorColor) { - Shape arrowHead = createOpenArrowEnd(); - AffineTransform oldAf = g.getTransform(); - AffineTransform af = createRotation(endOfLine, startOfLine, endOfLine); - AffineTransform gAf = g.getTransform(); - gAf.concatenate(af); - g.setTransform(gAf); - g.setColor(lineColor); - g.draw(arrowHead); - g.setTransform(oldAf); - } - - public static void openArrowStartDrawOps(Shapes shapes, - Point2D start, Point2D end, - Color lineColor, Color internalColor) { - AffineTransform af = createRotation(start, start, end); - shapes.add(new TransformDrawCmd(af)); - shapes.add(new ColorDrawCmd(lineColor)); - shapes.add(new ShapeDrawCmd(createOpenArrowStart())); - shapes.add(new DrawDrawCmd()); - } - - private static Shape createOpenArrowStart() { - GeneralPath arrowHead = new GeneralPath(); - arrowHead.moveTo(0, 0); - arrowHead.lineTo(5, 10); - arrowHead.moveTo(0, 0); - arrowHead.lineTo(-5, 10); - arrowHead.closePath(); - return arrowHead; - } - - private static void drawOpenArrowStart(Graphics2D g, - Point2D startOfLine, Point2D endOfLine, - Color lineColor, Color interiorColor) { - Shape arrowHead = createOpenArrowStart(); - AffineTransform oldAf = g.getTransform(); - AffineTransform af = createRotation(startOfLine, startOfLine, endOfLine); - AffineTransform gAf = g.getTransform(); - gAf.concatenate(af); - g.setTransform(gAf); - g.setColor(lineColor); - g.draw(arrowHead); - g.setTransform(oldAf); - } - - public static void closedArrowStartDrawOps(Shapes shapes, - Point2D start, Point2D end, - Color lineColor, Color internalColor) { - AffineTransform af = createRotation(start, start, end); - shapes.add(new TransformDrawCmd(af)); - if (internalColor != null) { - shapes.add(new ColorDrawCmd(internalColor)); - shapes.add(new ShapeDrawCmd(createClosedArrowStart())); - shapes.add(new FillDrawCmd()); - } - shapes.add(new ColorDrawCmd(lineColor)); - shapes.add(new ShapeDrawCmd(createClosedArrowStart())); - shapes.add(new DrawDrawCmd()); - } - - private static Shape createClosedArrowStart() { - Polygon arrowHead = new Polygon(); - arrowHead.addPoint(0, -5); - arrowHead.addPoint(-5, 5); - arrowHead.addPoint(5, 5); - return arrowHead; - } - - private static void drawClosedArrowStart(Graphics2D g, - Point2D startOfLine, Point2D endOfLine, - Color lineColor, Color interiorColor) { - Shape arrowHead = createClosedArrowStart(); - AffineTransform oldAf = g.getTransform(); - AffineTransform af = createRotation(startOfLine, startOfLine, endOfLine); - AffineTransform gAf = g.getTransform(); - gAf.concatenate(af); - g.setTransform(gAf); - if (interiorColor != null) { - g.setColor(interiorColor); - g.fill(arrowHead); - } - g.setColor(lineColor); - g.draw(arrowHead); - g.setTransform(oldAf); - } - - public static void closedArrowEndDrawOps(Shapes shapes, - Point2D start, Point2D end, - Color lineColor, Color internalColor) { - AffineTransform af = createRotation(end, start, end); - shapes.add(new TransformDrawCmd(af)); - if (internalColor != null) { - shapes.add(new ColorDrawCmd(internalColor)); - shapes.add(new ShapeDrawCmd(createClosedArrowEnd())); - shapes.add(new FillDrawCmd()); - } - shapes.add(new ColorDrawCmd(lineColor)); - shapes.add(new ShapeDrawCmd(createClosedArrowEnd())); - shapes.add(new DrawDrawCmd()); - } - - private static Shape createClosedArrowEnd() { - Polygon arrowHead = new Polygon(); - arrowHead.addPoint(0, 5); - arrowHead.addPoint(-5, -5); - arrowHead.addPoint(5, -5); - return arrowHead; - } - - private static void drawClosedArrowEnd(Graphics2D g, - Point2D startOfLine, Point2D endOfLine, - Color lineColor, Color interiorColor) { - Shape arrowHead = createClosedArrowEnd(); - AffineTransform oldAf = g.getTransform(); - AffineTransform af = createRotation(endOfLine, startOfLine, endOfLine); - AffineTransform gAf = g.getTransform(); - gAf.concatenate(af); - g.setTransform(gAf); - if (interiorColor != null) { - g.setColor(interiorColor); - g.fill(arrowHead); - } - g.setColor(lineColor); - g.draw(arrowHead); - g.setTransform(oldAf); - } - - private static AffineTransform createRotation(Point2D point, - Point2D startOfLine, - Point2D endOfLine) { - AffineTransform tx = new AffineTransform(); - Line2D.Double line = new Line2D.Double(startOfLine, endOfLine); - tx.setToIdentity(); - double angle = Math.atan2(line.y2 - line.y1, line.x2 - line.x1); - tx.translate(point.getX(), point.getY()); - tx.rotate(angle - (Math.PI / 2)); - return tx; - } - - @SuppressWarnings("unchecked") - public void init() throws InterruptedException { - super.init(); - // line points - List value = library.getArray(entries, L_KEY); - if (value != null) { - startOfLine = new Point2D.Float(value.get(0).floatValue(), value.get(1).floatValue()); - endOfLine = new Point2D.Float(value.get(2).floatValue(), value.get(3).floatValue()); - } - - // line ends. - List value2 = library.getArray(entries, LE_KEY); - if (value2 != null) { - startArrow = (Name) value2.get(0); - endArrow = (Name) value2.get(1); - } - - // parse out interior colour, specific to link annotations. - interiorColor = null; // we default to black but probably should be null - List C = (List) getObject(IC_KEY); - // parse thought rgb colour. - if (C != null && C.size() >= 3) { - float red = ((Number) C.get(0)).floatValue(); - float green = ((Number) C.get(1)).floatValue(); - float blue = ((Number) C.get(2)).floatValue(); - red = Math.max(0.0f, Math.min(1.0f, red)); - green = Math.max(0.0f, Math.min(1.0f, green)); - blue = Math.max(0.0f, Math.min(1.0f, blue)); - interiorColor = new Color(red, green, blue); - } - - // check if there is an AP entry, if no generate the shapes data - // from the other properties. - if (!hasAppearanceStream() && startOfLine != null && endOfLine != null) { - Object tmp = getObject(RECTANGLE_KEY); - Rectangle2D.Float rectangle = null; - if (tmp instanceof List) { - rectangle = library.getRectangle(entries, RECTANGLE_KEY); - } - if (rectangle != null) { - setBBox(rectangle.getBounds()); - } - resetAppearanceStream(new AffineTransform()); - } - // try and generate an appearance stream. - resetNullAppearanceStream(); - } - - /** - * Resets the annotations appearance stream. - */ - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - - // nothing to reset, creating new annotation. - if (startOfLine == null || endOfLine == null) { - return; - } - - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - AffineTransform matrix = appearanceState.getMatrix(); - // reset transform and shapes. - appearanceState.setMatrix(new AffineTransform()); - appearanceState.setShapes(new Shapes()); - - // adjust the line's start and end points for any potential move - AffineTransform af = new AffineTransform(); - af.setToTranslation(dx * pageTransform.getScaleX(), -dy * pageTransform.getScaleY()); - af.transform(startOfLine, startOfLine); - af.transform(endOfLine, endOfLine); - setStartOfLine(startOfLine); - setEndOfLine(endOfLine); - - Rectangle2D bbox = appearanceState.getBbox(); - bbox.setRect(userSpaceRectangle.x, userSpaceRectangle.y, userSpaceRectangle.width, userSpaceRectangle.height); - setUserSpaceRectangle(userSpaceRectangle); - - setModifiedDate(PDate.formatDateTime(new Date())); - - // draw the basic line. - Stroke stroke = getBorderStyleStroke(); - GeneralPath line = new GeneralPath(); - line.moveTo((float) startOfLine.getX(), (float) startOfLine.getY()); - line.lineTo((float) endOfLine.getX(), (float) endOfLine.getY()); - line.closePath(); - - Shapes shapes = appearanceState.getShapes(); -// shapes.add(new GraphicsStateCmd(EXT_GSTATE_NAME)); - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity))); - shapes.add(new ShapeDrawCmd(line)); - shapes.add(new StrokeDrawCmd(stroke)); - shapes.add(new ColorDrawCmd(color)); - shapes.add(new DrawDrawCmd()); - - // check for a ending end cap. - if (startArrow.equals(LineAnnotation.LINE_END_OPEN_ARROW)) { - openArrowStartDrawOps( - shapes, startOfLine, endOfLine, color, interiorColor); - } else if (startArrow.equals(LineAnnotation.LINE_END_CLOSED_ARROW)) { - closedArrowStartDrawOps( - shapes, startOfLine, endOfLine, color, interiorColor); - } else if (startArrow.equals(LineAnnotation.LINE_END_CIRCLE)) { - circleDrawOps( - shapes, startOfLine, startOfLine, endOfLine, color, interiorColor); - } else if (startArrow.equals(LineAnnotation.LINE_END_DIAMOND)) { - diamondDrawOps( - shapes, startOfLine, startOfLine, endOfLine, color, interiorColor); - } else if (startArrow.equals(LineAnnotation.LINE_END_SQUARE)) { - squareDrawOps( - shapes, startOfLine, startOfLine, endOfLine, color, interiorColor); - } - // check for a starting end cap. - if (endArrow.equals(LineAnnotation.LINE_END_OPEN_ARROW)) { - openArrowEndDrawOps( - shapes, startOfLine, endOfLine, color, interiorColor); - } else if (endArrow.equals(LineAnnotation.LINE_END_CLOSED_ARROW)) { - closedArrowEndDrawOps( - shapes, startOfLine, endOfLine, color, interiorColor); - } else if (endArrow.equals(LineAnnotation.LINE_END_CIRCLE)) { - circleDrawOps( - shapes, endOfLine, startOfLine, endOfLine, color, interiorColor); - } else if (endArrow.equals(LineAnnotation.LINE_END_DIAMOND)) { - diamondDrawOps( - shapes, endOfLine, startOfLine, endOfLine, color, interiorColor); - } else if (endArrow.equals(LineAnnotation.LINE_END_SQUARE)) { - squareDrawOps( - shapes, endOfLine, startOfLine, endOfLine, color, interiorColor); - } - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))); - - // remove appearance stream if it exists on an existing edit. - entries.remove(APPEARANCE_STREAM_KEY); - - // we don't write out an appearance stream for line annotation, we just regenerate it from properties - - // mark the change. - StateManager stateManager = library.getStateManager(); - stateManager.addChange(new PObject(this, this.getPObjectReference())); - } - - public Point2D getStartOfLine() { - return startOfLine; - } - - public void setStartOfLine(Point2D startOfLine) { - this.startOfLine = startOfLine; - } - - public Point2D getEndOfLine() { - return endOfLine; - } - - public void setEndOfLine(Point2D endOfLine) { - this.endOfLine = endOfLine; - List pointArray = new ArrayList(4); - pointArray.add((float) startOfLine.getX()); - pointArray.add((float) startOfLine.getY()); - pointArray.add((float) endOfLine.getX()); - pointArray.add((float) endOfLine.getY()); - entries.put(L_KEY, pointArray); - } - - public Color getInteriorColor() { - return interiorColor; - } - - public void setInteriorColor(Color interiorColor) { - this.interiorColor = interiorColor; - float[] compArray = new float[3]; - this.interiorColor.getColorComponents(compArray); - List colorValues = new ArrayList(compArray.length); - for (float comp : compArray) { - colorValues.add(comp); - } - entries.put(IC_KEY, colorValues); - } - - public Name getStartArrow() { - return startArrow; - } - - public void setStartArrow(Name startArrow) { - this.startArrow = startArrow; - List endNameArray = new ArrayList(2); - endNameArray.add(startArrow); - endNameArray.add(endArrow); - entries.put(LE_KEY, endNameArray); - } - - public Name getEndArrow() { - return endArrow; - } - - public void setEndArrow(Name endArrow) { - this.endArrow = endArrow; - List endNameArray = new ArrayList(2); - endNameArray.add(startArrow); - endNameArray.add(endArrow); - entries.put(LE_KEY, endNameArray); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/LinkAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/LinkAnnotation.java deleted file mode 100644 index 9d8e683def..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/LinkAnnotation.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.util.HashMap; -import java.util.logging.Logger; - - -/** - *

Refer to: 8.4.5 Annotation Types

- *

- * - * - * - *
Key Type Value
Subtype name (Required) The type of - * annotation that this dictionary describes; must be Link for a link - * annotation.
Dest array, name, or - * string (Optional; not permitted if an A entry is - * present) A destination to be displayed when the annotation is activated - * (see Section 8.2.1, "Destinations"; see also implementation note 90 in - * Appendix H).
H name(Optional; PDF 1.2) The annotation's highlighting mode, the - * visual effect to be used when the mouse button is pressed or held down inside - * its active area: - *
N (None) No - * highlighting.
I (Invert) Invert the contents of - * the annotation rectangle.
O (Outline) Invert the - * annotation's border.
P (Push) Display the - * annotation as if it were being pushed below the surface of the page; see - * implementation note 91 in Appendix H.
Acrobat viewer displays the link - * appearance with bevel border, ignoring any down appearance.
Default value: I.
QuadPointsarray (Optional; PDF 1.6) An array of 8 x n numbers - * specifying the coordinates of n quadrilaterals in default user space that - * comprise the region in which the link should be activated. The coordinates - * for each quadrilateral are given in the order
x1 y1 x2 y2 x3 y3 x4 y4
- * specifying the four vertices of the quadrilateral in counterclockwise order. - * For orientation purposes, such as when applying an underline border style, - * the bottom of a quadrilateral is the line formed by (x1, y1) and (x2, y2). If - * this entry is not present or the viewer application does not recognize it, - * the region specified by the Rect entry should be used. - * QuadPoints should be ignored if any coordinate in the array lies - * outside the region specified by Rect.
- * - * @author Mark Collette - * @since 2.5 - */ -public class LinkAnnotation extends Annotation { - - private static final Logger logger = - Logger.getLogger(LinkAnnotation.class.toString()); - - /** - * Key used to indicate highlight mode. - */ - public static final Name DESTINATION_KEY = new Name("Dest"); - - /** - * Key used to indcate highlight mode. - */ - public static final Name HIGHLIGHT_MODE_KEY = new Name("H"); - - /** - * Indicates that the annotation has no highlight effect. - */ - public static final Name HIGHLIGHT_NONE = new Name("N"); - - /** - * Indicates that the annotation rectangle colours should be inverted for - * its highlight effect. - */ - public static final Name HIGHLIGHT_INVERT = new Name("I"); - - /** - * Indicates that the annotation rectangle border should be inverted for its - * highlight effect. - */ - public static final Name HIGHLIGHT_OUTLINE = new Name("O"); - - /** - * Indicates that the annotation rectangle border should be pushed below the - * surface of th page. - */ - public static final Name HIGHLIGHT_PUSH = new Name("P"); - - /** - * Creates a new instance of a LinkAnnotation. - * - * @param l document library. - * @param h dictionary entries. - */ - public LinkAnnotation(Library l, HashMap h) { - super(l, h); - } - - /** - * Gets an instance of a LinkAnnotation that has valid Object Reference. - * - * @param library document library - * @param rect bounding rectangle in user space - * @return new LinkAnnotation Instance. - */ - public static LinkAnnotation getInstance(Library library, - Rectangle rect) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE); - entries.put(Dictionary.SUBTYPE_KEY, Annotation.SUBTYPE_LINK); - // coordinates - if (rect != null) { - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(rect)); - } else { - entries.put(Annotation.RECTANGLE_KEY, new Rectangle(10, 10, 50, 100)); - } - // write out the default highlight state. - entries.put(HIGHLIGHT_MODE_KEY, HIGHLIGHT_INVERT); - - // create the new instance - LinkAnnotation linkAnnotation = null; - try { - linkAnnotation = new LinkAnnotation(library, entries); - linkAnnotation.init(); - linkAnnotation.setPObjectReference(stateManager.getNewReferencNumber()); - linkAnnotation.setNew(true); - - // set default flags. - linkAnnotation.setFlag(Annotation.FLAG_READ_ONLY, false); - linkAnnotation.setFlag(Annotation.FLAG_NO_ROTATE, false); - linkAnnotation.setFlag(Annotation.FLAG_NO_ZOOM, false); - linkAnnotation.setFlag(Annotation.FLAG_PRINT, true); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Link annotation instance creation was interrupted"); - } - - return linkAnnotation; - } - - public void init() throws InterruptedException { - super.init(); - // try and generate an appearance stream. - resetNullAppearanceStream(); - } - - /** - *

Gets the link annotations highlight mode (visual effect)taht should - * be displayed when the mouse button is pressed or held down inside it's - * active area.

- * - * @return one of the predefined highlight effects, HIGHLIGHT_NONE, - * HIGHLIGHT_OUTLINE or HIGHLIGHT_PUSH. - */ - public Name getHighlightMode() { - Object possibleName = getObject(HIGHLIGHT_MODE_KEY); - if (possibleName instanceof Name) { - Name name = (Name) possibleName; - if (HIGHLIGHT_NONE.equals(name)) { - return HIGHLIGHT_NONE; - } else if (HIGHLIGHT_OUTLINE.equals(name)) { - return HIGHLIGHT_OUTLINE; - } else if (HIGHLIGHT_PUSH.equals(name)) { - return HIGHLIGHT_PUSH; - } - } - return HIGHLIGHT_INVERT; - } - - /** - * A destination to be displayed when the annotation is ativated. Only - * permitted if an A entry is not present. - * - * @return annotation target destination, null if not present in - * annotation. - */ - public Destination getDestination() { - Object obj = getObject(DESTINATION_KEY); - if (obj != null) { - return new Destination(library, obj); - } - return null; - } - - @Override - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/MarkupAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/MarkupAnnotation.java deleted file mode 100644 index 5c3c1adce2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/MarkupAnnotation.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.graphics.GraphicsState; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * As mentioned in 12.5.2, “Annotation Dictionaries,†the meaning of an - * annotation’s Contents entry varies by annotation type. Typically, it is the - * text that shall be displayed for the annotation or, if the annotation does not - * display text, an alternate description of the annotation’s contents in - * human-readable form. In either case, the Contents entry is useful when - * extracting the document’s contents in support of accessibility to users with - * disabilities or for other purposes (see 14.9.3, “Alternate Descriptionsâ€). - *

- * Many annotation types are defined as markup annotations because they are used - * primarily to mark up PDF documents (see Table 170). These annotations have - * text that appears as part of the annotation and may be displayed in other ways - * by a conforming reader, such as in a Comments pane. - *

- * Markup annotations may be divided into the following groups: - *

    - *
  • Free text annotations display text directly on the page. The annotation’s - * Contents entry specifies the displayed text.
  • - *
  • Most other markup annotations have an associated pop-up window that may - * contain text. The annotation’s Contents entry specifies the text that shall - * be displayed when the pop-up window is opened. These include text, line, - * square, circle, polygon, polyline, highlight, underline, squiggly-underline, - * strikeout, rubber stamp, caret, ink, and file attachment annotations.
  • - *
  • Sound annotations do not have a pop-up window but may also have associated - * text specified by the Contents entry.
  • - *
- * - * @since 5.0 - */ -public abstract class MarkupAnnotation extends Annotation { - - /** - * Optional; PDF 1.1) The text label that shall be displayed in the title bar - * of the annotation’s pop-up window when open and active. This entry shall - * identify the user who added the annotation. - */ - public static final Name T_KEY = new Name("T"); - - /** - * (Optional; PDF 1.4) The constant opacity value that shall be used in - * painting the annotation (see Sections 11.2, “Overview of Transparency,†- * and 11.3.7, “Shape and Opacity Computationsâ€). This value shall apply to - * all visible elements of the annotation in its closed state (including its - * background and border) but not to the pop-up window that appears when the - * annotation is opened. - */ - public static final Name CA_KEY = new Name("CA"); - - /** - * (Optional; PDF 1.5) A rich text string (see 12.7.3.4, “Rich Text Stringsâ€) - * that shall be displayed in the pop-up window when the annotation is opened. - */ - public static final Name RC_KEY = new Name("RC"); - - /** - * (Optional; PDF 1.5) The date and time (7.9.4, “Datesâ€) when the - * annotation was created. - */ - public static final Name CREATION_DATE_KEY = new Name("CreationDate"); - - /** - * (Required if an RT entry is present, otherwise optional; PDF 1.5) A - * reference to the annotation that this annotation is “in reply to.†Both - * annotations shall be on the same page of the document. The relationship - * between the two annotations shall be specified by the RT entry. - *

- * If this entry is present in an FDF file (see 12.7.7, “Forms Data Formatâ€), - * its type shall not be a dictionary but a text string containing the - * contents of the NM entry of the annotation being replied to, to allow for - * a situation where the annotation being replied to is not in the same FDF - * file. - */ - public static final Name IRT_KEY = new Name("IRT"); - - /** - * (Optional; PDF 1.5) Text representing a short description of the subject - * being addressed by the annotation. - */ - public static final Name SUBJ_KEY = new Name("Subj"); - - /** - * (Optional; PDF 1.3) An indirect reference to a pop-up annotation for - * entering or editing the text associated with this annotation. - */ - public static final Name POPUP_KEY = new Name("Popup"); - - /** - * Optional; meaningful only if IRT is present; PDF 1.6) A name specifying - * the relationship (the “reply typeâ€) between this annotation and one - * specified by IRT. Valid values are: - *

- * R - The annotation shall be considered a reply to the annotation specified - * by IRT. Conforming readers shall not display replies to an annotation - * individually but together in the form of threaded comments. - *

- * Group - The annotation shall be grouped with the annotation specified by - * IRT; see the discussion following this Table. - *

- * Default value: R. - */ - public static final Name RT_KEY = new Name("RT"); - - /** - * (Optional; PDF 1.6) A name describing the intent of the markup annotation. - * Intents allow conforming readers to distinguish between different uses - * and behaviors of a single markup annotation type. If this entry is not - * present or its value is the same as the annotation type, the annotation - * shall have no explicit intent and should behave in a generic manner in a - * conforming reader. - *

- * Free text annotations (Table 174), line annotations (Table 175), polygon - * annotations (Table 178), and (PDF 1.7) polyline annotations (Table 178) - * have defined intents, whose values are enumerated in the corresponding - * tables. - */ - public static final Name IT_KEY = new Name("IT"); - - /** - * (Optional; PDF 1.7) An external data dictionary specifying data that shall - * be associated with the annotation. This dictionary contains the following - * entries: - *

- * Type - (optional) If present, shall be ExData. - *

- * Subtype - (required) a name specifying the type of data that the markup - * annotation shall be associated with. The only defined value is Markup3D. - * Table 298 lists the values that correspond to a subtype of Markup3D. - */ - public static final Name EX_DATA_KEY = new Name("ExData"); - - /** - * Named graphics state name used to store transparency values. - */ - public static final Name EXT_GSTATE_NAME = new Name("ip1"); - - protected String titleText; - protected PopupAnnotation popupAnnotation; - protected float opacity = 1.0f; - protected String richText; - protected PDate creationDate; - protected MarkupAnnotation inReplyToAnnotation; - protected String subject; - protected Name replyToRelation = new Name("R"); - protected Name intent; - // exData not implemented - - public MarkupAnnotation(Library l, HashMap h) { - super(l, h); - } - - public void init() throws InterruptedException { - super.init(); - // title text - titleText = getString(T_KEY); - - // rich text - richText = getString(RC_KEY); - - // subject text - subject = getString(SUBJ_KEY); - - // creation date - Object value = library.getObject(entries, CREATION_DATE_KEY); - if (value != null && value instanceof StringObject) { - creationDate = new PDate(securityManager, getString(CREATION_DATE_KEY)); - } - - // popup child - value = library.getObject(entries, POPUP_KEY); - if (value != null && value instanceof PopupAnnotation) { - popupAnnotation = (PopupAnnotation) value; - } - - // opacity - float ca = library.getFloat(entries, CA_KEY); - if (ca != 0.0f) { - opacity = ca; - } - - // in reply to annotation - value = library.getObject(entries, IRT_KEY); - if (value != null && value instanceof MarkupAnnotation) { - inReplyToAnnotation = (MarkupAnnotation) value; - } - - // in reply to annotation - value = library.getName(entries, RT_KEY); - if (value != null) { - replyToRelation = (Name) value; - } - - // intent of annotation - value = library.getName(entries, IT_KEY); - if (value != null) { - intent = (Name) value; - } - } - - - public String getTitleText() { - return titleText; - } - - public PopupAnnotation getPopupAnnotation() { - return popupAnnotation; - } - - protected static void generateExternalGraphicsState(Form form, float opacity) { - // add the transparency graphic context settings. - if (form != null) { - Resources resources = form.getResources(); - HashMap graphicsProperties = new HashMap(2); - HashMap graphicsState = new HashMap(1); - graphicsProperties.put(GraphicsState.CA_STROKING_KEY, opacity); - graphicsProperties.put(GraphicsState.CA_NON_STROKING_KEY, opacity); - graphicsState.put(EXT_GSTATE_NAME, graphicsProperties); - resources.getEntries().put(Resources.EXTGSTATE_KEY, graphicsState); - form.setResources(resources); - } - } - - /** - * Gets the opacity value for a markup annotation. This value can be optionally used to apply a global - * opacity value when painting or regenerating the contentStream. - * - * @return current opacity value in the range of 0.0 ... 1.0 - */ - public float getOpacity() { - return opacity; - } - - /** - * Get the opacity value in the range of 0 ... 255. - * - * @return current opacity value in the range of 0 ... 255. - */ - public int getOpacityNormalized() { - return Math.round(opacity * 255); - } - - /** - * Set the opacity value of the /CA key in the markup annotation dictionary. - * - * @param opacity opacity in the range of 0.0 ... 1.0. - */ - public void setOpacity(float opacity) { - if (this.opacity >= 0 && this.opacity <= 1.0) { - this.opacity = opacity; - entries.put(CA_KEY, this.opacity); - } - } - - /** - * Set the opacity value of the /CA key in the markup annotation dictionary. - * - * @param opacity opacity in the range of 0 ... 255. - */ - public void setOpacity(int opacity) { - if (this.opacity >= 0 && this.opacity <= 255) { - this.opacity = Math.round(opacity / 2.55f) / 100.0f; - entries.put(CA_KEY, this.opacity); - } - } - - public String getRichText() { - return richText; - } - - public PDate getCreationDate() { - return creationDate; - } - - public MarkupAnnotation getInReplyToAnnotation() { - return inReplyToAnnotation; - } - - public String getSubject() { - return subject; - } - - public Name getReplyToRelation() { - return replyToRelation; - } - - public Name getIntent() { - return intent; - } - - public void setTitleText(String titleText) { - this.titleText = setString(T_KEY, titleText); - } - - public void setPopupAnnotation(PopupAnnotation popupAnnotation) { - this.popupAnnotation = popupAnnotation; - entries.put(POPUP_KEY, popupAnnotation.getPObjectReference()); - } - - public void setRichText(String richText) { - this.richText = setString(RC_KEY, richText); - } - - public void setCreationDate(String creationDate) { - this.creationDate = new PDate(securityManager, creationDate); - setString(CREATION_DATE_KEY, creationDate); - } - - public void setInReplyToAnnotation(MarkupAnnotation inReplyToAnnotation) { - this.inReplyToAnnotation = inReplyToAnnotation; - entries.put(IRT_KEY, inReplyToAnnotation.getPObjectReference()); - } - - public void setSubject(String subject) { - this.subject = setString(SUBTYPE_KEY, subject); - } - - public String toString() { - return getTitleText(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/PopupAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/PopupAnnotation.java deleted file mode 100644 index 11450825c7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/PopupAnnotation.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.PRectangle; -import org.icepdf.core.pobjects.StateManager; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * A pop-up annotation (PDF 1.3) displays text in a pop-up window for entry and - * editing. It shall not appear alone but is associated with a markup annotation, - * its parent annotation, and shall be used for editing the parent’s text. It - * shall have no appearance stream or associated actions of its own and shall be - * identified by the Popup entry in the parent’s annotation dictionary - * (see Table 174). Table 183 shows the annotation dictionary entries specific to - * this type of annotation.A pop-up annotation (PDF 1.3) displays text in a pop-up - * window for entry and editing. It shall not appear alone but is associated - * with a markup annotation, its parent annotation, and shall be used for editing - * the parent’s text. It shall have no appearance stream or associated actions - * of its own and shall be identified by the Popup entry in the parent’s annotation - * dictionary (see Table 174). Table 183 shows the annotation dictionary entries - * specific to this type of annotation. - * - * @since 5.0 - */ -public class PopupAnnotation extends Annotation { - - private static final Logger logger = - Logger.getLogger(PopupAnnotation.class.toString()); - - /** - * (Optional; shall be an indirect reference) The parent annotation with - * which this pop-up annotation shall be associated. - *

- * If this entry is present, the parent annotation’s Contents, M, C, and T - * entries (see Table 168) shall override those of the pop-up annotation - * itself. - */ - public static final Name PARENT_KEY = new Name("Parent"); - /** - * (Optional) A flag specifying whether the pop-up annotation shall - * initially be displayed open. Default value: false (closed). - */ - public static final Name OPEN_KEY = new Name("Open"); - - protected boolean open; - - protected MarkupAnnotation parent; - - public PopupAnnotation(Library l, HashMap h) { - super(l, h); - } - - public void init() throws InterruptedException{ - super.init(); - open = library.getBoolean(entries, OPEN_KEY); - } - - /** - * Gets an instance of a PopupAnnotation that has valid Object Reference. - * - * @param library document library - * @param rect bounding rectangle in user space - * @return new PopupAnnotation Instance. - */ - public static PopupAnnotation getInstance(Library library, - Rectangle rect) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE); - entries.put(Dictionary.SUBTYPE_KEY, Annotation.SUBTYPE_POPUP); - // coordinates - if (rect != null) { - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(rect)); - } else { - entries.put(Annotation.RECTANGLE_KEY, new Rectangle(10, 10, 50, 100)); - } - - // create the new instance - PopupAnnotation popupAnnotation = null; - try { - popupAnnotation = new PopupAnnotation(library, entries); - popupAnnotation.init(); - popupAnnotation.setPObjectReference(stateManager.getNewReferencNumber()); - popupAnnotation.setNew(true); - - // set default flags. - popupAnnotation.setFlag(Annotation.FLAG_READ_ONLY, false); - popupAnnotation.setFlag(Annotation.FLAG_NO_ROTATE, false); - popupAnnotation.setFlag(Annotation.FLAG_NO_ZOOM, false); - popupAnnotation.setFlag(Annotation.FLAG_PRINT, false); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.finer("Popup Annotation initialization was interrupted"); - } - - return popupAnnotation; - } - - @Override - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - - } - - public boolean isOpen() { - return open; - } - - public void setOpen(boolean open) { - this.open = open; - entries.put(OPEN_KEY, open); - } - - public MarkupAnnotation getParent() { - Object tmp = library.getObject(entries, PARENT_KEY); - // should normally be a text annotation type. - if (tmp != null && tmp instanceof MarkupAnnotation) { - parent = (MarkupAnnotation) tmp; - } - return parent; - } - - public void setParent(MarkupAnnotation parent) { - this.parent = parent; - entries.put(PARENT_KEY, parent.getPObjectReference()); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/SignatureWidgetAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/SignatureWidgetAnnotation.java deleted file mode 100644 index 1d7dc5f820..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/SignatureWidgetAnnotation.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.SignatureHandler; -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.util.Library; - -import java.awt.geom.AffineTransform; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * A digital signature (PDF 1.3) may be used to authenticate the identity of a user and the document's contents. It - * stores information about the signer and the state of the document when it was signed. The signature may be purely - * mathematical, such as a public/private-key encrypted document digest, or it may be a biometric form of identification, - * such as a handwritten signature, fingerprint, or retinal scan. The specific form of authentication used shall be - * implemented by a special software module called a signature handler. Signature handlers shall be identified in - * accordance with the rules defined in Annex E. - *
- * NOTE 2
- * The entries in the signature dictionary can be conceptualized as being in different dictionaries; they are in one - * dictionary for historical and cryptographic reasons. The categories are signature properties (R, M, Name, Reason, - * Location, Prop_Build, Prop_AuthTime, and Prop_AuthType); key information (Cert and portions of Contents when the - * signature value is a PKCS#7 object); reference (Reference and ByteRange); and signature value (Contents when the - * signature value is a PKCS#1 object). - */ -public class SignatureWidgetAnnotation extends AbstractWidgetAnnotation { - - private static final Logger logger = - Logger.getLogger(SignatureWidgetAnnotation.class.toString()); - - // signature field dictionary, - private SignatureFieldDictionary fieldDictionary; - - // signatures value holds all the signature info for signing. - private SignatureDictionary signatureDictionary; - - private SignatureValidator signatureValidator; - - public SignatureWidgetAnnotation(Library l, HashMap h) { - super(l, h); - fieldDictionary = new SignatureFieldDictionary(library, entries); - - HashMap valueDict = library.getDictionary(entries, FieldDictionary.V_KEY); - signatureDictionary = new SignatureDictionary(library, valueDict); - - } - - public SignatureValidator getSignatureValidator() { - if (signatureValidator == null) { - SignatureHandler signatureHandler = fieldDictionary.getLibrary().getSignatureHandler(); - signatureValidator = signatureHandler.validateSignature(fieldDictionary); - } - return signatureValidator; - } - - public SignatureWidgetAnnotation(Annotation widgetAnnotation) { - super(widgetAnnotation.getLibrary(), widgetAnnotation.getEntries()); - fieldDictionary = new SignatureFieldDictionary(library, entries); - // copy over the reference number. - setPObjectReference(widgetAnnotation.getPObjectReference()); - } - - public SignatureDictionary getSignatureDictionary() { - return signatureDictionary; - } - - @Override - public void reset() { - - } - - @Override - public void resetAppearanceStream(double dx, double dy, AffineTransform pageSpace) { - - } - - @Override - public SignatureFieldDictionary getFieldDictionary() { - return fieldDictionary; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/SquareAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/SquareAnnotation.java deleted file mode 100644 index 80329b6ad3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/SquareAnnotation.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.pobjects.graphics.commands.*; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * Square annotations (PDF 1.3) shall display, respectively, a - * rectangle or an ellipse on the page. When opened, they shall display a - * pop-up window containing the text of the associated note. The rectangle or - * ellipse shall be inscribed within the annotation rectangle defined by the - * annotation dictionary’s Rect entry (see Table 168). - *

- * Figure 63 shows two annotations, each with a border width of 18 points. Despite - * the names square and circle, the width and height of the annotation rectangle - * need not be equal. Table 177 shows the annotation dictionary entries specific - * to these types of annotations. - * - * @since 5.0 - */ -public class SquareAnnotation extends MarkupAnnotation { - - private static final Logger logger = - Logger.getLogger(SquareAnnotation.class.toString()); - - /** - * (Optional; PDF 1.4) An array of numbers in the range 0.0 to 1.0 specifying - * the interior color that shall be used to fill the annotation’s line endings - * (see Table 176). The number of array elements shall determine the colour - * space in which the colour is defined: - * 0 - No colour; transparent - * 1 - DeviceGray - * 3 - DeviceRGB - * 4 - DeviceCMYK - */ - public static final Name IC_KEY = new Name("IC"); - - private Color fillColor; - private boolean isFillColor; - private Rectangle rectangle; - - public SquareAnnotation(Library l, HashMap h) { - super(l, h); - } - - public void init() throws InterruptedException { - super.init(); - // parse out interior colour, specific to link annotations. - fillColor = Color.WHITE; // we default to black but probably should be null - java.util.List C = (java.util.List) getObject(IC_KEY); - // parse thought rgb colour. - if (C != null && C.size() >= 3) { - float red = ((Number) C.get(0)).floatValue(); - float green = ((Number) C.get(1)).floatValue(); - float blue = ((Number) C.get(2)).floatValue(); - red = Math.max(0.0f, Math.min(1.0f, red)); - green = Math.max(0.0f, Math.min(1.0f, green)); - blue = Math.max(0.0f, Math.min(1.0f, blue)); - fillColor = new Color(red, green, blue); - isFillColor = true; - } - - // try and generate an appearance stream. - resetNullAppearanceStream(); - } - - /** - * Gets an instance of a SquareAnnotation that has valid Object Reference. - * - * @param library document library - * @param rect bounding rectangle in user space - * @return new SquareAnnotation Instance. - */ - public static SquareAnnotation getInstance(Library library, - Rectangle rect) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE); - entries.put(Dictionary.SUBTYPE_KEY, Annotation.SUBTYPE_SQUARE); - // coordinates - if (rect != null) { - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(rect)); - } else { - entries.put(Annotation.RECTANGLE_KEY, new Rectangle(10, 10, 50, 100)); - } - - // create the new instance - SquareAnnotation squareAnnotation = null; - try { - squareAnnotation = new SquareAnnotation(library, entries); - squareAnnotation.init(); - squareAnnotation.setPObjectReference(stateManager.getNewReferencNumber()); - squareAnnotation.setNew(true); - - // set default flags. - squareAnnotation.setFlag(Annotation.FLAG_READ_ONLY, false); - squareAnnotation.setFlag(Annotation.FLAG_NO_ROTATE, false); - squareAnnotation.setFlag(Annotation.FLAG_NO_ZOOM, false); - squareAnnotation.setFlag(Annotation.FLAG_PRINT, true); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Square annotation instance creation was interrupted"); - } - - return squareAnnotation; - } - - /** - * Resets the annotations appearance stream. - */ - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - // grab the current appearance stream as we'll be updating the shapes. - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - // clean identity matrix (nothing fancy) and new empty shapes. - appearanceState.setMatrix(new AffineTransform()); - appearanceState.setShapes(new Shapes()); - // grab references so so we can bass them to the update appearance method. - AffineTransform matrix = appearanceState.getMatrix(); - Shapes shapes = appearanceState.getShapes(); - // we paint everything in annotation space which is relative to the bbox. - Rectangle2D bbox = appearanceState.getBbox(); - bbox.setRect(0, 0, bbox.getWidth(), bbox.getHeight()); - // setup the AP stream. - setModifiedDate(PDate.formatDateTime(new Date())); - // refresh /rect entry to match bbox of the appearance stream. - rectangle = getUserSpaceRectangle().getBounds(); - // check the stroke width - if (borderStyle.getStrokeWidth() == 0) { - borderStyle.setStrokeWidth(1); - } - - BasicStroke stroke = getBorderStyleStroke(); - int strokeWidth = (int) stroke.getLineWidth(); - - // setup the space for the AP content stream. - Rectangle rectangleToDraw = new Rectangle( - strokeWidth, - strokeWidth, - (int) userSpaceRectangle.getWidth() - strokeWidth * 2, - (int) userSpaceRectangle.getHeight() - strokeWidth * 2); - - System.out.println(bbox); - System.out.println(userSpaceRectangle); - - shapes.add(new GraphicsStateCmd(EXT_GSTATE_NAME)); - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity))); - shapes.add(new StrokeDrawCmd(stroke)); - shapes.add(new ShapeDrawCmd(rectangleToDraw)); - if (isFillColor) { - shapes.add(new ColorDrawCmd(fillColor)); - shapes.add(new FillDrawCmd()); - } - if (borderStyle.getStrokeWidth() > 0) { - shapes.add(new ColorDrawCmd(color)); - shapes.add(new DrawDrawCmd()); - } - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))); - - // update the appearance stream - // create/update the appearance stream of the xObject. - Form form = updateAppearanceStream(shapes, bbox, matrix, - PostScriptEncoder.generatePostScript(shapes.getShapes())); - generateExternalGraphicsState(form, opacity); - } - - public Color getFillColor() { - return fillColor; - } - - public void setFillColor(Color fillColor) { - this.fillColor = fillColor; - float[] compArray = new float[3]; - this.fillColor.getColorComponents(compArray); - java.util.List colorValues = new ArrayList(compArray.length); - for (float comp : compArray) { - colorValues.add(comp); - } - entries.put(IC_KEY, colorValues); - } - - public Rectangle getRectangle() { - return rectangle; - } - - public void setRectangle(Rectangle rectangle) { - this.rectangle = rectangle; - } - - public boolean isFillColor() { - return isFillColor; - } - - public void setFillColor(boolean fillColor) { - isFillColor = fillColor; - if (!isFillColor) { - entries.remove(IC_KEY); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/TextAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/TextAnnotation.java deleted file mode 100644 index 4301869a23..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/TextAnnotation.java +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.content.ContentParser; -import org.icepdf.core.util.content.ContentParserFactory; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.text.MessageFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * A text annotation represents a “sticky note†attached to a point in the PDF - * document. When closed, the annotation shall appear as an icon; when open, it - * shall display a pop-up window containing the text of the note in a font and - * size chosen by the conforming reader. Text annotations shall not scale and - * rotate with the page; they shall behave as if the NoZoom and NoRotate annotation - * flags (see Table 165) were always set. Table 172shows the annotation dictionary - * entries specific to this type of annotation. - * - * @since 5.0 - */ -public class TextAnnotation extends MarkupAnnotation { - - private static final Logger logger = - Logger.getLogger(TextAnnotation.class.toString()); - - /** - * (Optional) A flag specifying whether the annotation shall initially be - * displayed open. Default value: false (closed). - */ - public static final Name OPEN_KEY = new Name("Open"); - /** - * Optional) The name of an icon that shall be used in displaying the annotation. - * Conforming readers shall provide predefined icon appearances for at least - * the following standard names: - *

- * Comment, Key, Note, Help, NewParagraph, Paragraph, Insert - *

- * Additional names may be supported as well. Default value: Note. - *

- * The annotation dictionary’s AP entry, if present, shall take precedence - * over the Name entry; see Table 168 and 12.5.5, “Appearance Streams.†- */ - public static final Name NAME_KEY = new Name("Name"); - /** - * (Optional; PDF 1.5) The state to which the original annotation shall be - * set; see 12.5.6.3, “Annotation States.†- *

- * Default: “Unmarked†if StateModel is “Markedâ€; “None†if StateModel is “Reviewâ€. - */ - public static final Name STATE_KEY = new Name("State"); - /** - * (Required if State is present, otherwise optional; PDF 1.5) The state model - * corresponding to State; see 12.5.6.3, “Annotation States.†- */ - public static final Name STATE_MODEL_KEY = new Name("StateModel"); - /** - * Named text icon times. - */ - - public static final Name COMMENT_ICON = new Name("Comment"); - public static final Name CHECK_ICON = new Name("Check"); - public static final Name CHECK_MARK_ICON = new Name("CheckMark"); - public static final Name CIRCLE_ICON = new Name("Circle"); - public static final Name CROSS_ICON = new Name("Cross"); - public static final Name CROSS_HAIRS_ICON = new Name("CrossHairs"); - public static final Name HELP_ICON = new Name("Help"); - public static final Name INSERT_ICON = new Name("Insert"); - public static final Name KEY_ICON = new Name("Key"); - public static final Name NEW_PARAGRAPH_ICON = new Name("NewParagraph"); - public static final Name PARAGRAPH_ICON = new Name("Paragraph"); - public static final Name RIGHT_ARROW_ICON = new Name("RightArrow"); - public static final Name RIGHT_POINTER_ICON = new Name("RightPointer"); - public static final Name STAR_ICON = new Name("Star"); - public static final Name UP_ARROW_ICON = new Name("UpArrow"); - public static final Name UP_LEFT_ARROW_ICON = new Name("UpLeftArrow"); - /** - * State Models - */ - public static final String STATE_MODEL_MARKED = "Marked"; - public static final String STATE_MODEL_REVIEW = "Review"; - /** - * State names. - */ - public static final String STATE_MARKED = "Marked"; - public static final String STATE_UNMARKED = "Unmarked"; - public static final String STATE_ACCEPTED = "Accepted"; - public static final String STATE_REJECTED = "Rejected"; - public static final String STATE_CANCELLED = "Cancelled"; - public static final String STATE_COMPLETED = "Completed"; - public static final String STATE_REVIEW_NONE = "None"; - - protected boolean open; - protected Name iconName = COMMENT_ICON; - protected String state; - protected String stateModel; - public TextAnnotation(Library l, HashMap h) { - super(l, h); - } - - public void init() throws InterruptedException { - super.init(); - // open state - open = library.getBoolean(entries, OPEN_KEY); - - // state - Object value = library.getObject(entries, STATE_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - state = text.getDecryptedLiteralString(securityManager); - } else if (value instanceof String) { - state = (String) value; - } - - // icon name - value = library.getName(entries, NAME_KEY); - if (value != null) { - iconName = (Name) value; - } - - // state model - value = library.getObject(entries, STATE_MODEL_KEY); - if (value != null && value instanceof StringObject) { - StringObject text = (StringObject) value; - stateModel = text.getDecryptedLiteralString(securityManager); - } else if (value instanceof String) { - stateModel = (String) value; - } - - // try and generate an appearance stream. - resetNullAppearanceStream(); - } - - /** - * Gets an instance of a TextAnnotation that has valid Object Reference. - * - * @param library document library - * @param rect bounding rectangle in user space - * @return new TextAnnotation Instance. - */ - public static TextAnnotation getInstance(Library library, - Rectangle rect) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE); - entries.put(Dictionary.SUBTYPE_KEY, Annotation.SUBTYPE_TEXT); - // rotation and scale locking - entries.put(Annotation.FLAG_KEY, 28); - // coordinates - if (rect != null) { - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(rect)); - } else { - entries.put(Annotation.RECTANGLE_KEY, new Rectangle2D.Float(10, 10, 50, 100)); - } - - // create the new instance - TextAnnotation textAnnotation = null; - try { - textAnnotation = new TextAnnotation(library, entries); - textAnnotation.init(); - textAnnotation.setPObjectReference(stateManager.getNewReferencNumber()); - textAnnotation.setNew(true); - - // set default flags. - textAnnotation.setFlag(Annotation.FLAG_READ_ONLY, false); - textAnnotation.setFlag(Annotation.FLAG_NO_ROTATE, true); - textAnnotation.setFlag(Annotation.FLAG_NO_ZOOM, true); - textAnnotation.setFlag(Annotation.FLAG_PRINT, true); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Text annotation instance creation was interrupted"); - } - - return textAnnotation; - } - - /** - * Resets the annotations appearance stream. - */ - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - // setup the context - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - - appearanceState.setMatrix(new AffineTransform()); - appearanceState.setShapes(new Shapes()); - - Rectangle2D bbox = appearanceState.getBbox(); - bbox.setRect(0, 0, bbox.getWidth(), bbox.getHeight()); - // setup the AP stream. - setModifiedDate(PDate.formatDateTime(new Date())); - - AffineTransform matrix = appearanceState.getMatrix(); - Shapes shapes; - - String iconContentString; - // get the correct icon content - if (iconName.equals(COMMENT_ICON)) { - iconContentString = COMMENT_CONTENT_STREAM; - } else if (iconName.equals(CHECK_ICON)) { - iconContentString = CHECK_CONTENT_STREAM; - } else if (iconName.equals(CHECK_MARK_ICON)) { - iconContentString = CHECK_MARK_CONTENT_STREAM; - } else if (iconName.equals(CIRCLE_ICON)) { - iconContentString = CIRCLE_CONTENT_STREAM; - } else if (iconName.equals(CROSS_ICON)) { - iconContentString = CROSS_CONTENT_STREAM; - } else if (iconName.equals(CROSS_HAIRS_ICON)) { - iconContentString = CROSS_HAIRS_CONTENT_STREAM; - } else if (iconName.equals(HELP_ICON)) { - iconContentString = HELP_CONTENT_STREAM; - } else if (iconName.equals(INSERT_ICON)) { - iconContentString = INSERT_CONTENT_STREAM; - } else if (iconName.equals(KEY_ICON)) { - iconContentString = KEY_CONTENT_STREAM; - } else if (iconName.equals(NEW_PARAGRAPH_ICON)) { - iconContentString = NEW_PARAGRAPH_CONTENT_STREAM; - } else if (iconName.equals(PARAGRAPH_ICON)) { - iconContentString = PARAGRAPH_CONTENT_STREAM; - } else if (iconName.equals(RIGHT_ARROW_ICON)) { - iconContentString = RIGHT_ARROW_CONTENT_STREAM; - } else if (iconName.equals(RIGHT_POINTER_ICON)) { - iconContentString = RIGHT_POINTER_CONTENT_STREAM; - } else if (iconName.equals(STAR_ICON)) { - iconContentString = STAR_CONTENT_STREAM; - } else if (iconName.equals(UP_ARROW_ICON)) { - iconContentString = UP_ARROW_CONTENT_STREAM; - } else if (iconName.equals(UP_LEFT_ARROW_ICON)) { - iconContentString = UP_LEFT_ARROW_CONTENT_STREAM; - } else { - iconContentString = COMMENT_CONTENT_STREAM; - } - // need to make sure we have a colour so we can generate the content stream. - if (color == null) { - color = Color.YELLOW; - } - float[] compArray = new float[3]; - color.getColorComponents(compArray); - StringBuilder colorString = new StringBuilder() - .append(compArray[0]).append(" ") - .append(compArray[1]).append(" ") - .append(compArray[2]); - // apply the colour - Object[] colorArgument = new Object[]{EXT_GSTATE_NAME, colorString}; - MessageFormat formatter = new MessageFormat(iconContentString); - iconContentString = formatter.format(colorArgument); - - Form form = updateAppearanceStream(null, bbox, matrix, null); - generateExternalGraphicsState(form, opacity); - // parse the shapes and assign to this instance - try { - Resources resources = form.getResources(); - ContentParser cp = ContentParserFactory.getInstance().getContentParser(library, resources); - shapes = cp.parse(new byte[][]{iconContentString.getBytes()}, null).getShapes(); - } catch (Exception e) { - shapes = new Shapes(); - logger.log(Level.FINEST, "Error building named icon.", e); - } - - // update the appearance stream - // create/update the appearance stream of the xObject. - form = updateAppearanceStream(shapes, bbox, matrix, iconContentString.getBytes()); -// generateExternalGraphicsState(form, opacity); - if (form != null) { - appearanceState.setShapes(shapes); - } - } - - public boolean isOpen() { - return open; - } - - public Name getIconName() { - return iconName; - } - - public String getState() { - return state; - } - - public String getStateModel() { - return stateModel; - } - - public void setOpen(boolean open) { - this.open = open; - entries.put(OPEN_KEY, open); - } - - public void setIconName(Name iconName) { - this.iconName = iconName; - entries.put(NAME_KEY, iconName); - } - - public void setState(String state) { - this.state = state; - setString(STATE_KEY, state); - } - - public void setStateModel(String stateModel) { - this.stateModel = stateModel; - setString(STATE_KEY, stateModel); - } - - // comment name streams. - - public static final String COMMENT_CONTENT_STREAM = - "q 1 1 1 rg 0 i 1 w 4 M 1 j 0 J []0 d 1 0 0 1 9 5.0908 cm /{0} gs 7.74 12.616 m -7.74 12.616 l -8.274 12.616 -8.707 12.184 -8.707 11.649 c -8.707 -3.831 l -8.707 -4.365 -8.274 -4.798 -7.74 -4.798 c 7.74 -4.798 l 8.274 -4.798 8.707 -4.365 8.707 -3.831 c 8.707 11.649 l 8.707 12.184 8.274 12.616 7.74 12.616 c h f Q 0 G {1} rg 0 i 0.60 w 4 M 1 j 0 J []0 d {1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 9 5.0908 cm 0 0 m -0.142 0 -0.28 0.008 -0.418 0.015 c -2.199 -1.969 -5.555 -2.242 -4.642 -1.42 c -4.024 -0.862 -3.916 0.111 -3.954 0.916 c -5.658 1.795 -6.772 3.222 -6.772 4.839 c -6.772 7.509 -3.74 9.674 0 9.674 c 3.74 9.674 6.772 7.509 6.772 4.839 c 6.772 2.167 3.74 0 0 0 c 7.74 12.616 m -7.74 12.616 l -8.274 12.616 -8.707 12.184 -8.707 11.649 c -8.707 -3.831 l -8.707 -4.365 -8.274 -4.798 -7.74 -4.798 c 7.74 -4.798 l 8.274 -4.798 8.707 -4.365 8.707 -3.831 c 8.707 11.649 l 8.707 12.184 8.274 12.616 7.74 12.616 c b"; - public static final String CHECK_CONTENT_STREAM = - "{1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d 1 0 0 1 7.1836 1.2061 cm /{0} gs 0 0 m 6.691 11.152 11.31 14.196 v 10.773 15.201 9.626 16.892 8.155 17.587 c 2.293 10.706 -0.255 4.205 y -4.525 9.177 l -6.883 5.608 l h b"; - public static final String CHECK_MARK_CONTENT_STREAM = - "q 0.396 0.396 0.396 rg 1 0 0 1 13.5151 16.5 cm /{0} gs 0 0 m -6.7 -10.23 l -8.81 -7 l -13.22 -7 l -6.29 -15 l 4.19 0 l h f Q "; - public static final String CIRCLE_CONTENT_STREAM = - "q 1 1 1 rg 0 i 1 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 9.999 3.6387 cm 0 0 m -3.513 0 -6.36 2.85 -6.36 6.363 c -6.36 9.875 -3.513 12.724 0 12.724 c 3.514 12.724 6.363 9.875 6.363 6.363 c 6.363 2.85 3.514 0 0 0 c h f Q {1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 9.999 3.6387 cm 0 0 m -3.513 0 -6.36 2.85 -6.36 6.363 c -6.36 9.875 -3.513 12.724 0 12.724 c 3.514 12.724 6.363 9.875 6.363 6.363 c 6.363 2.85 3.514 0 0 0 c 0 16.119 m -5.388 16.119 -9.756 11.751 -9.756 6.363 c -9.756 0.973 -5.388 -3.395 0 -3.395 c 5.391 -3.395 9.757 0.973 9.757 6.363 c 9.757 11.751 5.391 16.119 0 16.119 c b"; - public static final String CROSS_CONTENT_STREAM = - "{1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 18.6924 3.1357 cm 0 0 m -6.363 6.364 l 0 12.728 l -2.828 15.556 l -9.192 9.192 l -15.556 15.556 l -18.384 12.728 l -12.02 6.364 l -18.384 0 l -15.556 -2.828 l -9.192 3.535 l -2.828 -2.828 l h b"; - public static final String CROSS_HAIRS_CONTENT_STREAM = - "q 1 1 1 rg 0 i 1 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 9.9771 1.9443 cm 0 0 m -4.448 0 -8.053 3.604 -8.053 8.053 c -8.053 12.5 -4.448 16.106 0 16.106 c 4.447 16.106 8.054 12.5 8.054 8.053 c 8.054 3.604 4.447 0 0 0 c h f Q {1} rg 0 G 0 i 0.61 w 4 M 0 j 0 J []0 d /{0} gs q 1 0 0 1 9.9771 1.9443 cm 0 0 m -4.448 0 -8.053 3.604 -8.053 8.053 c -8.053 12.5 -4.448 16.106 0 16.106 c 4.447 16.106 8.054 12.5 8.054 8.053 c 8.054 3.604 4.447 0 0 0 c 0 17.716 m -5.336 17.716 -9.663 13.39 -9.663 8.053 c -9.663 2.716 -5.336 -1.61 0 -1.61 c 5.337 -1.61 9.664 2.716 9.664 8.053 c 9.664 13.39 5.337 17.716 0 17.716 c b Q q 1 0 0 1 10.7861 14.8325 cm 0 0 m -1.611 0 l -1.611 -4.027 l -5.638 -4.027 l -5.638 -5.638 l -1.611 -5.638 l -1.611 -9.665 l 0 -9.665 l 0 -5.638 l 4.026 -5.638 l 4.026 -4.027 l 0 -4.027 l h b Q"; - public static final String HELP_CONTENT_STREAM = - "q 1 1 1 rg 0 i 1 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 12.1465 10.5137 cm -2.146 9.403 m -7.589 9.403 -12.001 4.99 -12.001 -0.453 c -12.001 -5.895 -7.589 -10.309 -2.146 -10.309 c 3.296 -10.309 7.709 -5.895 7.709 -0.453 c 7.709 4.99 3.296 9.403 -2.146 9.403 c h f Q {1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 12.1465 10.5137 cm 0 0 m -0.682 -0.756 -0.958 -1.472 -0.938 -2.302 c -0.938 -2.632 l -3.385 -2.632 l -3.403 -2.154 l -3.459 -1.216 -3.147 -0.259 -2.316 0.716 c -1.729 1.433 -1.251 2.022 -1.251 2.647 c -1.251 3.291 -1.674 3.715 -2.594 3.751 c -3.202 3.751 -3.937 3.531 -4.417 3.2 c -5.041 5.205 l -4.361 5.591 -3.274 5.959 -1.968 5.959 c 0.46 5.959 1.563 4.616 1.563 3.089 c 1.563 1.691 0.699 0.771 0 0 c -2.227 -6.863 m -2.245 -6.863 l -3.202 -6.863 -3.864 -6.146 -3.864 -5.189 c -3.864 -4.196 -3.182 -3.516 -2.227 -3.516 c -1.233 -3.516 -0.589 -4.196 -0.57 -5.189 c -0.57 -6.146 -1.233 -6.863 -2.227 -6.863 c -2.146 9.403 m -7.589 9.403 -12.001 4.99 -12.001 -0.453 c -12.001 -5.895 -7.589 -10.309 -2.146 -10.309 c 3.296 -10.309 7.709 -5.895 7.709 -0.453 c 7.709 4.99 3.296 9.403 -2.146 9.403 c b"; - public static final String INSERT_CONTENT_STREAM = - "0 G {1} rg 0 i 0.59 w 4 M 0 j 0 J []0 d /{0} gs 1 0 0 1 8.5386 19.8545 cm 0 0 m -8.39 -19.719 l 8.388 -19.719 l h B"; - public static final String KEY_CONTENT_STREAM = - "q 1 1 1 rg 0 i 1 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 6.5 12.6729 cm 0.001 5.138 m -2.543 5.138 -4.604 3.077 -4.604 0.534 c -4.604 -1.368 -3.449 -3.001 -1.802 -3.702 c -1.802 -4.712 l -0.795 -5.719 l -1.896 -6.82 l -0.677 -8.039 l -1.595 -8.958 l -0.602 -9.949 l -1.479 -10.829 l -0.085 -12.483 l 1.728 -10.931 l 1.728 -3.732 l 1.737 -3.728 1.75 -3.724 1.76 -3.721 c 3.429 -3.03 4.604 -1.385 4.604 0.534 c 4.604 3.077 2.542 5.138 0.001 5.138 c f Q {1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 6.5 12.6729 cm 0 0 m -1.076 0 -1.95 0.874 -1.95 1.95 c -1.95 3.028 -1.076 3.306 0 3.306 c 1.077 3.306 1.95 3.028 1.95 1.95 c 1.95 0.874 1.077 0 0 0 c 0.001 5.138 m -2.543 5.138 -4.604 3.077 -4.604 0.534 c -4.604 -1.368 -3.449 -3.001 -1.802 -3.702 c -1.802 -4.712 l -0.795 -5.719 l -1.896 -6.82 l -0.677 -8.039 l -1.595 -8.958 l -0.602 -9.949 l -1.479 -10.829 l -0.085 -12.483 l 1.728 -10.931 l 1.728 -3.732 l 1.737 -3.728 1.75 -3.724 1.76 -3.721 c 3.429 -3.03 4.604 -1.385 4.604 0.534 c 4.604 3.077 2.542 5.138 0.001 5.138 c b"; - public static final String NEW_PARAGRAPH_CONTENT_STREAM = - "{1} rg 0 G 0 i 0.58 w 4 M 0 j 0 J []0 d /{0} gs {1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs q 1 0 0 1 6.4995 20 cm 0 0 m -6.205 -12.713 l 6.205 -12.713 l h b Q q 1 0 0 1 1.1909 6.2949 cm 0 0 m 1.278 0 l 1.353 0 1.362 -0.02 1.391 -0.066 c 2.128 -1.363 3.78 -4.275 3.966 -4.713 c 3.985 -4.713 l 3.976 -4.453 3.957 -3.91 3.957 -3.137 c 3.957 -0.076 l 3.957 -0.02 3.976 0 4.041 0 c 4.956 0 l 5.021 0 5.04 -0.029 5.04 -0.084 c 5.04 -6.049 l 5.04 -6.113 5.021 -6.133 4.947 -6.133 c 3.695 -6.133 l 3.621 -6.133 3.611 -6.113 3.574 -6.066 c 3.052 -4.955 1.353 -2.063 0.971 -1.186 c 0.961 -1.186 l 0.999 -1.68 0.999 -2.146 1.008 -3.025 c 1.008 -6.049 l 1.008 -6.104 0.989 -6.133 0.933 -6.133 c 0.009 -6.133 l -0.046 -6.133 -0.075 -6.123 -0.075 -6.049 c -0.075 -0.066 l -0.075 -0.02 -0.056 0 0 0 c f Q q 1 0 0 1 9.1367 3.0273 cm 0 0 m 0.075 0 0.215 -0.008 0.645 -0.008 c 1.4 -0.008 2.119 0.281 2.119 1.213 c 2.119 1.969 1.633 2.381 0.737 2.381 c 0.354 2.381 0.075 2.371 0 2.361 c h -1.146 3.201 m -1.146 3.238 -1.129 3.268 -1.082 3.268 c -0.709 3.275 0.02 3.285 0.729 3.285 c 2.613 3.285 3.248 2.314 3.258 1.232 c 3.258 -0.27 2.007 -0.914 0.607 -0.914 c 0.327 -0.914 0.057 -0.914 0 -0.904 c 0 -2.789 l 0 -2.836 -0.019 -2.865 -0.074 -2.865 c -1.082 -2.865 l -1.119 -2.865 -1.146 -2.846 -1.146 -2.799 c h f Q"; - public static final String PARAGRAPH_CONTENT_STREAM = - "q 1 1 1 rg 0 i 1 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 19.6973 10.0005 cm 0 0 m 0 -5.336 -4.326 -9.662 -9.663 -9.662 c -14.998 -9.662 -19.324 -5.336 -19.324 0 c -19.324 5.335 -14.998 9.662 -9.663 9.662 c -4.326 9.662 0 5.335 0 0 c h f Q {1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs q 1 0 0 1 19.6973 10.0005 cm 0 0 m 0 -5.336 -4.326 -9.662 -9.663 -9.662 c -14.998 -9.662 -19.324 -5.336 -19.324 0 c -19.324 5.335 -14.998 9.662 -9.663 9.662 c -4.326 9.662 0 5.335 0 0 c h S Q q 1 0 0 1 11.6787 2.6582 cm 0 0 m -1.141 0 l -1.227 0 -1.244 0.052 -1.227 0.139 c -0.656 1.157 -0.52 2.505 -0.52 3.317 c -0.52 3.594 l -2.833 3.783 -5.441 4.838 -5.441 8.309 c -5.441 10.778 -3.714 12.626 -0.57 13.024 c -0.535 13.508 -0.381 14.129 -0.242 14.389 c -0.207 14.44 -0.174 14.475 -0.104 14.475 c 1.088 14.475 l 1.156 14.475 1.191 14.458 1.175 14.372 c 1.105 14.095 0.881 13.127 0.881 12.402 c 0.881 9.431 0.932 7.324 0.95 4.06 c 0.95 2.298 0.708 0.813 0.189 0.07 c 0.155 0.034 0.103 0 0 0 c b Q"; - public static final String RIGHT_ARROW_CONTENT_STREAM = - "q 1 1 1 rg 0 i 1 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 3.7856 11.1963 cm 6.214 -10.655 m 11.438 -10.655 15.673 -6.42 15.673 -1.196 c 15.673 4.027 11.438 8.262 6.214 8.262 c 0.991 8.262 -3.244 4.027 -3.244 -1.196 c -3.244 -6.42 0.991 -10.655 6.214 -10.655 c h f Q {1} rg 0 G 0 i 0.59 w 4 M 0 j 0 J []0 d /{0} gs 1 0 0 1 3.7856 11.1963 cm 0 0 m 8.554 0 l 6.045 2.51 l 7.236 3.702 l 12.135 -1.197 l 7.236 -6.096 l 6.088 -4.949 l 8.644 -2.394 l 0 -2.394 l h 6.214 -10.655 m 11.438 -10.655 15.673 -6.42 15.673 -1.196 c 15.673 4.027 11.438 8.262 6.214 8.262 c 0.991 8.262 -3.244 4.027 -3.244 -1.196 c -3.244 -6.42 0.991 -10.655 6.214 -10.655 c b"; - public static final String RIGHT_POINTER_CONTENT_STREAM = - "{1} rg 0 G 0.59 w 4 M 0 j 0 J []0 d /{0} gs 1 0 0 1 1.1871 17.0000 cm 0 0 m 4.703 -8.703 l 0 -17 l 18.813 -8.703 l b"; - public static final String STAR_CONTENT_STREAM = - "{1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 9.999 18.8838 cm 0 0 m 3.051 -6.178 l 9.867 -7.168 l 4.934 -11.978 l 6.099 -18.768 l 0 -15.562 l -6.097 -18.768 l -4.933 -11.978 l -9.866 -7.168 l -3.048 -6.178 l b"; - public static final String UP_ARROW_CONTENT_STREAM = - "{1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 1.1007 6.7185 cm 0 0 m 4.009 0 l 4.009 -6.719 l 11.086 -6.719 l 11.086 0 l 14.963 0 l 7.499 13.081 l b"; - public static final String UP_LEFT_ARROW_CONTENT_STREAM = - "{1} rg 0 G 0 i 0.59 w 4 M 1 j 0 J []0 d /{0} gs 1 0 0 1 2.8335 1.7627 cm 0 0 m -2.74 15.16 l 12.345 12.389 l 9.458 9.493 l 14.027 4.91 l 7.532 -1.607 l 2.964 2.975 l b"; - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/TextMarkupAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/TextMarkupAnnotation.java deleted file mode 100644 index fa5846cae6..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/TextMarkupAnnotation.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.graphics.Shapes; -import org.icepdf.core.pobjects.graphics.commands.*; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Text markup annotations shall appear as highlights, underlines, strikeouts - * (all PDF 1.3), or jagged (“squigglyâ€) underlines (PDF 1.4) in the text of a - * document. When opened, they shall display a pop-up window containing the text - * of the associated note. Table 179 shows the annotation dictionary entries - * specific to these types of annotations. - * - * @since 5.0 - */ -public class TextMarkupAnnotation extends MarkupAnnotation { - - private static final Logger logger = - Logger.getLogger(TextMarkupAnnotation.class.toString()); - - public static final Name SUBTYPE_HIGHLIGHT = new Name("Highlight"); - public static final Name SUBTYPE_UNDERLINE = new Name("Underline"); - public static final Name SUBTYPE_SQUIGGLY = new Name("Squiggly"); - public static final Name SUBTYPE_STRIKE_OUT = new Name("StrikeOut"); - - private static Color highlightColor; - private static Color strikeOutColor; - private static Color underlineColor; - - static { - - // sets annotation selected highlight colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.textmarkup.highlight.color", "#ffff00"); - int colorValue = ColorUtil.convertColor(color); - highlightColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("ffff00", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading Text Markup Annotation highlight colour"); - } - } - // sets annotation selected highlight colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.textmarkup.strikeOut.color", "#ff0000"); - int colorValue = ColorUtil.convertColor(color); - strikeOutColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("ff0000", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading Text Markup Annotation strike out colour"); - } - } - // sets annotation selected highlight colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.textmarkup.underline.color", "#00ff00"); - int colorValue = ColorUtil.convertColor(color); - underlineColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("00ff00", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading Text Markup Annotation underline colour"); - } - } - } - - /** - * (Required) An array of 8 × n numbers specifying the coordinates of - * n quadrilaterals in default user space. Each quadrilateral shall encompasses - * a word or group of contiguous words in the text underlying the annotation. - * The coordinates for each quadrilateral shall be given in the order - * x1 y1 x2 y2 x3 y3 x4 y4 - * specifying the quadrilateral’s four vertices in counterclockwise order - * (see Figure 64). The text shall be oriented with respect to the edge - * connecting points (x1, y1) and (x2, y2). - *

- * The annotation dictionary’s AP entry, if present, shall take precedence - * over QuadPoints; see Table 168 and 12.5.5, “Appearance Streams.†- */ - public static final Name KEY_QUAD_POINTS = new Name("QuadPoints"); - - /** - * Highlight transparency default - */ - public static final int HIGHLIGHT_ALPHA = 80; - - - /** - * Converted Quad points. - */ - private Shape[] quadrilaterals; - - private Color textMarkupColor; - - private GeneralPath markupPath; - private ArrayList markupBounds; - - /** - * Creates a new instance of an TextMarkupAnnotation. - * - * @param l document library. - * @param h dictionary entries. - */ - public TextMarkupAnnotation(Library l, HashMap h) { - super(l, h); - } - - @SuppressWarnings("unchecked") - public void init() throws InterruptedException { - super.init(); - // collect the quad points. - List quadPoints = library.getArray(entries, KEY_QUAD_POINTS); - if (quadPoints != null) { - int size = quadPoints.size() / 8; - quadrilaterals = new Shape[size]; - GeneralPath shape; - for (int i = 0, count = 0; i < size; i++, count += 8) { - shape = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 4); - shape.moveTo(quadPoints.get(count + 6).floatValue(), quadPoints.get(count + 7).floatValue()); - shape.lineTo(quadPoints.get(count + 4).floatValue(), quadPoints.get(count + 5).floatValue()); - shape.lineTo(quadPoints.get(count).floatValue(), quadPoints.get(count + 1).floatValue()); - shape.lineTo(quadPoints.get(count + 2).floatValue(), quadPoints.get(count + 3).floatValue()); - shape.closePath(); - quadrilaterals[i] = shape; - } - } - if (SUBTYPE_HIGHLIGHT.equals(subtype)) { - textMarkupColor = highlightColor; - } else if (SUBTYPE_STRIKE_OUT.equals(subtype)) { - textMarkupColor = strikeOutColor; - } else if (SUBTYPE_UNDERLINE.equals(subtype)) { - textMarkupColor = underlineColor; - } else if (SUBTYPE_SQUIGGLY.equals(subtype)) { - // not implemented - } - - // for editing purposes grab anny shapes from the AP Stream and - // store them as markupBounds and markupPath. This works ok but - // perhaps a better way would be to reapply the bound box - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - Shapes shapes = appearanceState.getShapes(); - if (shapes != null) { - markupBounds = new ArrayList(); - markupPath = new GeneralPath(); - - ShapeDrawCmd shapeDrawCmd; - for (DrawCmd cmd : shapes.getShapes()) { - if (cmd instanceof ShapeDrawCmd) { - shapeDrawCmd = (ShapeDrawCmd) cmd; - markupBounds.add(shapeDrawCmd.getShape()); - markupPath.append(shapeDrawCmd.getShape(), false); - } - } - - } - // try and generate an appearance stream. - resetNullAppearanceStream(); - } - - /** - * Gets an instance of a TextMarkupAnnotation that has valid Object Reference. - * - * @param library document library - * @param rect bounding rectangle in user space - * @return new TextMarkupAnnotation Instance. - */ - public static TextMarkupAnnotation getInstance(Library library, - Rectangle rect, - final Name subType) { - // state manager - StateManager stateManager = library.getStateManager(); - - // create a new entries to hold the annotation properties - HashMap entries = new HashMap(); - // set default link annotation values. - entries.put(Dictionary.TYPE_KEY, Annotation.TYPE_VALUE); - entries.put(Dictionary.SUBTYPE_KEY, subType); - entries.put(Annotation.FLAG_KEY, 4); - // coordinates - if (rect != null) { - entries.put(Annotation.RECTANGLE_KEY, - PRectangle.getPRectangleVector(rect)); - } else { - entries.put(Annotation.RECTANGLE_KEY, new Rectangle(10, 10, 50, 100)); - } - - TextMarkupAnnotation textMarkupAnnotation = - null; - try { - textMarkupAnnotation = new TextMarkupAnnotation(library, entries); - textMarkupAnnotation.init(); - entries.put(NM_KEY, - new LiteralStringObject(String.valueOf(textMarkupAnnotation.hashCode()))); - textMarkupAnnotation.setPObjectReference(stateManager.getNewReferencNumber()); - textMarkupAnnotation.setNew(true); - textMarkupAnnotation.setModifiedDate(PDate.formatDateTime(new Date())); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Text markup annotation instance creation was interrupted"); - } - return textMarkupAnnotation; - } - - - public static boolean isTextMarkupAnnotation(Name subType) { - return SUBTYPE_HIGHLIGHT.equals(subType) || - SUBTYPE_UNDERLINE.equals(subType) || - SUBTYPE_SQUIGGLY.equals(subType) || - SUBTYPE_STRIKE_OUT.equals(subType); - } - - /** - * Resets the annotations appearance stream. - */ - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - - // check if we have anything to reset. - if (markupBounds == null) { - return; - } - - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - appearanceState.setShapes(new Shapes()); - - Rectangle2D bbox = appearanceState.getBbox(); - AffineTransform matrix = appearanceState.getMatrix(); - Shapes shapes = appearanceState.getShapes(); - - // setup the stroke from the border settings. - BasicStroke stroke = new BasicStroke(1f); - shapes.add(new StrokeDrawCmd(stroke)); - shapes.add(new GraphicsStateCmd(EXT_GSTATE_NAME)); - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity))); - if (SUBTYPE_HIGHLIGHT.equals(subtype)) { - shapes.add(new ShapeDrawCmd(markupPath)); - shapes.add(new ColorDrawCmd(textMarkupColor)); - shapes.add(new FillDrawCmd()); - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))); - } else if (SUBTYPE_STRIKE_OUT.equals(subtype)) { - for (Shape shape : markupBounds) { - // calculate the line that will stroke the bounds - GeneralPath strikeOutPath = new GeneralPath(); - Rectangle2D bound = shape.getBounds2D(); - float y = (float) (bound.getMinY() + (bound.getHeight() / 2)); - strikeOutPath.moveTo((float) bound.getMinX(), y); - strikeOutPath.lineTo((float) bound.getMaxX(), y); - strikeOutPath.closePath(); - shapes.add(new ShapeDrawCmd(strikeOutPath)); - shapes.add(new ColorDrawCmd(textMarkupColor)); - shapes.add(new DrawDrawCmd()); - } - } else if (SUBTYPE_UNDERLINE.equals(subtype)) { - for (Shape shape : markupBounds) { - // calculate the line that will stroke the bounds - GeneralPath underlinePath = new GeneralPath(); - Rectangle2D bound = shape.getBounds2D(); - underlinePath.moveTo((float) bound.getMinX(), (float) bound.getMinY()); - underlinePath.lineTo((float) bound.getMaxX(), (float) bound.getMinY()); - underlinePath.closePath(); - shapes.add(new ShapeDrawCmd(underlinePath)); - shapes.add(new ColorDrawCmd(textMarkupColor)); - shapes.add(new DrawDrawCmd()); - } - } else if (SUBTYPE_SQUIGGLY.equals(subtype)) { - // not implemented, need to create a custom stroke or - // build out a custom line move. - } - shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f))); - - // create the quad points - List quadPoints = new ArrayList(); - if (markupBounds != null) { - Rectangle2D bounds; - // build out the square in quadrant 1. - for (Shape shape : markupBounds) { - bounds = shape.getBounds2D(); - - quadPoints.add((float) bounds.getX()); - quadPoints.add((float) (bounds.getY() + bounds.getHeight())); - - quadPoints.add((float) (bounds.getX() + bounds.getWidth())); - quadPoints.add((float) (bounds.getY() + bounds.getHeight())); - - quadPoints.add((float) (bounds.getX())); - quadPoints.add((float) (bounds.getY())); - - quadPoints.add((float) (bounds.getX() + bounds.getWidth())); - quadPoints.add((float) (bounds.getY())); - } - } - entries.put(KEY_QUAD_POINTS, quadPoints); - setModifiedDate(PDate.formatDateTime(new Date())); - - // update the appearance stream - // create/update the appearance stream of the xObject. - Form form = updateAppearanceStream(shapes, bbox, matrix, - PostScriptEncoder.generatePostScript(shapes.getShapes())); - generateExternalGraphicsState(form, opacity); - } - - @Override - protected void renderAppearanceStream(Graphics2D g) { - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - Shapes shapes = appearanceState.getShapes(); - - // Appearance stream takes precedence over the quad points. - if (shapes != null) { - super.renderAppearanceStream(g); - } - // draw the quad points. - else if (quadrilaterals != null) { - - // check to see if we are painting highlight annotations. - // if so we add some transparency to the context. - if (subtype != null && SUBTYPE_HIGHLIGHT.equals(subtype)) { - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .30f)); - // remove other alpha defs from painting - if (shapes != null) { - shapes.setPaintAlpha(false); - } - } - - Object tmp = getObject(RECTANGLE_KEY); - Rectangle2D.Float rectangle = null; - if (tmp instanceof List) { - rectangle = library.getRectangle(entries, RECTANGLE_KEY); - } - - // get the current position of the userSpaceRectangle - Rectangle2D.Float origRect = getUserSpaceRectangle(); - // build the transform to go back to users space - AffineTransform af = g.getTransform(); - double x = rectangle.getX() - origRect.getX(); - double y = rectangle.getY() - origRect.getY(); - af.translate(-origRect.getX(), -origRect.getY()); - g.setTransform(af); - g.setColor(highlightColor); - AffineTransform af2 = new AffineTransform(); - af2.translate(-x, -y); - for (Shape shape : quadrilaterals) { - g.fill(af2.createTransformedShape(shape)); - } - // revert the alpha value. - if (subtype != null && SUBTYPE_HIGHLIGHT.equals(subtype)) { - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f)); - // remove other alpha defs from painting - if (shapes != null) { - shapes.setPaintAlpha(true); - } - } - } - } - - public void setMarkupPath(GeneralPath markupPath) { - this.markupPath = markupPath; - } - - public GeneralPath getMarkupPath() { - return markupPath; - } - - public void setMarkupBounds(ArrayList markupBounds) { - this.markupBounds = markupBounds; - } - - public Color getTextMarkupColor() { - return textMarkupColor; - } - - public void setTextMarkupColor(Color textMarkupColor) { - this.textMarkupColor = textMarkupColor; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/TextWidgetAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/TextWidgetAnnotation.java deleted file mode 100644 index 4cf425f68d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/TextWidgetAnnotation.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.pobjects.acroform.TextFieldDictionary; -import org.icepdf.core.pobjects.acroform.VariableTextFieldDictionary; -import org.icepdf.core.pobjects.fonts.FontFile; -import org.icepdf.core.pobjects.fonts.FontManager; -import org.icepdf.core.util.Library; - -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.HashMap; - -/** - * Text field (field type Text) is a box or space for text fill-in data typically - * entered from a keyboard. The text may be restricted to a single line or may - * be permitted to span multiple lines, depending on the setting of the Multi line - * flag in the field dictionary’s Ff entry. Table 228 shows the flags pertaining - * to this type of field. A text field shall have a field type of Text. A conforming - * PDF file, and a conforming processor shall obey the usage guidelines as - * defined by the big flags below. - * - * @since 5.1 - */ -public class TextWidgetAnnotation extends AbstractWidgetAnnotation { - - protected FontFile fontFile; - - private TextFieldDictionary fieldDictionary; - - public TextWidgetAnnotation(Library l, HashMap h) { - super(l, h); - fieldDictionary = new TextFieldDictionary(library, entries); - fontFile = fieldDictionary.getFont() != null ? fieldDictionary.getFont().getFont() : null; - if (fontFile == null) { - fontFile = FontManager.getInstance().initialize().getInstance( - fieldDictionary.getFontName().toString(), 0); - } - } - - public void resetAppearanceStream(double dx, double dy, AffineTransform pageTransform) { - - // we won't touch password fields, we'll used the original display - TextFieldDictionary.TextFieldType textFieldType = fieldDictionary.getTextFieldType(); - if (textFieldType == TextFieldDictionary.TextFieldType.TEXT_PASSWORD) { - // nothing to do, let the password comp handle the look. - } else { - // get at the original postscript as well alter the marked content - Appearance appearance = appearances.get(currentAppearance); - AppearanceState appearanceState = appearance.getSelectedAppearanceState(); - Rectangle2D bbox = appearanceState.getBbox(); - // putting in identity, as we a trump any cm in the annotation stream. - AffineTransform matrix = new AffineTransform();//appearanceState.getMatrix(); - String currentContentStream = appearanceState.getOriginalContentStream(); - currentContentStream = buildTextWidgetContents(currentContentStream); - - // finally create the shapes from the altered stream. - if (currentContentStream != null) { - appearanceState.setContentStream(currentContentStream.getBytes()); - } - - // some widgets don't have AP dictionaries in such a case we need to create the form object - // and build out the default properties. - Form appearanceStream = getOrGenerateAppearanceForm(); - - if (appearanceStream != null) { - // update the content stream with the new stream data. - appearanceStream.setRawBytes(currentContentStream.getBytes()); - // add the appearance stream - StateManager stateManager = library.getStateManager(); - stateManager.addChange(new PObject(appearanceStream, appearanceStream.getPObjectReference())); - // add an AP entry for the - HashMap appearanceRefs = new HashMap(); - appearanceRefs.put(APPEARANCE_STREAM_NORMAL_KEY, appearanceStream.getPObjectReference()); - entries.put(APPEARANCE_STREAM_KEY, appearanceRefs); - Rectangle2D formBbox = new Rectangle2D.Float( - (float) bbox.getX(), (float) bbox.getY(), (float) bbox.getWidth(), (float) bbox.getHeight()); - appearanceStream.setAppearance(null, matrix, formBbox); - // add link to resources on forum, if no resources exist. - if (library.getResources(appearanceStream.getEntries(), Form.RESOURCES_KEY) == null && - library.getCatalog().getInteractiveForm().getResources() != null) { - appearanceStream.getEntries().put(Form.RESOURCES_KEY, - library.getCatalog().getInteractiveForm().getResources().getEntries()); - } else { - // need to find some resources, try adding the parent page. - Page page = getPage(); - if (page != null && page.getResources() != null) { - appearanceStream.getEntries().put(Form.RESOURCES_KEY, page.getResources().getEntries()); - } - } - // add the annotation as changed as T entry has also been updated to reflect teh changed content. - stateManager.addChange(new PObject(this, this.getPObjectReference())); - - // compress the form object stream. - if (compressAppearanceStream) { - appearanceStream.getEntries().put(Stream.FILTER_KEY, new Name("FlateDecode")); - } else { - appearanceStream.getEntries().remove(Stream.FILTER_KEY); - } - appearanceStream.init(); - } - } - } - - public String buildTextWidgetContents(String currentContentStream) { - - // text widgets can be null, in this case we setup the default so we can add our own data. - if (currentContentStream == null || currentContentStream.equals("")) { - currentContentStream = " /Tx BMC q BT ET Q EMC"; - } - String contents = (String) fieldDictionary.getFieldValue(); -// int btStart = currentContentStream.indexOf("BT") + 2; -// int etEnd = currentContentStream.lastIndexOf("ET"); - int btStart = currentContentStream.indexOf("BMC") + 3; - int etEnd = currentContentStream.lastIndexOf("EMC"); - - String preBt = ""; - String postEt = ""; - String markedContent = ""; - if (btStart >= 0 && etEnd >= 0) { - // grab the pre post marked content postscript. - preBt = currentContentStream.substring(0, btStart) + " BT "; - postEt = "ET " + currentContentStream.substring(etEnd); - // marked content which we will use to try and find some data points. - markedContent = currentContentStream.substring(btStart, etEnd); - } else { - preBt = "/Tx BMC q BT "; - postEt = " ET Q EMC "; - } - - // check for a bounding box definition - Rectangle2D.Float bounds = findRectangle(preBt); - boolean isfourthQuadrant = false; - if (bounds != null && bounds.getHeight() < 0) { - isfourthQuadrant = true; - } - - // finally build out the new content stream - StringBuilder content = new StringBuilder(); - // calculate line light - double lineHeight = getLineHeight(fieldDictionary.getDefaultAppearance()); - - // apply the default appearance. - Page parentPage = getPage(); - content.append(generateDefaultAppearance(markedContent, - parentPage != null?parentPage.getResources():null, fieldDictionary)); - if (fieldDictionary.getDefaultAppearance() == null) { - lineHeight = getFontSize(markedContent); - } - - // apply the text offset, 4 is just a generic padding. - if (!isfourthQuadrant) { - double height = getBbox().getHeight(); - double size = fieldDictionary.getSize(); - content.append(lineHeight).append(" TL "); - // todo rework taking into account multi line height. - double hOffset = Math.ceil(size + (height - size)); - content.append(2).append(' ').append(hOffset).append(" Td "); - } else { - content.append(2).append(' ').append(2).append(" Td "); - } - // encode the text so it can be properly encoded in PDF string format - // hex encode the text so that we better handle character codes > 127 - content = encodeHexString(content, contents); - - // build the final content stream. - currentContentStream = preBt + content + postEt; - return currentContentStream; - } - - - public void reset() { - // set the fields value (V) to the default value defined by the DV key. - Object oldValue = fieldDictionary.getFieldValue(); - Object tmp = fieldDictionary.getDefaultFieldValue(); - if (tmp != null) { - // apply the default value - fieldDictionary.setFieldValue(fieldDictionary.getDefaultFieldValue(), getPObjectReference()); - changeSupport.firePropertyChange("valueFieldReset", oldValue, fieldDictionary.getFieldValue()); - } else { - // otherwise we remove the key - fieldDictionary.getEntries().remove(FieldDictionary.V_KEY); - fieldDictionary.setFieldValue("", getPObjectReference()); - if (changeSupport != null) { - changeSupport.firePropertyChange("valueFieldReset", oldValue, ""); - } - } - } - - @Override - public TextFieldDictionary getFieldDictionary() { - return fieldDictionary; - } - - public String generateDefaultAppearance(String content, Resources resources, - VariableTextFieldDictionary variableTextFieldDictionary) { - if (variableTextFieldDictionary != null) { - return variableTextFieldDictionary.generateDefaultAppearance(content, resources); - } - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/WidgetAnnotation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/WidgetAnnotation.java deleted file mode 100644 index 0562c67960..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/annotations/WidgetAnnotation.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.annotations; - -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.util.Library; - -import java.awt.geom.AffineTransform; -import java.util.HashMap; - -/** - * Interactive forms (see 12.7, “Interactive Formsâ€) use widget annotations (PDF 1.2) - * to represent the appearance of fields and to manage user interactions. As a - * convenience, when a field has only a single associated widget annotation, the - * contents of the field dictionary (12.7.3, “Field Dictionariesâ€) and the - * annotation dictionary may be merged into a single dictionary containing - * entries that pertain to both a field and an annotation. - * - * @since 5.0 - */ -public class WidgetAnnotation extends AbstractWidgetAnnotation { - - - private FieldDictionary fieldDictionary; - - - public WidgetAnnotation(Library l, HashMap h) { - super(l, h); - fieldDictionary = new FieldDictionary(library, entries); - } - - public void resetAppearanceStream(double dx, double dy, AffineTransform pageSpace) { - - } - - @Override - public void reset() { - - } - - @Override - public FieldDictionary getFieldDictionary() { - return fieldDictionary; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/ASCII85Decode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/ASCII85Decode.java deleted file mode 100644 index 3f6b174e18..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/ASCII85Decode.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.filters; - -import java.io.IOException; -import java.io.InputStream; - -/** - * @author Mark Collette - * @since 2.0 - */ - -public class ASCII85Decode extends ChunkingInputStream { - private boolean eof = false; - - public ASCII85Decode(InputStream input) { - super(); - - setInputStream(input); - setBufferSize(4); - } - - protected int fillInternalBuffer() throws IOException { - if (eof) - return -1; - long value = 0; - int count = 0; - long c = 0; - while (true) { - c = in.read(); - if (c < 0) { - eof = true; - break; - } - if (c == 0x00 || c == 0x09 || c == 0x0a || c == 0x0c || c == 0x0d || c == 0x20) - continue; - if (c == 126) { // '~' - eof = true; - break; - } - if (c == 122) { // 'z' - buffer[0] = 0; - buffer[1] = 0; - buffer[2] = 0; - buffer[3] = 0; - count = 0; - return 4; - } - count++; - value = value * 85 + (c - 33); - if (count == 5) { - buffer[0] = (byte) ((value >> 24) & 0xFF); - buffer[1] = (byte) ((value >> 16) & 0xFF); - buffer[2] = (byte) ((value >> 8) & 0xFF); - buffer[3] = (byte) (value & 0xFF); - value = 0; - count = 0; - return 4; - } - } - if (count == 2) { - value = value * (85L * 85 * 85) + 0xFFFFFF; - } else if (count == 3) { - value = value * (85L * 85) + 0xFFFF; - } else if (count == 4) { - value = value * (85L) + 0xFF; - } - if (count >= 2) - buffer[0] = (byte) ((value >> 24) & 0xFF); - if (count >= 3) - buffer[1] = (byte) ((value >> 16) & 0xFF); - if (count >= 4) - buffer[2] = (byte) ((value >> 8) & 0xFF); - return count - 1; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/ASCIIHexDecode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/ASCIIHexDecode.java deleted file mode 100644 index 0ab8312437..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/ASCIIHexDecode.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.filters; - -import org.icepdf.core.util.Parser; - -import java.io.IOException; -import java.io.InputStream; - -/** - * @author Mark Collette - * @since 2.0 - */ -public class ASCIIHexDecode extends ChunkingInputStream { - public ASCIIHexDecode(InputStream input) { - super(); - - setInputStream(input); - setBufferSize(4096); - } - - protected int fillInternalBuffer() throws IOException { - int numRead = 0; - - for (int i = 0; i < buffer.length; i++) { - byte val = 0; - int hi; - int lo; - do { - hi = in.read(); - } while (Parser.isWhitespace((char) hi)); - if (hi < 0) - break; - do { - lo = in.read(); - } while (Parser.isWhitespace((char) lo)); - - if (hi >= '0' && hi <= '9') { - hi -= '0'; - val |= ((byte) ((hi << 4) & 0xF0)); - } else if (hi >= 'a' && hi <= 'z') { - hi = hi - 'a' + 10; - val |= ((byte) ((hi << 4) & 0xF0)); - } else if (hi >= 'A' && hi <= 'Z') { - hi = hi - 'A' + 10; - val |= ((byte) ((hi << 4) & 0xF0)); - } - - if (lo >= 0) { - if (lo >= '0' && lo <= '9') { - lo -= '0'; - val |= ((byte) (lo & 0x0F)); - } else if (lo >= 'a' && lo <= 'z') { - lo = lo - 'a' + 10; - val |= ((byte) (lo & 0x0F)); - } else if (lo >= 'A' && lo <= 'Z') { - lo = lo - 'A' + 10; - val |= ((byte) (lo & 0x0F)); - } - } - buffer[numRead++] = val; - } - - if (numRead == 0) - return -1; - return numRead; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/CCITTFax.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/CCITTFax.java deleted file mode 100644 index 8dd37a494e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/CCITTFax.java +++ /dev/null @@ -1,901 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.filters; - - -import org.icepdf.core.io.BitStream; -import org.icepdf.core.io.ZeroPaddedInputStream; -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import javax.imageio.ImageIO; -import javax.imageio.ImageReader; -import java.awt.*; -import java.awt.image.*; -import java.awt.image.renderable.ParameterBlock; -import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Many facsimile and document imaging file formats support a form of lossless - * data compression often described as CCITT encoding. The CCITT (International - * Telegraph and Telephone Consultative Committee) is a standards organization - * that has developed a series of communications protocols for the facsimile - * transmission of black-and-white images over telephone lines and data networks. - * These protocols are known officially as the CCITT T.4 and T.6 standards but - * are more commonly referred to as CCITT Group 3 and Group 4 compression, - * respectively. - *

- * The CCITT actually defines three algorithms for the encoding of bi-level image data: - * Group 3 One-Dimensional (G31D) - * Group 3 Two-Dimensional (G32D) - not implemented - * Group 4 Two-Dimensional (G42D) - */ -public class CCITTFax { - - private static final Logger logger = - Logger.getLogger(CCITTFax.class.toString()); - - // white codes - static final String[] _twcodes = { - "00110101", "000111", "0111", "1000", "1011", "1100", "1110", "1111", - "10011", "10100", "00111", "01000", "001000", "000011", "110100", - "110101", "101010", "101011", "0100111", "0001100", "0001000", - "0010111", "0000011", "0000100", "0101000", "0101011", "0010011", - "0100100", "0011000", "00000010", "00000011", "00011010", "00011011", - "00010010", "00010011", "00010100", "00010101", "00010110", - "00010111", "00101000", "00101001", "00101010", "00101011", - "00101100", "00101101", "00000100", "00000101", "00001010", - "00001011", "01010010", "01010011", "01010100", "01010101", - "00100100", "00100101", "01011000", "01011001", "01011010", - "01011011", "01001010", "01001011", "00110010", "00110011", - "00110100" - }; - - // wite codes - static final String[] _mwcodes = { - "11011", "10010", "010111", "0110111", "00110110", "00110111", "01100100", - "01100101", "01101000", "01100111", "011001100", "011001101", - "011010010", "011010011", "011010100", "011010101", "011010110", - "011010111", "011011000", "011011001", "011011010", "011011011", - "010011000", "010011001", "010011010", "011000", "010011011" - }; - - // black codes - static final String[] _tbcodes = { - "0000110111", "010", "11", "10", "011", "0011", "0010", "00011", "000101", - "000100", "0000100", "0000101", "0000111", "00000100", "00000111", - "000011000", "0000010111", "0000011000", "0000001000", "00001100111", - "00001101000", "00001101100", "00000110111", "00000101000", - "00000010111", "00000011000", "000011001010", "000011001011", - "000011001100", "000011001101", "000001101000", "000001101001", - "000001101010", "000001101011", "000011010010", "000011010011", - "000011010100", "000011010101", "000011010110", "000011010111", - "000001101100", "000001101101", "000011011010", "000011011011", - "000001010100", "000001010101", "000001010110", "000001010111", - "000001100100", "000001100101", "000001010010", "000001010011", - "000000100100", "000000110111", "000000111000", "000000100111", - "000000101000", "000001011000", "000001011001", "000000101011", - "000000101100", "000001011010", "000001100110", "000001100111" - }; - // black codes - static final String[] _mbcodes = { - "0000001111", "000011001000", "000011001001", "000001011011", "000000110011", - "000000110100", "000000110101", "0000001101100", "0000001101101", - "0000001001010", "0000001001011", "0000001001100", "0000001001101", - "0000001110010", "0000001110011", "0000001110100", "0000001110101", - "0000001110110", "0000001110111", "0000001010010", "0000001010011", - "0000001010100", "0000001010101", "0000001011010", "0000001011011", - "0000001100100", "0000001100101" - }; - static final String[] _extmcodes = { - "00000001000", "00000001100", "00000001101", "000000010010", "000000010011", - "000000010100", "000000010101", "000000010110", "000000010111", - "000000011100", "000000011101", "000000011110", "000000011111" - }; - - // Mode command binary values - static final String[] _modecodes = { - "0001", // P - Pass Mode - "001", // H - Horizontal Mode, when neither P or V Modes - "1", // V0 - Vertical Mode - "011", // VR1 - Vertical Mode, one pixel to the right - "000011", // VR2 - Vertical Mode, two pixel to the right - "0000011", // VR3 - Vertical Mode, three pixel to the right - "010", // VL1 - Vertical Mode, one pixel to the left - "000010", // VL2 - Vertical Mode, two pixel to the left - "0000010", // VL3 - Vertical Mode, three pixel to the left - "0000001111", // EXT2D - Extension, 2D - "000000001111", // EXT1D - Extension, 1D - "000000000001" // EOL - }; - - private static class Code { - private long value; - private int length; - private int tablePosition; - - public Code() { - value = 0L; - length = 0; - } - - public Code(String strValue, int tablePosition) { - value = 0L; - length = 0; - this.tablePosition = tablePosition; - for (int i = 0; i < strValue.length(); i++) - append(strValue.charAt(i) == '1'); - } - - public final void append(boolean bit) { - // This is effectively similar to the old String code, - // which kept the extra bits, but would then not match - // any of the table entries - if (bit) { - if (length <= 63) { - long mask = (1L << length); - value |= mask; - } - } - length++; - } - - public final boolean equals(Object ob) { - if (ob instanceof Code) { - Code c = (Code) ob; - return (value == c.value && length == c.length); - } - return false; - } - - public final void reset() { - value = 0L; - length = 0; - } - - public final int getLength() { - return length; - } - - public final int getTablePosition() { - return tablePosition; - } - } - - static final Code[][] twcodes = convertStringArrayToCodeArray2D(_twcodes); - static final Code[][] mwcodes = convertStringArrayToCodeArray2D(_mwcodes); - static final Code[][] tbcodes = convertStringArrayToCodeArray2D(_tbcodes); - static final Code[][] mbcodes = convertStringArrayToCodeArray2D(_mbcodes); - static final Code[][] extmcodes = convertStringArrayToCodeArray2D(_extmcodes); - static final Code[][] modecodes = convertStringArrayToCodeArray2D(_modecodes); - - private static Code[][] convertStringArrayToCodeArray2D(String[] strArray) { - int len = strArray.length; - - // Make histogram of sizes - int[] codeLengths = new int[64]; - for (String aStrArray : strArray) { - int entryLength = aStrArray.length(); - codeLengths[entryLength]++; - } - - // Make a 2d array of Code objects, where the first index is for - // the length of the Code, and the second index differentiates - // between all Code objects with that length - // In this way, we separate all Code objects by their length, - // and can thus reduce the search space - // In theory, we could then sort each sublist, and do a binary search... - int largestLength = codeLengths.length - 1; - while (largestLength > 0 && codeLengths[largestLength] == 0) - largestLength--; - Code[][] codeArray = new Code[largestLength + 1][]; - for (int i = 0; i < codeArray.length; i++) - codeArray[i] = new Code[codeLengths[i]]; - - for (int i = 0; i < len; i++) { - int entryLength = strArray[i].length(); - Code[] entries = codeArray[entryLength]; - for (int j = 0; j < entries.length; j++) { - if (entries[j] == null) { - entries[j] = new Code(strArray[i], i); - break; - } - } - } - - return codeArray; - } - - private static int findPositionInTable(Code lookFor, Code[][] lookIn) { - int lookForIndex = lookFor.getLength(); - if (lookForIndex >= lookIn.length) - return -1; - Code[] lookInWithSameLength = lookIn[lookForIndex]; - if (lookInWithSameLength == null) - return -1; - for (Code potentialMatch : lookInWithSameLength) { - if (lookFor.equals(potentialMatch)) - return potentialMatch.getTablePosition(); - } - return -1; - - } - - // Black and white colour bit values. - static int black = 0; - static int white = 1; - - // Never actually used. -// class FaxCode { -// FaxCode zero; -// FaxCode one; -// boolean leaf; -// int tipo; -// int len; -// } - - private static final short TIFF_COMPRESSION_NONE_default = 1; - private static final short TIFF_COMPRESSION_GROUP3_1D = 2; - private static final short TIFF_COMPRESSION_GROUP3_2D = 3; - private static final short TIFF_COMPRESSION_GROUP4 = 4; - - private static final String[] TIFF_COMPRESSION_NAMES = new String[]{ - "", - "TIFF_COMPRESSION_NONE_default", - "TIFF_COMPRESSION_GROUP3_1D", - "TIFF_COMPRESSION_GROUP3_2D", - "TIFF_COMPRESSION_GROUP4" - }; - - private static final short TIFF_PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO_default = 0; - private static final short TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO = 1; - - private static boolean USE_JAI_IMAGE_LIBRARY = false; - private static Method jaiCreate = null; - private static Method ssWrapInputStream = null; - private static Method roGetAsBufferedImage = null; - - static { - try { - Class jaiClass = Class.forName("javax.media.jai.JAI"); - jaiCreate = jaiClass.getMethod("create", String.class, ParameterBlock.class); - Class ssClass = Class.forName("com.sun.media.jai.codec.SeekableStream"); - ssWrapInputStream = ssClass.getMethod("wrapInputStream", InputStream.class, Boolean.TYPE); - Class roClass = Class.forName("javax.media.jai.RenderedOp"); - roGetAsBufferedImage = roClass.getMethod("getAsBufferedImage"); - USE_JAI_IMAGE_LIBRARY = true; - } catch (Exception e) { - logger.info("javax.media.jai.JAI could not bef found on the class path"); - } - - if (logger.isLoggable(Level.FINER)) { - Iterator iter = ImageIO.getImageReadersByFormatName("TIFF"); - ImageReader reader; - while (iter.hasNext()) { - reader = iter.next(); - logger.finer("CCITTFaxDecode Image reader: " + reader); - } - } - } - - /** - * Map bitstream values to tw and mw codes. - * - * @param inb bit stream containing the CCITT data - * @throws java.io.IOException - */ - static int findWhite(BitStream inb, Code code) throws IOException { - return findTone(inb, code, twcodes, mwcodes); - } - - /** - * Finds the next black occruence in the stream - * - * @throws java.io.IOException - */ - static int findBlack(BitStream inb, Code code) throws IOException { - return findTone(inb, code, tbcodes, mbcodes); - } - - static int findTone(BitStream inb, Code code, Code[][] tCodes, Code[][] mCodes) throws IOException { - code.reset(); - while (!inb.atEndOfFile()) { - int i = inb.getBits(1); - code.append(i != 0); - int j; - j = findPositionInTable(code, tCodes); - if (j >= 0) { - //System.err.println("BINGO! tb "+_tbcodes[j]+" "+j); - return j; - } - j = findPositionInTable(code, mCodes); - if (j >= 0) { - //System.err.println("BINGO! mb "+_mbcodes[j]+" "+(j+1)*64); - return (j + 1) * 64; - } - j = findPositionInTable(code, extmcodes); - if (j >= 0) { - //System.err.println("BINGO! extm "+_extmcodes[j]+" "+(1792+j*64)); - return (1792 + j * 64); - } - } - inb.close(); - //System.err.println("CODE ERROR! " + code); - return 0; - } - - /** - * @throws java.io.IOException - */ - static void addRun(int x, G4State s, BitStream out) throws IOException { - s.runLength += x; - s.cur[s.curIndex++] = s.runLength; - s.a0 += x; - if (s.runLength > 0) { - // black/white color switch !s.white - out.putRunBits(s.white ? white : black, s.runLength); - } - out.close(); - s.runLength = 0; - } - - /** - * @throws java.io.IOException - */ - static int readmode(BitStream inb, Code code) throws IOException { - code.reset(); - while (!inb.atEndOfFile()) { - int i = inb.getBits(1); - code.append(i != 0); - int j = findPositionInTable(code, modecodes); - if (j >= 0) { - return j; - } - } - inb.close(); - return -1; - } - - /** - */ - static void detectB1(G4State s) { - if (s.curIndex != 0) { - while (s.b1 <= s.a0 && s.b1 < s.width) { - int r = s.ref[s.refIndex] + s.ref[s.refIndex + 1]; - if (r == 0) - s.b1 = s.width; - s.b1 += r; - if (s.refIndex + 2 < s.ref.length) { - s.refIndex += 2; - } -// else { - //System.out.println("ERROR in detectB1, refIndex=" + s.refIndex - // + ", ref.length=" + s.ref.length); -// } - } - } - } - - /** - */ - static void decodePass(G4State s) { - detectB1(s); - s.b1 += s.ref[s.refIndex++]; - s.runLength += s.b1 - s.a0; - s.a0 = s.b1; - s.b1 += s.ref[s.refIndex++]; - } - - /** - * @throws java.io.IOException - */ - static void decodeHorizontal(BitStream in, BitStream out, G4State s, Code code) throws IOException { - int rl; - do { - rl = s.white ? findWhite(in, code) : findBlack(in, code); - if (rl >= 0) { - if (rl < 64) { - addRun(rl + s.longrun, s, out); - s.white = !s.white; - s.longrun = 0; - } else { - s.longrun += rl; - } - } else { - addRun(rl, s, out); - } - } while (rl >= 64); - out.close(); - } - - /** - * @throws java.io.IOException - */ - static void resetRuns(BitStream outb, G4State state) throws IOException { - //System.err.println("EOL! "+state.a0); - state.white = true; - addRun(0, state, outb); - if (state.a0 != state.width) { - //System.out.println( (state.a0 < state.width ? "Premature EOL" : "Line length mismatch") ); - while (state.a0 > state.width) - state.a0 -= state.cur[--state.curIndex]; - if (state.a0 < state.width) { - if (state.a0 < 0) - state.a0 = 0; - if ((state.curIndex & 0x1) != 0) - addRun(0, state, outb); - addRun(state.width - state.a0, state, outb); - } else if (state.a0 > state.width) { - addRun(state.width, state, outb); - addRun(0, state, outb); - } - } - int tmp[] = state.ref; - state.ref = state.cur; - state.cur = tmp; - //now zero out extra spots for runs - for (int i = state.curIndex; i < state.width; i++) - state.ref[i] = 0; - for (int i = 0; i < state.width; i++) - state.cur[i] = 0; - state.runLength = 0; - state.a0 = 0; - state.b1 = state.ref[0]; - state.refIndex = 1; - state.curIndex = 0; - - outb.close(); - } - - /** - */ - public static void Group4Decode(InputStream in, OutputStream out, int width, boolean blackIs1) { - BitStream inb = new BitStream(in); - BitStream outb = new BitStream(out); - // assign default colour mapping - black = 0; - white = 1; - - // apply blackIs1, which inverts the colour pallet - if (blackIs1) { - black = 1; - white = 0; - } - - Code code = new Code(); - - try { - G4State graphicState = new G4State(width); - while (!inb.atEndOfFile()) { - int mode = readmode(inb, code); - switch (mode) { - case 0: // P - decodePass(graphicState); - continue; - case 1: // H - decodeHorizontal(inb, outb, graphicState, code); - decodeHorizontal(inb, outb, graphicState, code); - detectB1(graphicState); - break; - case 2: // V0 - detectB1(graphicState); - addRun(graphicState.b1 - graphicState.a0, graphicState, outb); - graphicState.white = !graphicState.white; - graphicState.b1 += graphicState.ref[graphicState.refIndex++]; - break; - case 3: // VR1 - detectB1(graphicState); - addRun(graphicState.b1 - graphicState.a0 + 1, graphicState, outb); - graphicState.white = !graphicState.white; - graphicState.b1 += graphicState.ref[graphicState.refIndex++]; - break; - case 4: // VR2 - detectB1(graphicState); - addRun(graphicState.b1 - graphicState.a0 + 2, graphicState, outb); - graphicState.white = !graphicState.white; - graphicState.b1 += graphicState.ref[graphicState.refIndex++]; - break; - case 5: // VR3 - detectB1(graphicState); - addRun(graphicState.b1 - graphicState.a0 + 3, graphicState, outb); - graphicState.white = !graphicState.white; - graphicState.b1 += graphicState.ref[graphicState.refIndex++]; - break; - case 6: // VL1 - detectB1(graphicState); - addRun(graphicState.b1 - graphicState.a0 - 1, graphicState, outb); - graphicState.white = !graphicState.white; - if (graphicState.refIndex > 0) - graphicState.b1 -= graphicState.ref[--graphicState.refIndex]; - break; - case 7: // VL2 - detectB1(graphicState); - addRun(graphicState.b1 - graphicState.a0 - 2, graphicState, outb); - graphicState.white = !graphicState.white; - if (graphicState.refIndex > 0) - graphicState.b1 -= graphicState.ref[--graphicState.refIndex]; - break; - case 8: // VL3 - detectB1(graphicState); - addRun(graphicState.b1 - graphicState.a0 - 3, graphicState, outb); - graphicState.white = !graphicState.white; - if (graphicState.refIndex > 0) - graphicState.b1 -= graphicState.ref[--graphicState.refIndex]; - break; - case 11: // EOL - resetRuns(outb, graphicState); - break; - default: - //System.err.println("UNK! "+mode); - } - if (graphicState.a0 >= graphicState.width) { - resetRuns(outb, graphicState); - } - } - // do a little memory clean up. - inb.close(); - outb.close(); - in.close(); - // out.flush(); // need this for further proccessing - out.close(); - } catch (Exception e) { - logger.log(Level.FINE, "Error decoding group4 CITTFax", e); - } - } - - public static BufferedImage attemptDeriveBufferedImageFromBytes( - ImageStream stream, Library library, HashMap streamDictionary, Color fill) throws InvocationTargetException, IllegalAccessException { - if (!USE_JAI_IMAGE_LIBRARY) - return null; - - boolean imageMask = stream.isImageMask(); - List decodeArray = (List) library.getObject(streamDictionary, ImageStream.DECODE_KEY); - // get decode parameters from stream properties - HashMap decodeParmsDictionary = library.getDictionary(streamDictionary, ImageStream.DECODEPARMS_KEY); - boolean blackIs1 = stream.getBlackIs1(library, decodeParmsDictionary); - // double check for blackIs1 in the main dictionary. - if (!blackIs1 && ImageStream.CHECK_PARENT_BLACK_IS_1) { - blackIs1 = stream.getBlackIs1(library, streamDictionary); - } - float k = library.getFloat(decodeParmsDictionary, ImageStream.K_KEY); - - short compression = TIFF_COMPRESSION_NONE_default; - if (k < 0) compression = TIFF_COMPRESSION_GROUP4; - else if (k > 0) compression = TIFF_COMPRESSION_GROUP3_2D; - else if (k == 0) compression = TIFF_COMPRESSION_GROUP3_1D; - boolean hasHeader; - - InputStream input = stream.getDecodedByteArrayInputStream(); - if (input == null) - return null; - input = new ZeroPaddedInputStream(input); - BufferedInputStream bufferedInput = new BufferedInputStream(input, 1024); - bufferedInput.mark(4); - try { - int hb1 = bufferedInput.read(); - int hb2 = bufferedInput.read(); - bufferedInput.reset(); - if (hb1 < 0 || hb2 < 0) { - input.close(); - return null; - } - hasHeader = ((hb1 == 0x4d && hb2 == 0x4d) || (hb1 == 0x49 && hb2 == 0x49)); - } catch (IOException e) { - try { - input.close(); - } catch (IOException ioe) { - // keep quiet - } - return null; - } - input = bufferedInput; - - BufferedImage img; - - byte[] fakeHeaderBytes; - if (!hasHeader) { - // Apparently if the stream dictionary contains all the necessary info about - // the TIFF data in the stream, then some encoders omit the standard - // TIFF header in the stream, which confuses some image decoders, like JAI, - // in which case we inject a TIFF header which is derived from the stream - // dictionary. - fakeHeaderBytes = new byte[]{ - // TIFF Header - 0x4d, 0x4d, // 00 : Big (sane) endian - 0x00, 0x2a, // 02 : Magic 42 - 0x00, 0x00, 0x00, 0x08, // 04 : Offset to first IFD - - // First IFD - 0x00, 0x0c, // 08 : Num Directory Entries - // Directory Entries: ushort tag, ushort type, uint count, uint valueOrOffset - 0x00, (byte) 0xfe, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // 0a : NewSubfileType - 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // 16 : ImageWidth - 0x01, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // 22 : ImageLength - 0x01, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // 2E : BitsPerSample - 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // 3A : Compression - 0x01, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // 46 : PhotometricInterpretation - 0x01, 0x11, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, (byte) 0xAE, // 52 : StripOffsets - 0x01, 0x16, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // 5E : RowsPerStrip - 0x01, 0x17, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // 6A : StripByteCounts - 0x01, 0x1A, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, (byte) 0x9E, // 76 : XResolution - 0x01, 0x1B, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, (byte) 0xA6, // 82 : YResolution - 0x01, 0x28, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // 8E : ResolutionUnit - 0x00, 0x00, 0x00, 0x00, // 9A : Next IFD - // Values from IFD, which don't fit in value field - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, // 9E : XResolution RATIONAL value - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01}; // A6 : YResolution RATIONAL value - // AE : Begin data - - // Have to fill in values for: ImageWidth, ImageLength, BitsPerSample, Compression, - // PhotometricIntrerpretation, RowsPerStrip, StripByteCounts - - boolean pdfStatesBlackAndWhite = false; - if (blackIs1) { - pdfStatesBlackAndWhite = true; - } - int width = library.getInt(streamDictionary, ImageStream.WIDTH_KEY); - int height = library.getInt(streamDictionary, ImageStream.HEIGHT_KEY); - - Object columnsObj = library.getObject(decodeParmsDictionary, ImageStream.COLUMNS_KEY); - if (columnsObj != null && columnsObj instanceof Number) { - int columns = ((Number) columnsObj).intValue(); - if (columns > width) - width = columns; - } - - Utils.setIntIntoByteArrayBE(width, fakeHeaderBytes, 0x1E); // ImageWidth - Utils.setIntIntoByteArrayBE(height, fakeHeaderBytes, 0x2A); // ImageLength - Object bitsPerComponent = // BitsPerSample - library.getObject(streamDictionary, ImageStream.BITSPERCOMPONENT_KEY); - if (bitsPerComponent != null && bitsPerComponent instanceof Number) { - Utils.setShortIntoByteArrayBE(((Number) bitsPerComponent).shortValue(), fakeHeaderBytes, 0x36); - } - - Utils.setShortIntoByteArrayBE(compression, fakeHeaderBytes, 0x42); - short photometricInterpretation = TIFF_PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO_default; - // PDF has default BlackIs1=false ==> White=1, Black=0 - // TIFF has default PhotometricInterpretation=0 ==> White=0, Black=1 - // So, if PDF doesn't state what black and white are, then use TIFF's default - if (pdfStatesBlackAndWhite) { - if (!blackIs1) - photometricInterpretation = TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO; - } - Utils.setShortIntoByteArrayBE( // PhotometricInterpretation - photometricInterpretation, fakeHeaderBytes, 0x4E); - Utils.setIntIntoByteArrayBE(height, fakeHeaderBytes, 0x66); // RowsPerStrip - int lengthOfCompressedData = Integer.MAX_VALUE - 1; // StripByteCounts - Object lengthValue = library.getObject(streamDictionary, Stream.LENGTH_KEY); - if (lengthValue != null && lengthValue instanceof Number) - lengthOfCompressedData = ((Number) lengthValue).intValue(); - else { - // JAI's SeekableStream pukes if we give a number too large - int approxLen = width * height; - if (approxLen > 0) - lengthOfCompressedData = approxLen; - } - Utils.setIntIntoByteArrayBE(lengthOfCompressedData, fakeHeaderBytes, 0x72); - - ByteArrayInputStream fakeHeaderBytesIn = new ByteArrayInputStream(fakeHeaderBytes); - org.icepdf.core.io.SequenceInputStream sin = new org.icepdf.core.io.SequenceInputStream(fakeHeaderBytesIn, input); - - img = deriveBufferedImageFromTIFFBytes(sin, library, lengthOfCompressedData, width, height, compression); - if (img == null) { - for (int i = 1; i <= 4; i++) { // Try the three other types of compression (1, 2, 3, 4) - compression++; - // We don't try the default uncompressed format, because it sometimes - // returns a blank image, which we don't want. If JAI fails, we - // want it to return null, so that the fallback code can have a try - if (compression > TIFF_COMPRESSION_GROUP4) - compression = TIFF_COMPRESSION_GROUP3_1D; - - Utils.setShortIntoByteArrayBE(compression, fakeHeaderBytes, 0x42); - input = stream.getDecodedByteArrayInputStream(); - if (input == null) - return null; - input = new ZeroPaddedInputStream(input); - fakeHeaderBytesIn = new ByteArrayInputStream(fakeHeaderBytes); - sin = new org.icepdf.core.io.SequenceInputStream(fakeHeaderBytesIn, input); - img = deriveBufferedImageFromTIFFBytes(sin, library, lengthOfCompressedData, width, height, compression); - if (img != null) { - break; - } - } - } - } else { - int width = library.getInt(streamDictionary, ImageStream.WIDTH_KEY); - int height = library.getInt(streamDictionary, ImageStream.HEIGHT_KEY); - int approxLen = width * height; - img = deriveBufferedImageFromTIFFBytes(input, library, approxLen, width, height, compression); - } - - if (img != null) { - img = applyImageMaskAndDecodeArray(img, imageMask, blackIs1, decodeArray, fill); - } - - return img; - } - - /** - * Calling code assumes that this method will trap all exceptions, - * so that null shows it didn't work - * - * @param in InputStream to TIFF byte data - * @return RenderedImage if could derive one, else null - */ - private static BufferedImage deriveBufferedImageFromTIFFBytes( - InputStream in, Library library, int compressedBytes, int width, int height, int compression) throws InvocationTargetException, IllegalAccessException { - BufferedImage img = null; - try { - /* - com.sun.media.jai.codec.SeekableStream s = com.sun.media.jai.codec.SeekableStream.wrapInputStream( in, true ); - ParameterBlock pb = new ParameterBlock(); - pb.add( s ); - javax.media.jai.RenderedOp op = javax.media.jai.JAI.create( "tiff", pb ); - */ - Object com_sun_media_jai_codec_SeekableStream_s = ssWrapInputStream.invoke(null, in, Boolean.TRUE); - ParameterBlock pb = new ParameterBlock(); - pb.add(com_sun_media_jai_codec_SeekableStream_s); - Object javax_media_jai_RenderedOp_op = jaiCreate.invoke(null, "tiff", pb); - - /* - * This was another approach: - - TIFFDecodeParam tiffDecodeParam = new TIFFDecodeParam(); - // tiffDecodeParam.setDecodePaletteAsShorts(true); - - ImageDecoder dec = ImageCodec.createImageDecoder("TIFF", s, tiffDecodeParam ); - - NullOpImage op = new NullOpImage( dec.decodeAsRenderedImage(0), null, null, OpImage.OP_IO_BOUND ); - - // RenderedImage img = dec.decodeAsRenderedImage(); - // RenderedImageAdapter ria = new RenderedImageAdapter(img); - // BufferedImage bi = ria.getAsBufferedImage(); - - */ - - if (javax_media_jai_RenderedOp_op != null) { - if (logger.isLoggable(Level.FINER)) { - logger.fine("Decoding TIFF: " + TIFF_COMPRESSION_NAMES[compression]); - } - // This forces the image to decode, so we can see if that fails, - // and then potentially try a different compression setting - /* op.getTile( 0, 0 ); */ - RenderedImage ri = (RenderedImage) javax_media_jai_RenderedOp_op; - Raster r = ri.getTile(0, 0); - - // Calling op.getAsBufferedImage() causes a spike in memory usage - // For example, for RenderedOp that's 100KB in size, we spike 18MB, - // with 1MB remaining and 17MB getting gc'ed - // So, we try to build it piecemeal instead - //System.out.println("Memory free: " + Runtime.getRuntime().freeMemory() + ", total:" + Runtime.getRuntime().totalMemory() + ", used: " + (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory())); - if (r instanceof WritableRaster) { - ColorModel cm = ri.getColorModel(); - img = new BufferedImage(cm, (WritableRaster) r, false, null); - } else { - /* img = op.getAsBufferedImage(); */ - img = (BufferedImage) roGetAsBufferedImage.invoke(javax_media_jai_RenderedOp_op); - } - } - } catch (Throwable e) { - // catch and return a null image so we can try again using a different compression method. - logger.finer("Decoding TIFF: " + TIFF_COMPRESSION_NAMES[compression] + " failed trying alternative"); - } finally { - try { - in.close(); - } catch (IOException e) { - // keep quiet - } - } - return img; - } - - private static BufferedImage applyImageMaskAndDecodeArray( - BufferedImage img, boolean imageMask, Boolean blackIs1, List decode, Color fill) { - // If the image we actually have is monochrome, and so is useful as an image mask - ColorModel cm = img.getColorModel(); - if (cm instanceof IndexColorModel && cm.getPixelSize() == 1) { - // From PDF 1.6 spec, concerning ImageMask and Decode array: - // [0 1] (the default for an image mask), a sample value of 0 marks - // the page with the current color, and a 1 leaves the previous - // contents unchanged. - // [1 0] Is the reverse - // In case alpha transparency doesn't work, it'll paint white opaquely - - boolean defaultDecode = - (decode == null) || - (0.0f == ((Number) decode.get(0)).floatValue()); - // From empirically testing 6 of the 9 possible combinations of - // BlackIs1 {true, false, not given} and Decode {[0 1], [1 0], not given} - // this is the rule. Unknown combinations: - // BlackIs1=false, Decode=[0 1] - // BlackIs1=false, Decode=[1 0] - // BlackIs1=true, Decode=[0 1] - boolean flag = ((blackIs1 == null) && (!defaultDecode)) || - ((blackIs1 != null) && blackIs1 && (decode == null)); - if (imageMask) { - int a = 0x00FFFFFF; // Clear if alpha supported, else white - int[] cmap = new int[]{ - (flag ? fill.getRGB() : a), - (flag ? a : fill.getRGB()) - }; - int transparentIndex = (flag ? 1 : 0); - IndexColorModel icm = new IndexColorModel( - cm.getPixelSize(), // the number of bits each pixel occupies - cmap.length, // the size of the color component arrays - cmap, // the array of color components - 0, // the starting offset of the first color component - true, // indicates whether alpha values are contained in the cmap array - transparentIndex, // the index of the fully transparent pixel - cm.getTransferType()); // the data type of the array used to represent pixel values. The data type must be either DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT - img = new BufferedImage( - icm, img.getRaster(), img.isAlphaPremultiplied(), null); - } else { - int[] cmap = new int[]{ - (flag ? 0xFF000000 : 0xFFFFFFFF), - (flag ? 0xFFFFFFFF : 0xFF000000) - }; - IndexColorModel icm = new IndexColorModel( - cm.getPixelSize(), // the number of bits each pixel occupies - cmap.length, // the size of the color component arrays - cmap, // the array of color components - 0, // the starting offset of the first color component - false, // indicates whether alpha values are contained in the cmap array - -1, // the index of the fully transparent pixel - cm.getTransferType()); // the data type of the array used to represent pixel values. The data type must be either DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT - img = new BufferedImage( - icm, img.getRaster(), img.isAlphaPremultiplied(), null); - } - } - return img; - } - - /* - public static void showRenderedImage(java.awt.image.RenderedImage ri, String frameTitle) { - System.out.println("showRenderedImage() \"" + frameTitle + "\""); - - // java.awt.Component djai = new com.sun.media.jai.widget.DisplayJAI( ri ); - java.awt.Component djai = null; - try { - Class displayClass = Class.forName("com.sun.media.jai.widget.DisplayJAI"); - if( displayClass != null ) { - java.lang.reflect.Constructor ctor = displayClass.getConstructor( - new Class[] { java.awt.image.RenderedImage.class } ); - djai = (java.awt.Component) ctor.newInstance( new Object[] { ri } ); - } - } - catch(Exception e) { - System.out.println("showRenderedImage() problem with JAI: " + e); - return; - } - - javax.swing.JFrame testFrame = new javax.swing.JFrame( frameTitle ); - testFrame.getContentPane().add( new javax.swing.JScrollPane(djai) ); - testFrame.pack(); - testFrame.setSize( new java.awt.Dimension(900,800) ); - testFrame.setVisible( true ); - System.out.println("showRenderedImage() shown"); - } - */ -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/CCITTFaxDecoder.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/CCITTFaxDecoder.java deleted file mode 100644 index ade1b95c40..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/CCITTFaxDecoder.java +++ /dev/null @@ -1,1579 +0,0 @@ -/* - * Based on the SUN code (see license beyond) changes are made to handle CCITTFax encoded - * data in a PDF image. This may or may not apply to real world CCITT documents. - * - * Copyright (c) 2007, intarsys consulting GmbH - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * - Neither the name of intarsys nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/* - * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * -Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * -Redistribution in binary form must reproduct the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY - * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR - * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE - * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING - * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS - * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, - * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER - * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF - * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * You acknowledge that Software is not designed,licensed or intended for use in - * the design, construction, operation or maintenance of any nuclear facility. - */ - -package org.icepdf.core.pobjects.filters; - - -public class CCITTFaxDecoder { - static int[] table1 = {0x00, // 0 bits are left in first byte - SHOULD - // NOT HAPPEN - 0x01, // 1 bits are left in first byte - 0x03, // 2 bits are left in first byte - 0x07, // 3 bits are left in first byte - 0x0f, // 4 bits are left in first byte - 0x1f, // 5 bits are left in first byte - 0x3f, // 6 bits are left in first byte - 0x7f, // 7 bits are left in first byte - 0xff // 8 bits are left in first byte - }; - - static int[] table2 = {0x00, // 0 - 0x80, // 1 - 0xc0, // 2 - 0xe0, // 3 - 0xf0, // 4 - 0xf8, // 5 - 0xfc, // 6 - 0xfe, // 7 - 0xff // 8 - }; - - // Table to be used when fillOrder = 2, for flipping bytes. - static byte[] flipTable = {0, -128, 64, -64, 32, -96, 96, -32, 16, -112, - 80, -48, 48, -80, 112, -16, 8, -120, 72, -56, 40, -88, 104, -24, - 24, -104, 88, -40, 56, -72, 120, -8, 4, -124, 68, -60, 36, -92, - 100, -28, 20, -108, 84, -44, 52, -76, 116, -12, 12, -116, 76, -52, - 44, -84, 108, -20, 28, -100, 92, -36, 60, -68, 124, -4, 2, -126, - 66, -62, 34, -94, 98, -30, 18, -110, 82, -46, 50, -78, 114, -14, - 10, -118, 74, -54, 42, -86, 106, -22, 26, -102, 90, -38, 58, -70, - 122, -6, 6, -122, 70, -58, 38, -90, 102, -26, 22, -106, 86, -42, - 54, -74, 118, -10, 14, -114, 78, -50, 46, -82, 110, -18, 30, -98, - 94, -34, 62, -66, 126, -2, 1, -127, 65, -63, 33, -95, 97, -31, 17, - -111, 81, -47, 49, -79, 113, -15, 9, -119, 73, -55, 41, -87, 105, - -23, 25, -103, 89, -39, 57, -71, 121, -7, 5, -123, 69, -59, 37, - -91, 101, -27, 21, -107, 85, -43, 53, -75, 117, -11, 13, -115, 77, - -51, 45, -83, 109, -19, 29, -99, 93, -35, 61, -67, 125, -3, 3, - -125, 67, -61, 35, -93, 99, -29, 19, -109, 83, -45, 51, -77, 115, - -13, 11, -117, 75, -53, 43, -85, 107, -21, 27, -101, 91, -37, 59, - -69, 123, -5, 7, -121, 71, -57, 39, -89, 103, -25, 23, -105, 87, - -41, 55, -73, 119, -9, 15, -113, 79, -49, 47, -81, 111, -17, 31, - -97, 95, -33, 63, -65, 127, -1,}; - - // The main 10 bit white runs lookup table - static short white[] = { - // 0 - 7 - 6430, 6400, 6400, 6400, 3225, 3225, 3225, 3225, - // 8 - 15 - 944, 944, 944, 944, 976, 976, 976, 976, - // 16 - 23 - 1456, 1456, 1456, 1456, 1488, 1488, 1488, 1488, - // 24 - 31 - 718, 718, 718, 718, 718, 718, 718, 718, - // 32 - 39 - 750, 750, 750, 750, 750, 750, 750, 750, - // 40 - 47 - 1520, 1520, 1520, 1520, 1552, 1552, 1552, 1552, - // 48 - 55 - 428, 428, 428, 428, 428, 428, 428, 428, - // 56 - 63 - 428, 428, 428, 428, 428, 428, 428, 428, - // 64 - 71 - 654, 654, 654, 654, 654, 654, 654, 654, - // 72 - 79 - 1072, 1072, 1072, 1072, 1104, 1104, 1104, 1104, - // 80 - 87 - 1136, 1136, 1136, 1136, 1168, 1168, 1168, 1168, - // 88 - 95 - 1200, 1200, 1200, 1200, 1232, 1232, 1232, 1232, - // 96 - 103 - 622, 622, 622, 622, 622, 622, 622, 622, - // 104 - 111 - 1008, 1008, 1008, 1008, 1040, 1040, 1040, 1040, - // 112 - 119 - 44, 44, 44, 44, 44, 44, 44, 44, - // 120 - 127 - 44, 44, 44, 44, 44, 44, 44, 44, - // 128 - 135 - 396, 396, 396, 396, 396, 396, 396, 396, - // 136 - 143 - 396, 396, 396, 396, 396, 396, 396, 396, - // 144 - 151 - 1712, 1712, 1712, 1712, 1744, 1744, 1744, 1744, - // 152 - 159 - 846, 846, 846, 846, 846, 846, 846, 846, - // 160 - 167 - 1264, 1264, 1264, 1264, 1296, 1296, 1296, 1296, - // 168 - 175 - 1328, 1328, 1328, 1328, 1360, 1360, 1360, 1360, - // 176 - 183 - 1392, 1392, 1392, 1392, 1424, 1424, 1424, 1424, - // 184 - 191 - 686, 686, 686, 686, 686, 686, 686, 686, - // 192 - 199 - 910, 910, 910, 910, 910, 910, 910, 910, - // 200 - 207 - 1968, 1968, 1968, 1968, 2000, 2000, 2000, 2000, - // 208 - 215 - 2032, 2032, 2032, 2032, 16, 16, 16, 16, - // 216 - 223 - 10257, 10257, 10257, 10257, 12305, 12305, 12305, 12305, - // 224 - 231 - 330, 330, 330, 330, 330, 330, 330, 330, - // 232 - 239 - 330, 330, 330, 330, 330, 330, 330, 330, - // 240 - 247 - 330, 330, 330, 330, 330, 330, 330, 330, - // 248 - 255 - 330, 330, 330, 330, 330, 330, 330, 330, - // 256 - 263 - 362, 362, 362, 362, 362, 362, 362, 362, - // 264 - 271 - 362, 362, 362, 362, 362, 362, 362, 362, - // 272 - 279 - 362, 362, 362, 362, 362, 362, 362, 362, - // 280 - 287 - 362, 362, 362, 362, 362, 362, 362, 362, - // 288 - 295 - 878, 878, 878, 878, 878, 878, 878, 878, - // 296 - 303 - 1904, 1904, 1904, 1904, 1936, 1936, 1936, 1936, - // 304 - 311 - -18413, -18413, -16365, -16365, -14317, -14317, -10221, -10221, - // 312 - 319 - 590, 590, 590, 590, 590, 590, 590, 590, - // 320 - 327 - 782, 782, 782, 782, 782, 782, 782, 782, - // 328 - 335 - 1584, 1584, 1584, 1584, 1616, 1616, 1616, 1616, - // 336 - 343 - 1648, 1648, 1648, 1648, 1680, 1680, 1680, 1680, - // 344 - 351 - 814, 814, 814, 814, 814, 814, 814, 814, - // 352 - 359 - 1776, 1776, 1776, 1776, 1808, 1808, 1808, 1808, - // 360 - 367 - 1840, 1840, 1840, 1840, 1872, 1872, 1872, 1872, - // 368 - 375 - 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, - // 376 - 383 - 6157, 6157, 6157, 6157, 6157, 6157, 6157, 6157, - // 384 - 391 - -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, - // 392 - 399 - -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, - // 400 - 407 - 14353, 14353, 14353, 14353, 16401, 16401, 16401, 16401, - // 408 - 415 - 22547, 22547, 24595, 24595, 20497, 20497, 20497, 20497, - // 416 - 423 - 18449, 18449, 18449, 18449, 26643, 26643, 28691, 28691, - // 424 - 431 - 30739, 30739, -32749, -32749, -30701, -30701, -28653, -28653, - // 432 - 439 - -26605, -26605, -24557, -24557, -22509, -22509, -20461, -20461, - // 440 - 447 - 8207, 8207, 8207, 8207, 8207, 8207, 8207, 8207, - // 448 - 455 - 72, 72, 72, 72, 72, 72, 72, 72, - // 456 - 463 - 72, 72, 72, 72, 72, 72, 72, 72, - // 464 - 471 - 72, 72, 72, 72, 72, 72, 72, 72, - // 472 - 479 - 72, 72, 72, 72, 72, 72, 72, 72, - // 480 - 487 - 72, 72, 72, 72, 72, 72, 72, 72, - // 488 - 495 - 72, 72, 72, 72, 72, 72, 72, 72, - // 496 - 503 - 72, 72, 72, 72, 72, 72, 72, 72, - // 504 - 511 - 72, 72, 72, 72, 72, 72, 72, 72, - // 512 - 519 - 104, 104, 104, 104, 104, 104, 104, 104, - // 520 - 527 - 104, 104, 104, 104, 104, 104, 104, 104, - // 528 - 535 - 104, 104, 104, 104, 104, 104, 104, 104, - // 536 - 543 - 104, 104, 104, 104, 104, 104, 104, 104, - // 544 - 551 - 104, 104, 104, 104, 104, 104, 104, 104, - // 552 - 559 - 104, 104, 104, 104, 104, 104, 104, 104, - // 560 - 567 - 104, 104, 104, 104, 104, 104, 104, 104, - // 568 - 575 - 104, 104, 104, 104, 104, 104, 104, 104, - // 576 - 583 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 584 - 591 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 592 - 599 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 600 - 607 - 4107, 4107, 4107, 4107, 4107, 4107, 4107, 4107, - // 608 - 615 - 266, 266, 266, 266, 266, 266, 266, 266, - // 616 - 623 - 266, 266, 266, 266, 266, 266, 266, 266, - // 624 - 631 - 266, 266, 266, 266, 266, 266, 266, 266, - // 632 - 639 - 266, 266, 266, 266, 266, 266, 266, 266, - // 640 - 647 - 298, 298, 298, 298, 298, 298, 298, 298, - // 648 - 655 - 298, 298, 298, 298, 298, 298, 298, 298, - // 656 - 663 - 298, 298, 298, 298, 298, 298, 298, 298, - // 664 - 671 - 298, 298, 298, 298, 298, 298, 298, 298, - // 672 - 679 - 524, 524, 524, 524, 524, 524, 524, 524, - // 680 - 687 - 524, 524, 524, 524, 524, 524, 524, 524, - // 688 - 695 - 556, 556, 556, 556, 556, 556, 556, 556, - // 696 - 703 - 556, 556, 556, 556, 556, 556, 556, 556, - // 704 - 711 - 136, 136, 136, 136, 136, 136, 136, 136, - // 712 - 719 - 136, 136, 136, 136, 136, 136, 136, 136, - // 720 - 727 - 136, 136, 136, 136, 136, 136, 136, 136, - // 728 - 735 - 136, 136, 136, 136, 136, 136, 136, 136, - // 736 - 743 - 136, 136, 136, 136, 136, 136, 136, 136, - // 744 - 751 - 136, 136, 136, 136, 136, 136, 136, 136, - // 752 - 759 - 136, 136, 136, 136, 136, 136, 136, 136, - // 760 - 767 - 136, 136, 136, 136, 136, 136, 136, 136, - // 768 - 775 - 168, 168, 168, 168, 168, 168, 168, 168, - // 776 - 783 - 168, 168, 168, 168, 168, 168, 168, 168, - // 784 - 791 - 168, 168, 168, 168, 168, 168, 168, 168, - // 792 - 799 - 168, 168, 168, 168, 168, 168, 168, 168, - // 800 - 807 - 168, 168, 168, 168, 168, 168, 168, 168, - // 808 - 815 - 168, 168, 168, 168, 168, 168, 168, 168, - // 816 - 823 - 168, 168, 168, 168, 168, 168, 168, 168, - // 824 - 831 - 168, 168, 168, 168, 168, 168, 168, 168, - // 832 - 839 - 460, 460, 460, 460, 460, 460, 460, 460, - // 840 - 847 - 460, 460, 460, 460, 460, 460, 460, 460, - // 848 - 855 - 492, 492, 492, 492, 492, 492, 492, 492, - // 856 - 863 - 492, 492, 492, 492, 492, 492, 492, 492, - // 864 - 871 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 872 - 879 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 880 - 887 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 888 - 895 - 2059, 2059, 2059, 2059, 2059, 2059, 2059, 2059, - // 896 - 903 - 200, 200, 200, 200, 200, 200, 200, 200, - // 904 - 911 - 200, 200, 200, 200, 200, 200, 200, 200, - // 912 - 919 - 200, 200, 200, 200, 200, 200, 200, 200, - // 920 - 927 - 200, 200, 200, 200, 200, 200, 200, 200, - // 928 - 935 - 200, 200, 200, 200, 200, 200, 200, 200, - // 936 - 943 - 200, 200, 200, 200, 200, 200, 200, 200, - // 944 - 951 - 200, 200, 200, 200, 200, 200, 200, 200, - // 952 - 959 - 200, 200, 200, 200, 200, 200, 200, 200, - // 960 - 967 - 232, 232, 232, 232, 232, 232, 232, 232, - // 968 - 975 - 232, 232, 232, 232, 232, 232, 232, 232, - // 976 - 983 - 232, 232, 232, 232, 232, 232, 232, 232, - // 984 - 991 - 232, 232, 232, 232, 232, 232, 232, 232, - // 992 - 999 - 232, 232, 232, 232, 232, 232, 232, 232, - // 1000 - 1007 - 232, 232, 232, 232, 232, 232, 232, 232, - // 1008 - 1015 - 232, 232, 232, 232, 232, 232, 232, 232, - // 1016 - 1023 - 232, 232, 232, 232, 232, 232, 232, 232,}; - - // Additional make up codes for both White and Black runs - static short[] additionalMakeup = {28679, 28679, 31752, (short) 32777, - (short) 33801, (short) 34825, (short) 35849, (short) 36873, - (short) 29703, (short) 29703, (short) 30727, (short) 30727, - (short) 37897, (short) 38921, (short) 39945, (short) 40969}; - - // Initial black run look up table, uses the first 4 bits of a code - static short[] initBlack = { - // 0 - 7 - 3226, 6412, 200, 168, 38, 38, 134, 134, // 8 - 15 - 100, 100, 100, 100, 68, 68, 68, 68}; - - // - static short[] twoBitBlack = {292, 260, 226, 226}; // 0 - 3 - - // Main black run table, using the last 9 bits of possible 13 bit code - static short black[] = { - // 0 - 7 - 62, 62, 30, 30, 0, 0, 0, 0, - // 8 - 15 - 0, 0, 0, 0, 0, 0, 0, 0, - // 16 - 23 - 0, 0, 0, 0, 0, 0, 0, 0, - // 24 - 31 - 0, 0, 0, 0, 0, 0, 0, 0, - // 32 - 39 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 40 - 47 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 48 - 55 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 56 - 63 - 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225, - // 64 - 71 - 588, 588, 588, 588, 588, 588, 588, 588, - // 72 - 79 - 1680, 1680, 20499, 22547, 24595, 26643, 1776, 1776, - // 80 - 87 - 1808, 1808, -24557, -22509, -20461, -18413, 1904, 1904, - // 88 - 95 - 1936, 1936, -16365, -14317, 782, 782, 782, 782, - // 96 - 103 - 814, 814, 814, 814, -12269, -10221, 10257, 10257, - // 104 - 111 - 12305, 12305, 14353, 14353, 16403, 18451, 1712, 1712, - // 112 - 119 - 1744, 1744, 28691, 30739, -32749, -30701, -28653, -26605, - // 120 - 127 - 2061, 2061, 2061, 2061, 2061, 2061, 2061, 2061, - // 128 - 135 - 424, 424, 424, 424, 424, 424, 424, 424, - // 136 - 143 - 424, 424, 424, 424, 424, 424, 424, 424, - // 144 - 151 - 424, 424, 424, 424, 424, 424, 424, 424, - // 152 - 159 - 424, 424, 424, 424, 424, 424, 424, 424, - // 160 - 167 - 750, 750, 750, 750, 1616, 1616, 1648, 1648, - // 168 - 175 - 1424, 1424, 1456, 1456, 1488, 1488, 1520, 1520, - // 176 - 183 - 1840, 1840, 1872, 1872, 1968, 1968, 8209, 8209, - // 184 - 191 - 524, 524, 524, 524, 524, 524, 524, 524, - // 192 - 199 - 556, 556, 556, 556, 556, 556, 556, 556, - // 200 - 207 - 1552, 1552, 1584, 1584, 2000, 2000, 2032, 2032, - // 208 - 215 - 976, 976, 1008, 1008, 1040, 1040, 1072, 1072, - // 216 - 223 - 1296, 1296, 1328, 1328, 718, 718, 718, 718, - // 224 - 231 - 456, 456, 456, 456, 456, 456, 456, 456, - // 232 - 239 - 456, 456, 456, 456, 456, 456, 456, 456, - // 240 - 247 - 456, 456, 456, 456, 456, 456, 456, 456, - // 248 - 255 - 456, 456, 456, 456, 456, 456, 456, 456, - // 256 - 263 - 326, 326, 326, 326, 326, 326, 326, 326, - // 264 - 271 - 326, 326, 326, 326, 326, 326, 326, 326, - // 272 - 279 - 326, 326, 326, 326, 326, 326, 326, 326, - // 280 - 287 - 326, 326, 326, 326, 326, 326, 326, 326, - // 288 - 295 - 326, 326, 326, 326, 326, 326, 326, 326, - // 296 - 303 - 326, 326, 326, 326, 326, 326, 326, 326, - // 304 - 311 - 326, 326, 326, 326, 326, 326, 326, 326, - // 312 - 319 - 326, 326, 326, 326, 326, 326, 326, 326, - // 320 - 327 - 358, 358, 358, 358, 358, 358, 358, 358, - // 328 - 335 - 358, 358, 358, 358, 358, 358, 358, 358, - // 336 - 343 - 358, 358, 358, 358, 358, 358, 358, 358, - // 344 - 351 - 358, 358, 358, 358, 358, 358, 358, 358, - // 352 - 359 - 358, 358, 358, 358, 358, 358, 358, 358, - // 360 - 367 - 358, 358, 358, 358, 358, 358, 358, 358, - // 368 - 375 - 358, 358, 358, 358, 358, 358, 358, 358, - // 376 - 383 - 358, 358, 358, 358, 358, 358, 358, 358, - // 384 - 391 - 490, 490, 490, 490, 490, 490, 490, 490, - // 392 - 399 - 490, 490, 490, 490, 490, 490, 490, 490, - // 400 - 407 - 4113, 4113, 6161, 6161, 848, 848, 880, 880, - // 408 - 415 - 912, 912, 944, 944, 622, 622, 622, 622, - // 416 - 423 - 654, 654, 654, 654, 1104, 1104, 1136, 1136, - // 424 - 431 - 1168, 1168, 1200, 1200, 1232, 1232, 1264, 1264, - // 432 - 439 - 686, 686, 686, 686, 1360, 1360, 1392, 1392, - // 440 - 447 - 12, 12, 12, 12, 12, 12, 12, 12, - // 448 - 455 - 390, 390, 390, 390, 390, 390, 390, 390, - // 456 - 463 - 390, 390, 390, 390, 390, 390, 390, 390, - // 464 - 471 - 390, 390, 390, 390, 390, 390, 390, 390, - // 472 - 479 - 390, 390, 390, 390, 390, 390, 390, 390, - // 480 - 487 - 390, 390, 390, 390, 390, 390, 390, 390, - // 488 - 495 - 390, 390, 390, 390, 390, 390, 390, 390, - // 496 - 503 - 390, 390, 390, 390, 390, 390, 390, 390, - // 504 - 511 - 390, 390, 390, 390, 390, 390, 390, 390,}; - - static byte[] twoDCodes = { - // 0 - 7 - 80, 88, 23, 71, 30, 30, 62, 62, // 8 - 15 - 4, 4, 4, 4, 4, 4, 4, 4, // 16 - 23 - 11, 11, 11, 11, 11, 11, 11, 11, // 24 - 31 - 11, 11, 11, 11, 11, 11, 11, 11, // 32 - 39 - 35, 35, 35, 35, 35, 35, 35, 35, // 40 - 47 - 35, 35, 35, 35, 35, 35, 35, 35, // 48 - 55 - 51, 51, 51, 51, 51, 51, 51, 51, // 56 - 63 - 51, 51, 51, 51, 51, 51, 51, 51, // 64 - 71 - 41, 41, 41, 41, 41, 41, 41, 41, // 72 - 79 - 41, 41, 41, 41, 41, 41, 41, 41, // 80 - 87 - 41, 41, 41, 41, 41, 41, 41, 41, // 88 - 95 - 41, 41, 41, 41, 41, 41, 41, 41, // 96 - 103 - 41, 41, 41, 41, 41, 41, 41, 41, // 104 - 111 - 41, 41, 41, 41, 41, 41, 41, 41, // 112 - 119 - 41, 41, 41, 41, 41, 41, 41, 41, // 120 - 127 - 41, 41, 41, 41, 41, 41, 41, 41,}; - - private int bitPointer; - - private int bytePointer; - - private byte[] data; - - private int w; - - private boolean align = false; - - private int fillOrder; - - // Data structures needed to store changing elements for the previous - // and the current scanline - private int changingElemSize = 0; - - private int[] prevChangingElems; - - private int[] currChangingElems; - - // Element at which to start search in getNextChangingElement - private int lastChangingElement = 0; - - private boolean fillBits = false; - - /** - * @param fillOrder The fill order of the compressed data bytes. - * @param w - * @param h - */ - public CCITTFaxDecoder(int fillOrder, int w, int h) { - this.fillOrder = fillOrder; - this.w = w; - - this.bitPointer = 0; - this.bytePointer = 0; - this.prevChangingElems = new int[w + 1]; - this.currChangingElems = new int[w + 1]; - } - - private boolean align() { - if (align && bitPointer != 0) { - bytePointer++; - bitPointer = 0; - return true; - } - return false; - } - - protected boolean consumeEOL() { - // Get the next 12 bits. - int next12Bits = nextNBits(12); - if (next12Bits == 1) { - // EOL found & consumed - return true; - } - // no EOL - unread and return - updatePointer(12); - return false; - } - - // Returns run length - private int decodeBlackCodeWord() { - int current; - int entry; - int bits; - int isT; - int code = -1; - int runLength = 0; - boolean isWhite = false; - - while (!isWhite) { - current = nextLesserThan8Bits(4); - entry = initBlack[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (code == 100) { - current = nextNBits(9); - entry = black[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (bits == 12) { - // Additional makeup codes - updatePointer(5); - current = nextLesserThan8Bits(4); - entry = additionalMakeup[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - runLength += code; - - updatePointer(4 - bits); - } else if (bits == 15) { - // EOL code - throw new RuntimeException( - "EOL code word encountered in Black run."); //$NON-NLS-1$ - } else { - runLength += code; - updatePointer(9 - bits); - if (isT == 0) { - isWhite = true; - } - } - } else if (code == 200) { - // Is a Terminating code - current = nextLesserThan8Bits(2); - entry = twoBitBlack[current]; - code = (entry >>> 5) & 0x07ff; - runLength += code; - bits = (entry >>> 1) & 0x0f; - updatePointer(2 - bits); - isWhite = true; - } else { - // Is a Terminating code - runLength += code; - updatePointer(4 - bits); - isWhite = true; - } - } - - return runLength; - } - - protected void decodeNextScanline(byte[] buffer, int lineOffset, - int bitOffset) { - int bits = 0; - int code = 0; - int isT = 0; - int current; - int entry; - int twoBits; - boolean isWhite = true; - - // Initialize starting of the changing elements array - changingElemSize = 0; - - // While scanline not complete - while (bitOffset < w) { - while (isWhite) { - // White run - current = nextNBits(10); - entry = white[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x0f; - - if (bits == 12) { // Additional Make up code - // Get the next 2 bits - twoBits = nextLesserThan8Bits(2); - // Consolidate the 2 new bits and last 2 bits into 4 bits - current = ((current << 2) & 0x000c) | twoBits; - entry = additionalMakeup[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - bitOffset += code; // Skip white run - - updatePointer(4 - bits); - } else if (bits == 0) { // ERROR - throw new RuntimeException("Invalid code encountered."); - } else if (bits == 15) { - // EOL recover - // move bits back... - updatePointer(10); - return; - } else { - // 11 bits - 0000 0111 1111 1111 = 0x07ff - code = (entry >>> 5) & 0x07ff; - bitOffset += code; - - updatePointer(10 - bits); - if (isT == 0) { - isWhite = false; - currChangingElems[changingElemSize++] = bitOffset; - } - } - } - - // Check whether this run completed one width, if so - // advance to next byte boundary for compression = 2. - if (bitOffset == w) { - align(); - break; - } - - while (!isWhite) { - // Black run - current = nextLesserThan8Bits(4); - entry = initBlack[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (code == 100) { - current = nextNBits(9); - entry = black[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x000f; - code = (entry >>> 5) & 0x07ff; - - if (bits == 12) { - // Additional makeup codes - updatePointer(5); - current = nextLesserThan8Bits(4); - entry = additionalMakeup[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(4 - bits); - } else if (bits == 15) { - // EOL recover - // unread bits ??? - updatePointer(9); - return; - } else { - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(9 - bits); - if (isT == 0) { - isWhite = true; - currChangingElems[changingElemSize++] = bitOffset; - } - } - } else if (code == 200) { - // Is a Terminating code - current = nextLesserThan8Bits(2); - entry = twoBitBlack[current]; - code = (entry >>> 5) & 0x07ff; - bits = (entry >>> 1) & 0x0f; - - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(2 - bits); - isWhite = true; - currChangingElems[changingElemSize++] = bitOffset; - } else { - // Is a Terminating code - setToBlack(buffer, lineOffset, bitOffset, code); - bitOffset += code; - - updatePointer(4 - bits); - isWhite = true; - currChangingElems[changingElemSize++] = bitOffset; - } - } - - // Check whether this run completed one width - if (bitOffset == w) { - - align(); - break; - } - } - - currChangingElems[changingElemSize++] = bitOffset; - } - - // One-dimensional decoding methods - public void decodeT41D(byte[] buffer, byte[] compData, int startX, - int height) { - this.data = compData; - int scanlineStride = (w + 7) / 8; - bitPointer = 0; - bytePointer = 0; - - int lineOffset = 0; - for (int i = 0; i < height; i++) { - consumeEOL(); - decodeNextScanline(buffer, lineOffset, startX); - lineOffset += scanlineStride; - } - } - - // Two-dimensional decoding methods - public void decodeT42D(byte[] buffer, byte[] compData, int startX, - int height) { - this.data = compData; - int scanlineStride = (w + 7) / 8; - bitPointer = 0; - bytePointer = 0; - - int a0; - int a1; - int b1; - int b2; - int[] b = new int[2]; - int entry; - int code; - int bits; - boolean isWhite; - int currIndex = 0; - int[] temp; - - // The data must start with an EOL code - if (readEOL(true) != 1) { - throw new RuntimeException("First scanline must be 1D encoded."); //$NON-NLS-1$ - } - - int lineOffset = 0; - int bitOffset; - - // Then the 1D encoded scanline data will occur, changing elements - // array gets set. - decodeNextScanline(buffer, lineOffset, startX); - lineOffset += scanlineStride; - - for (int lines = 1; lines < height; lines++) { - // Every line must begin with an EOL followed by a bit which - // indicates whether the following scanline is 1D or 2D encoded. - if (readEOL(false) == 0) { - // 2D encoded scanline follows - - // Initialize previous scanlines changing elements, and - // initialize current scanline's changing elements array - temp = prevChangingElems; - prevChangingElems = currChangingElems; - currChangingElems = temp; - currIndex = 0; - - // a0 has to be set just before the start of this scanline. - a0 = -1; - isWhite = true; - bitOffset = startX; - - lastChangingElement = 0; - - while (bitOffset < w) { - // Get the next changing element - getNextChangingElement(a0, isWhite, b); - - b1 = b[0]; - b2 = b[1]; - - // Get the next seven bits - entry = nextLesserThan8Bits(7); - - // Run these through the 2DCodes table - entry = (twoDCodes[entry] & 0xff); - - // Get the code and the number of bits used up - code = (entry & 0x78) >>> 3; - bits = entry & 0x07; - - if (code == 0) { - if (!isWhite) { - setToBlack(buffer, lineOffset, bitOffset, b2 - - bitOffset); - } - bitOffset = a0 = b2; - - // Set pointer to consume the correct number of bits. - updatePointer(7 - bits); - } else if (code == 1) { - // Horizontal - updatePointer(7 - bits); - - // identify the next 2 codes. - int number; - if (isWhite) { - number = decodeWhiteCodeWord(); - bitOffset += number; - currChangingElems[currIndex++] = bitOffset; - - number = decodeBlackCodeWord(); - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - currChangingElems[currIndex++] = bitOffset; - } else { - number = decodeBlackCodeWord(); - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - currChangingElems[currIndex++] = bitOffset; - - number = decodeWhiteCodeWord(); - bitOffset += number; - currChangingElems[currIndex++] = bitOffset; - } - - a0 = bitOffset; - } else if (code <= 8) { - // Vertical - a1 = b1 + (code - 5); - - currChangingElems[currIndex++] = a1; - - // We write the current color till a1 - 1 pos, - // since a1 is where the next color starts - if (!isWhite) { - setToBlack(buffer, lineOffset, bitOffset, a1 - - bitOffset); - } - bitOffset = a0 = a1; - isWhite = !isWhite; - - updatePointer(7 - bits); - } else { - throw new RuntimeException( - "Invalid code encountered while decoding 2D group 3 compressed data."); //$NON-NLS-1$ - } - } - - // Add the changing element beyond the current scanline for the - // other color too - currChangingElems[currIndex++] = bitOffset; - changingElemSize = currIndex; - } else { - // 1D encoded scanline follows - decodeNextScanline(buffer, lineOffset, startX); - } - - lineOffset += scanlineStride; - } - } - - public void decodeT6(byte[] buffer, byte[] compData, int startX, int height) { - this.data = compData; - int scanlineStride = (w + 7) / 8; - bitPointer = 0; - bytePointer = 0; - - int a0; - int a1; - int b1; - int b2; - int entry; - int code; - int bits; - boolean isWhite; - int currIndex; - int[] temp; - - // Return values from getNextChangingElement - int[] b = new int[2]; - - // uncompressedMode - have written some code for this, but this - // has not been tested due to lack of test images using this optional - - // Local cached reference - int[] cce = currChangingElems; - - // Assume invisible preceding row of all white pixels and insert - // both black and white changing elements beyond the end of this - // imaginary scanline. - changingElemSize = 0; - cce[changingElemSize++] = w; - cce[changingElemSize++] = w; - - int lineOffset = 0; - int bitOffset; - - for (int lines = 0; lines < height; lines++) { - // a0 has to be set just before the start of the scanline. - a0 = -1; - isWhite = true; - - // Assign the changing elements of the previous scanline to - // prevChangingElems and start putting this new scanline's - // changing elements into the currChangingElems. - temp = prevChangingElems; - prevChangingElems = currChangingElems; - cce = currChangingElems = temp; - currIndex = 0; - - // Start decoding the scanline at startX in the raster - bitOffset = startX; - - // Reset search start position for getNextChangingElement - lastChangingElement = 0; - - // Till one whole scanline is decoded - while (bitOffset < w) { - // Get the next changing element - getNextChangingElement(a0, isWhite, b); - b1 = b[0]; - b2 = b[1]; - - // Get the next seven bits - entry = nextLesserThan8Bits(7); - // Run these through the 2DCodes table - entry = (twoDCodes[entry] & 0xff); - - // Get the code and the number of bits used up - code = (entry & 0x78) >>> 3; - bits = entry & 0x07; - - if (code == 0) { // Pass - // We always assume WhiteIsZero format for fax. - if (!isWhite) { - if (b2 > w) { - b2 = w; - } - setToBlack(buffer, lineOffset, bitOffset, b2 - - bitOffset); - } - bitOffset = a0 = b2; - - // Set pointer to only consume the correct number of bits. - updatePointer(7 - bits); - } else if (code == 1) { // Horizontal - // Set pointer to only consume the correct number of bits. - updatePointer(7 - bits); - - // identify the next 2 alternating color codes. - int number; - if (isWhite) { - // Following are white and black runs - number = decodeWhiteCodeWord(); - bitOffset += number; - cce[currIndex++] = bitOffset; - - number = decodeBlackCodeWord(); - if (number > w - bitOffset) { - number = w - bitOffset; - } - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - cce[currIndex++] = bitOffset; - } else { - // First a black run and then a white run follows - number = decodeBlackCodeWord(); - if (number > w - bitOffset) { - number = w - bitOffset; - } - setToBlack(buffer, lineOffset, bitOffset, number); - bitOffset += number; - cce[currIndex++] = bitOffset; - - number = decodeWhiteCodeWord(); - bitOffset += number; - cce[currIndex++] = bitOffset; - } - - a0 = bitOffset; - } else if (code <= 8) { // Vertical - a1 = b1 + (code - 5); - cce[currIndex++] = a1; - - // We write the current color till a1 - 1 pos, - // since a1 is where the next color starts - if (!isWhite) { - if (a1 > w) { - a1 = w; - } - setToBlack(buffer, lineOffset, bitOffset, a1 - - bitOffset); - } - bitOffset = a0 = a1; - isWhite = !isWhite; - - updatePointer(7 - bits); - } else if (code == 11) { - if (nextLesserThan8Bits(3) != 7) { - throw new RuntimeException( - "Invalid code encountered while decoding 2D group 4 compressed data."); //$NON-NLS-1$ - } - - int zeros = 0; - boolean exit = false; - - while (!exit) { - while (nextLesserThan8Bits(1) != 1) { - zeros++; - } - - if (zeros > 5) { - // Exit code - - // Zeros before exit code - zeros = zeros - 6; - - if (!isWhite && (zeros > 0)) { - cce[currIndex++] = bitOffset; - } - - // Zeros before the exit code - bitOffset += zeros; - if (zeros > 0) { - // Some zeros have been written - isWhite = true; - } - - // Read in the bit which specifies the color of - // the following run - if (nextLesserThan8Bits(1) == 0) { - if (!isWhite) { - cce[currIndex++] = bitOffset; - } - isWhite = true; - } else { - if (isWhite) { - cce[currIndex++] = bitOffset; - } - isWhite = false; - } - - exit = true; - } - - if (zeros == 5) { - if (!isWhite) { - cce[currIndex++] = bitOffset; - } - bitOffset += zeros; - - // Last thing written was white - isWhite = true; - } else { - bitOffset += zeros; - - cce[currIndex++] = bitOffset; - setToBlack(buffer, lineOffset, bitOffset, 1); - ++bitOffset; - - // Last thing written was black - isWhite = false; - } - } - } else { - // break line - seems to be a common failure - // unread - updatePointer(7 - bits); - // and mark lines as complete - bitOffset = w; - // throw new RuntimeException( - // "Invalid code encountered while decoding 2D group 4 - // compressed data."); //$NON-NLS-1$ - } - } - - align(); - - // Add the changing element beyond the current scanline for the - // other color too - // make sure that the index does not exceed the bounds of the array - if (currIndex <= w) { - cce[currIndex++] = bitOffset; - } - - // Number of changing elements in this scanline. - changingElemSize = currIndex; - - lineOffset += scanlineStride; - } - } - - // Returns run length - private int decodeWhiteCodeWord() { - int current; - int entry; - int bits; - int isT; - int twoBits; - int code = -1; - int runLength = 0; - boolean isWhite = true; - - while (isWhite) { - current = nextNBits(10); - entry = white[current]; - - // Get the 3 fields from the entry - isT = entry & 0x0001; - bits = (entry >>> 1) & 0x0f; - - if (bits == 12) { // Additional Make up code - // Get the next 2 bits - twoBits = nextLesserThan8Bits(2); - // Consolidate the 2 new bits and last 2 bits into 4 bits - current = ((current << 2) & 0x000c) | twoBits; - entry = additionalMakeup[current]; - bits = (entry >>> 1) & 0x07; // 3 bits 0000 0111 - code = (entry >>> 4) & 0x0fff; // 12 bits - runLength += code; - updatePointer(4 - bits); - } else if (bits == 0) { // ERROR - throw new RuntimeException("Invalid code encountered."); //$NON-NLS-1$ - } else if (bits == 15) { // EOL - throw new RuntimeException( - "EOL code word encountered in White run."); //$NON-NLS-1$ - } else { - // 11 bits - 0000 0111 1111 1111 = 0x07ff - code = (entry >>> 5) & 0x07ff; - runLength += code; - updatePointer(10 - bits); - if (isT == 0) { - isWhite = false; - } - } - } - - return runLength; - } - - private void getNextChangingElement(int a0, boolean isWhite, int[] ret) { - // Local copies of instance variables - int[] pce = this.prevChangingElems; - int ces = this.changingElemSize; - - // If the previous match was at an odd element, we still - // have to search the preceeding element. - // int start = lastChangingElement & ~0x1; - int start = (lastChangingElement > 0) ? (lastChangingElement - 1) : 0; - if (isWhite) { - start &= ~0x1; // Search even numbered elements - } else { - start |= 0x1; // Search odd numbered elements - } - - ret[0] = w; - ret[1] = w; - - int i = start; - for (; i < ces; i += 2) { - int temp = pce[i]; - if (temp > a0) { - lastChangingElement = i; - ret[0] = temp; - break; - } - } - - if ((i + 1) < ces) { - ret[1] = pce[i + 1]; - } - } - - public boolean isAlign() { - return align; - } - - public boolean isFillBits() { - return fillBits; - } - - private int nextLesserThan8Bits(int bitsToGet) { - byte b; - byte next; - int l = data.length - 1; - int bp = this.bytePointer; - - if (fillOrder == 1) { - b = data[bp]; - if (bp == l) { - next = 0x00; - } else { - next = data[bp + 1]; - } - } else if (fillOrder == 2) { - b = flipTable[data[bp] & 0xff]; - if (bp == l) { - next = 0x00; - } else { - next = flipTable[data[bp + 1] & 0xff]; - } - } else { - throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ - } - - int bitsLeft = 8 - bitPointer; - int bitsFromNextByte = bitsToGet - bitsLeft; - - int shift = bitsLeft - bitsToGet; - int i1; - int i2; - if (shift >= 0) { - i1 = (b & table1[bitsLeft]) >>> shift; - bitPointer += bitsToGet; - if (bitPointer == 8) { - bitPointer = 0; - bytePointer++; - } - } else { - i1 = (b & table1[bitsLeft]) << (-shift); - i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); - - i1 |= i2; - bytePointer++; - bitPointer = bitsFromNextByte; - } - - return i1; - } - - private int nextNBits(int bitsToGet) { - byte b; - byte next; - byte next2next; - int l = data.length - 1; - int bp = this.bytePointer; - - if (fillOrder == 1) { - b = data[bp]; - - if (bp == l) { - next = 0x00; - next2next = 0x00; - } else if ((bp + 1) == l) { - next = data[bp + 1]; - next2next = 0x00; - } else { - next = data[bp + 1]; - next2next = data[bp + 2]; - } - } else if (fillOrder == 2) { - b = flipTable[data[bp] & 0xff]; - - if (bp == l) { - next = 0x00; - next2next = 0x00; - } else if ((bp + 1) == l) { - next = flipTable[data[bp + 1] & 0xff]; - next2next = 0x00; - } else { - next = flipTable[data[bp + 1] & 0xff]; - next2next = flipTable[data[bp + 2] & 0xff]; - } - } else { - throw new RuntimeException("tag must be either 1 or 2."); //$NON-NLS-1$ - } - - int bitsLeft = 8 - bitPointer; - int bitsFromNextByte = bitsToGet - bitsLeft; - int bitsFromNext2NextByte = 0; - if (bitsFromNextByte > 8) { - bitsFromNext2NextByte = bitsFromNextByte - 8; - bitsFromNextByte = 8; - } - - bytePointer++; - - int i1 = (b & table1[bitsLeft]) << (bitsToGet - bitsLeft); - int i2 = (next & table2[bitsFromNextByte]) >>> (8 - bitsFromNextByte); - - int i3 = 0; - if (bitsFromNext2NextByte != 0) { - i2 <<= bitsFromNext2NextByte; - i3 = (next2next & table2[bitsFromNext2NextByte]) >>> (8 - bitsFromNext2NextByte); - i2 |= i3; - bytePointer++; - bitPointer = bitsFromNext2NextByte; - } else { - if (bitsFromNextByte == 8) { - bitPointer = 0; - bytePointer++; - } else { - bitPointer = bitsFromNextByte; - } - } - - int i = i1 | i2; - return i; - } - - private int readEOL(boolean isFirstEOL) { - // Seek to the next EOL. - if (!seekEOL()) { - throw new RuntimeException("EOL not found"); - } - - if (!fillBits) { - int next12Bits = nextNBits(12); - if (isFirstEOL && (next12Bits == 0)) { - // Might have the case of EOL padding being used even - // though it was not flagged. - // This was observed to be the case in TIFFs produced - // by a well known vendor who shall remain nameless. - if (nextNBits(4) == 1) { - // EOL must be padded: reset the fillBits flag. - fillBits = true; - return 1; - } - } - if (next12Bits != 1) { - throw new RuntimeException( - "Scanline must begin with EOL code word."); //$NON-NLS-1$ - } - } else { - // First EOL code word xxxx 0000 0000 0001 will occur - // As many fill bits will be present as required to make - // the EOL code of 12 bits end on a byte boundary. - int bitsLeft = 8 - bitPointer; - - if (nextNBits(bitsLeft) != 0) { - throw new RuntimeException( - "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ - } - - // If the number of bitsLeft is less than 8, then to have a 12 - // bit EOL sequence, two more bytes are certainly going to be - // required. The first of them has to be all zeros, so ensure - // that. - if (bitsLeft < 4) { - if (nextNBits(8) != 0) { - throw new RuntimeException( - "All fill bits preceding EOL code must be 0."); //$NON-NLS-1$ - } - } - - // - // Some encoders under Group 3 Fax compression 1D writes TIFF - // files without the fill bits, but say otherwise. - // Need to check for this here. - // - int next8 = nextNBits(8); - - if (isFirstEOL && (next8 & 0xf0) == 0x10) { - // - // Fill bits are not actually used despite what the flag - // says. So switch fillBits off and then rewind so that - // only 12 bits have effectively been read. - // - fillBits = false; - updatePointer(4); - } else { - // - // This is the normal case. - // There might be a random number of fill bytes with 0s, so - // loop till the EOL of 0000 0001 is found, as long as all - // the bytes preceding it are 0's. - // - while (next8 != 1) { - // If not all zeros - if (next8 != 0) { - throw new RuntimeException("0 bits expected before EOL"); - } - next8 = nextNBits(8); - } - } - } - // The next one bit signifies 1D/2D encoding of next line. - return nextLesserThan8Bits(1); - } - - // Seeks to the next EOL in the compressed bitstream. - // Returns 'true' if and only if an EOL is found; if 'false' - // is returned it may be inferred that the EOF was reached first. - private boolean seekEOL() { - // Set maximum and current bit index into the compressed data. - int bitIndexMax = data.length * 8 - 1; - int bitIndex = bytePointer * 8 + bitPointer; - - // Loop while at least 12 bits are available. - while (bitIndex <= bitIndexMax - 12) { - // Get the next 12 bits. - int next12Bits = nextNBits(12); - bitIndex += 12; - - // Loop while the 12 bits are not unity, i.e., while the EOL - // has not been reached, and there is at least one bit left. - while (next12Bits != 1 && bitIndex < bitIndexMax) { - next12Bits = ((next12Bits & 0x000007ff) << 1) - | (nextLesserThan8Bits(1) & 0x00000001); - bitIndex++; - } - - // If EOL reached, rewind the pointers and return 'true'. - if (next12Bits == 1) { - updatePointer(12); - return true; - } - } - - // EOL not found: return 'false'. - return false; - } - - public void setAlign(boolean align) { - this.align = align; - } - - public void setFillBits(boolean fillBits) { - this.fillBits = fillBits; - } - - private void setToBlack(byte[] buffer, int lineOffset, int bitOffset, - int numBits) { - int bitNum = (8 * lineOffset) + bitOffset; - int lastBit = bitNum + numBits; - - int byteNum = bitNum >> 3; - - // Handle bits in first byte - int shift = bitNum & 0x7; - if (shift > 0) { - int maskVal = 1 << (7 - shift); - byte val = buffer[byteNum]; - while ((maskVal > 0) && (bitNum < lastBit)) { - val |= maskVal; - maskVal >>= 1; - ++bitNum; - } - buffer[byteNum] = val; - } - - // Fill in 8 bits at a time - byteNum = bitNum >> 3; - while (bitNum < (lastBit - 7)) { - buffer[byteNum++] = (byte) 255; - bitNum += 8; - } - - // Fill in remaining bits - while (bitNum < lastBit) { - byteNum = bitNum >> 3; - buffer[byteNum] |= (1 << (7 - (bitNum & 0x7))); - ++bitNum; - } - } - - // Move pointer backwards by given amount of bits - private void updatePointer(int bitsToMoveBack) { - if (bitsToMoveBack > 8) { - bytePointer -= bitsToMoveBack / 8; - bitsToMoveBack %= 8; - } - - int i = bitPointer - bitsToMoveBack; - - if (i < 0) { - bytePointer--; - bitPointer = 8 + i; - } else { - bitPointer = i; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/ChunkingInputStream.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/ChunkingInputStream.java deleted file mode 100644 index aca5c3143f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/ChunkingInputStream.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.filters; - -import java.io.IOException; -import java.io.InputStream; - -/** - * Most of the filters have to read in a chunk of data from their input stream, - * and do some processing on it, before they can make it available to others - * - * @author Mark Collette - * @since 2.0 - */ -public abstract class ChunkingInputStream extends InputStream { - protected InputStream in; - protected byte[] buffer; - private int bufferPosition; - private int bufferAvailable; - - public ChunkingInputStream() { - in = null; - buffer = null; - bufferPosition = 0; - bufferAvailable = 0; - } - - protected void setInputStream(InputStream input) { - in = input; - } - - protected void setBufferSize(int size) { - buffer = new byte[size]; - } - - /** - * For some reason, when reading from InflaterInputStream, if we ask to - * fill a buffer, it will instead only give us a chunk at a time, - * even though more data is available, and buffer.length has bee requested - * - * @throws IOException - */ - protected int fillBufferFromInputStream() throws IOException { - return fillBufferFromInputStream(0, buffer.length); - } - - protected int fillBufferFromInputStream(int offset, int length) throws IOException { - int read = 0; - int mayRead = in.available(); - int currRead; - try { - while (mayRead >= 0 && read < length) { - currRead = in.read(buffer, offset + read, length - read); - if (currRead < 0 && read == 0) - return currRead; - if (currRead <= 0) - break; - read += currRead; - } - } catch (IOException e) { - // catch the rare and elusive zlib EOF error and keep going - } - return read; - } - - /** - * This is only called if bufferAvailable is 0. - * Implementations should read in more data, and return how many bytes are now available - */ - protected abstract int fillInternalBuffer() throws IOException; - - - private int ensureDataAvailable() throws IOException { - if (bufferAvailable > 0) - return bufferAvailable; - bufferPosition = 0; - bufferAvailable = 0; - int avail = fillInternalBuffer(); - if (avail > 0) - bufferAvailable = avail; - return bufferAvailable; - } - - - // - // InputStream overrides - // - - public boolean markSupported() { - return false; - } - - public void mark(int readlimit) { - } - - public void reset() throws IOException { - } - - public int read() throws IOException { - int avail = ensureDataAvailable(); - if (avail <= 0) - return -1; - byte b = buffer[bufferPosition]; - bufferPosition++; - bufferAvailable--; - return (((int) b) & 0xFF); - } - - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - public int read(byte[] b, int off, int length) throws IOException { - int read = 0; - while (read < length) { - int avail = ensureDataAvailable(); - if (avail <= 0) { - if (read > 0) - return read; - else - return -1; - } - - int toRead = Math.min(length - read, avail); - int srcIdx = bufferPosition; - int dstIdx = off + read; - System.arraycopy(buffer, srcIdx, b, dstIdx, toRead); - bufferPosition += toRead; - bufferAvailable -= toRead; - read += toRead; - } - return read; - } - - public long skip(long n) throws IOException { - long skipped = 0L; - while (skipped < n) { - int avail = ensureDataAvailable(); - if (avail <= 0) { - if (skipped > 0L) - return skipped; - else - return -1; - } - - long toSkip = Math.min(n - skipped, avail); - bufferPosition += toSkip; - bufferAvailable -= toSkip; - skipped += toSkip; - } - return skipped; - } - - public int available() throws IOException { - return bufferAvailable; - } - - public void close() throws IOException { - if (in != null) { - in.close(); - in = null; - } - } - - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(super.toString()); - sb.append(": "); - if (in == null) - sb.append("null"); - else - sb.append(in.toString()); - return sb.toString(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/FlateDecode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/FlateDecode.java deleted file mode 100644 index dfbd10a3d9..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/FlateDecode.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.filters; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.zip.InflaterInputStream; - -/** - * @author Mark Collette - * @since 2.0 - */ - -public class FlateDecode extends ChunkingInputStream { - - - private static int DEFAULT_BUFFER_SIZE; - - static { - DEFAULT_BUFFER_SIZE = Defs.sysPropertyInt("org.icepdf.core.flateDecode.bufferSize", - 16384); - } - - public static final Name DECODE_PARMS_VALUE = new Name("DecodeParms"); - public static final Name PREDICTOR_VALUE = new Name("Predictor"); - public static final Name WIDTH_VALUE = new Name("Width"); - public static final Name COLUMNS_VALUE = new Name("Columns"); - public static final Name COLORS_VALUE = new Name("Colors"); - public static final Name BITS_PER_COMPONENT_VALUE = new Name("BitsPerComponent"); - - - private InputStream originalInputKeptSolelyForDebugging; - private int width; - private int numComponents; - private int bitsPerComponent; - private int bpp = 1; // From RFC 2083 (PNG), it's bytes per pixel, rounded up to 1 - private int predictor; - - - public FlateDecode(Library library, HashMap props, InputStream input) { - super(); - originalInputKeptSolelyForDebugging = input; - width = 0; - numComponents = 0; - bitsPerComponent = 0; - bpp = 1; - - int intermediateBufferSize = DEFAULT_BUFFER_SIZE; - - // get decode parameters from stream properties - HashMap decodeParmsDictionary = library.getDictionary(props, DECODE_PARMS_VALUE); - predictor = library.getInt(decodeParmsDictionary, PREDICTOR_VALUE); - if (predictor != PredictorDecode.PREDICTOR_NONE && - predictor != PredictorDecode.PREDICTOR_TIFF_2 && - predictor != PredictorDecode.PREDICTOR_PNG_NONE && - predictor != PredictorDecode.PREDICTOR_PNG_SUB && - predictor != PredictorDecode.PREDICTOR_PNG_UP && - predictor != PredictorDecode.PREDICTOR_PNG_AVG && - predictor != PredictorDecode.PREDICTOR_PNG_PAETH && - predictor != PredictorDecode.PREDICTOR_PNG_OPTIMUM) { - predictor = PredictorDecode.PREDICTOR_NONE; - } - if (predictor != PredictorDecode.PREDICTOR_NONE) { - Number widthNumber = library.getNumber(props, WIDTH_VALUE); - if (widthNumber != null) - width = widthNumber.intValue(); - else - width = library.getInt(decodeParmsDictionary, COLUMNS_VALUE); - - // Since DecodeParms.BitsPerComponent has a default value, I don't think we'd - // look at entries.ColorSpace to know the number of components. But, here's the info: - // /ColorSpace /DeviceGray: 1 comp, /DeviceRBG: 3 comps, /DeviceCMYK: 4 comps, /DeviceN: N comps - // I'm going to extend that to mean I won't look at entries.BitsPerComponent either - - numComponents = 1; // DecodeParms.Colors: 1,2,3,4 Default=1 - bitsPerComponent = 8; // DecodeParms.BitsPerComponent: 1,2,4,8,16 Default=8 - - Object numComponentsDecodeParmsObj = library.getObject(decodeParmsDictionary, COLORS_VALUE); - if (numComponentsDecodeParmsObj instanceof Number) { - numComponents = ((Number) numComponentsDecodeParmsObj).intValue(); - } - Object bitsPerComponentDecodeParmsObj = library.getObject(decodeParmsDictionary, BITS_PER_COMPONENT_VALUE); - if (bitsPerComponentDecodeParmsObj instanceof Number) { - bitsPerComponent = ((Number) bitsPerComponentDecodeParmsObj).intValue(); - } - - bpp = Math.max(1, Utils.numBytesToHoldBits(numComponents * bitsPerComponent)); - - // Make buffer exactly large enough for one row of data (without predictor) - intermediateBufferSize = - Utils.numBytesToHoldBits(width * numComponents * bitsPerComponent); - } - - // Create the inflater input stream which will do the encoding - setInputStream(new InflaterInputStream(input)); - setBufferSize(intermediateBufferSize); - } - - protected int fillInternalBuffer() throws IOException { - - if (predictor == PredictorDecode.PREDICTOR_NONE) { - int numRead = fillBufferFromInputStream(); - if (numRead <= 0) - return -1; - return numRead; - } else if (predictor == PredictorDecode.PREDICTOR_TIFF_2) { - int numRead = fillBufferFromInputStream(); - if (numRead <= 0) - return -1; - if (bitsPerComponent == 8) { - for (int i = 0; i < numRead; i++) { - int prevIndex = i - numComponents; - if (prevIndex >= 0) { - buffer[i] += buffer[prevIndex]; - } - } - } - return numRead; - } - // Predictor decode is handle by the PredictorDecode class as it's also - // used by LZW Decode. So all we need to do is fill the buffer. - else if (predictor >= PredictorDecode.PREDICTOR_PNG_NONE && - predictor <= PredictorDecode.PREDICTOR_PNG_OPTIMUM) { - int numRead = fillBufferFromInputStream(); - if (numRead <= 0) return -1; - return numRead; - } - - return -1; - } - - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(super.toString()); - sb.append(", orig: "); - if (originalInputKeptSolelyForDebugging == null) - sb.append("null"); - else - sb.append(originalInputKeptSolelyForDebugging.toString()); - return sb.toString(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/G4State.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/G4State.java deleted file mode 100644 index f201076a73..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/G4State.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.filters; - -/** - * This is a utility class that aids the decoding of CCITT 4 2D encoded data. - * CCITTFax is the parent class that uses this class to keep track of the - * locations of the B & W bit locations with in the stream - */ -class G4State { - int[] ref; - int[] cur; - boolean white = true; // colour reference - int a0; // The reference element on the coding line - int b1; // The next changing element on the reference line to the right of a0 and of opppsite color of a0 - int refIndex; // the previous scan line - int curIndex; // the current scan line - int runLength; - int width; - int longrun; - - /** - * Greate a new instance of a G4State. - * - * @param w width of the line being looked at. - */ - G4State(int w) { - width = w; - ref = new int[width + 1]; - cur = new int[width + 1]; - a0 = 0; - b1 = width; - ref[0] = width; - ref[1] = 0; - runLength = 0; - longrun = 0; - refIndex = 1; - curIndex = 0; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/LZWDecode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/LZWDecode.java deleted file mode 100644 index 250a100ac6..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/LZWDecode.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.filters; - -import org.icepdf.core.io.BitStream; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Stack; - -/** - * @author Mark Collette - * @since 2.0 - */ -public class LZWDecode extends ChunkingInputStream { - - public static final Name DECODEPARMS_KEY = new Name("DecodeParms"); - public static final Name EARLYCHANGE_KEY = new Name("EarlyChange"); - - - private BitStream inb; - private int earlyChange; - private int code; - private int old_code; - private boolean firstTime; - - private int code_len; - private int last_code; - private Code[] codes; - - - public LZWDecode(BitStream inb, Library library, HashMap entries) { - this.inb = inb; - - this.earlyChange = 1; // Default value - HashMap decodeParmsDictionary = library.getDictionary(entries, DECODEPARMS_KEY); - if (decodeParmsDictionary != null) { - Number earlyChangeNumber = library.getNumber(decodeParmsDictionary, EARLYCHANGE_KEY); - if (earlyChangeNumber != null) { - this.earlyChange = earlyChangeNumber.intValue(); - } - } - - code = 0; - old_code = 0; - firstTime = true; - initCodeTable(); - setBufferSize(4096); - } - - protected int fillInternalBuffer() throws IOException { - int numRead = 0; - // start decompression, haven't tried to optimized this one yet for - // speed or for memory. - - if (firstTime) { - firstTime = false; - old_code = code = inb.getBits(code_len); - } else if (inb.atEndOfFile()) - return -1; - - do { - if (code == 256) { - initCodeTable(); - } else if (code == 257) { - break; - } else { - if (codes[code] != null) { - Stack stack = new Stack(); - codes[code].getString(stack); - Code c = (Code) stack.pop(); - addToBuffer(c.c, numRead); - numRead++; - //System.err.println((char)c.c); - byte first = c.c; - while (!stack.empty()) { - c = (Code) stack.pop(); - addToBuffer(c.c, numRead); - numRead++; - //System.err.println((char)c.c); - } - // while (codes[last_code]!=null) last_code++; - codes[last_code++] = new Code(codes[old_code], first); - } else { - //System.err.println("MISS: "+last_code+" "+code); - if (code != last_code) - throw new RuntimeException("LZWDecode failure"); - Stack stack = new Stack(); - codes[old_code].getString(stack); - Code c = (Code) stack.pop(); - addToBuffer(c.c, numRead); - numRead++; - //System.err.println((char)c.c); - byte first = c.c; - while (!stack.empty()) { - c = (Code) stack.pop(); - addToBuffer(c.c, numRead); - numRead++; - //System.err.println((char)c.c); - } - addToBuffer(first, numRead); - numRead++; - codes[code] = new Code(codes[old_code], first); - last_code++; - } - } - if (code_len < 12 && last_code == (1 << code_len) - earlyChange) { - //System.err.println(last_code+" "+code_len); - code_len++; - } - old_code = code; - code = inb.getBits(code_len); - - if (inb.atEndOfFile()) - break; - } while (numRead < buffer.length); - - return numRead; - } - - private void initCodeTable() { - code_len = 9; - last_code = 257; - codes = new Code[4096]; - for (int i = 0; i < 256; i++) - codes[i] = new Code(null, (byte) i); - } - - private void addToBuffer(byte b, int offset) { - if (offset >= buffer.length) { // Should never happen - byte[] bufferNew = new byte[buffer.length * 2]; - System.arraycopy(buffer, 0, bufferNew, 0, buffer.length); - buffer = bufferNew; - } - buffer[offset] = b; - } - - - public void close() throws IOException { - super.close(); - - if (inb != null) { - inb.close(); - inb = null; - } - } - - - /** - * Utility class for decode methods. - */ - private static class Code { - Code prefix; - byte c; - - Code(Code p, byte cc) { - prefix = p; - c = cc; - } - - @SuppressWarnings("unchecked") - void getString(Stack s) { - s.push(this); - if (prefix != null) - prefix.getString(s); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/PredictorDecode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/PredictorDecode.java deleted file mode 100644 index 7dfde344ba..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/PredictorDecode.java +++ /dev/null @@ -1,249 +0,0 @@ -package org.icepdf.core.pobjects.filters; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; - -/** - * Predictor decoder for LZW and Flate data streams. Uses the same streaming - * as our other Filters but simplifies how the bytes are read in as we treat - * the parent (LZW or Flate) stream as a regular ChunkingInputStream. - * - * @since 5.0.6 - */ -public class PredictorDecode extends ChunkingInputStream { - - /** - * No predictor function is used - */ - protected static final int PREDICTOR_NONE = 1; - - /** - * For every row, each component is derived from corresponding component in entry to left - */ - protected static final int PREDICTOR_TIFF_2 = 2; - - /** - * For current row, PNG predictor to do nothing - */ - protected static final int PREDICTOR_PNG_NONE = 10; - - /** - * For current row, derive each byte from byte left-by-bytesPerPixel - */ - protected static final int PREDICTOR_PNG_SUB = 11; - - /** - * For current row, derive each byte from byte above - */ - protected static final int PREDICTOR_PNG_UP = 12; - - /** - * For current row, derive each byte from average of byte left-by-bytesPerPixel and byte above - */ - protected static final int PREDICTOR_PNG_AVG = 13; - - /** - * For current row, derive each byte from non-linear function of byte left-by-bytesPerPixel and byte above and byte left-by-bytesPerPixel of above - */ - protected static final int PREDICTOR_PNG_PAETH = 14; - - /** - * When given in DecodeParms dict, in stream dict, means first byte of each row is row's predictor - */ - protected static final int PREDICTOR_PNG_OPTIMUM = 15; - - protected static final Name DECODE_PARMS_VALUE = new Name("DecodeParms"); - protected static final Name PREDICTOR_VALUE = new Name("Predictor"); - protected static final Name WIDTH_VALUE = new Name("Width"); - protected static final Name COLUMNS_VALUE = new Name("Columns"); - protected static final Name COLORS_VALUE = new Name("Colors"); - protected static final Name BITS_PER_COMPONENT_VALUE = new Name("BitsPerComponent"); - protected static final Name EARLY_CHANGE_VALUE = new Name("EarlyChange"); - - protected int predictor; - protected int numComponents; - protected int bitsPerComponent; - protected int width; - protected int bytesPerPixel = 1;// From RFC 2083 (PNG), it's bytes per pixel, rounded up to 1 - - // reference to previous buffer - protected byte[] aboveBuffer; - - public PredictorDecode(InputStream input, Library library, HashMap entries) { - super(); - // get decode parameters from stream properties - HashMap decodeParmsDictionary = library.getDictionary(entries, DECODE_PARMS_VALUE); - predictor = library.getInt(decodeParmsDictionary, PREDICTOR_VALUE); - - Number widthNumber = library.getNumber(entries, WIDTH_VALUE); - if (widthNumber != null) { - width = widthNumber.intValue(); - } else { - width = library.getInt(decodeParmsDictionary, COLUMNS_VALUE); - } - // Since DecodeParms.BitsPerComponent has a default value, I don't think we'd - // look at entries.ColorSpace to know the number of components. But, here's the info: - // /ColorSpace /DeviceGray: 1 comp, /DeviceRBG: 3 comps, /DeviceCMYK: 4 comps, /DeviceN: N comps - // I'm going to extend that to mean I won't look at entries.BitsPerComponent either - - numComponents = 1; // DecodeParms.Colors: 1,2,3,4 Default=1 - bitsPerComponent = 8; // DecodeParms.BitsPerComponent: 1,2,4,8,16 Default=8 - - Object numComponentsDecodeParmsObj = library.getObject(decodeParmsDictionary, COLORS_VALUE); - if (numComponentsDecodeParmsObj instanceof Number) { - numComponents = ((Number) numComponentsDecodeParmsObj).intValue(); - } - Object bitsPerComponentDecodeParmsObj = library.getObject(decodeParmsDictionary, BITS_PER_COMPONENT_VALUE); - if (bitsPerComponentDecodeParmsObj instanceof Number) { - bitsPerComponent = ((Number) bitsPerComponentDecodeParmsObj).intValue(); - } - bytesPerPixel = Math.max(1, Utils.numBytesToHoldBits(numComponents * bitsPerComponent)); - - // Make buffer exactly large enough for one row of data (without predictor) - int intermediateBufferSize = Utils.numBytesToHoldBits( - width * numComponents * bitsPerComponent); - - // last row of data above our current buffer - aboveBuffer = new byte[intermediateBufferSize]; - setBufferSize(intermediateBufferSize); - - setInputStream(input); - } - - @Override - protected int fillInternalBuffer() throws IOException { - byte[] temp = aboveBuffer; - aboveBuffer = buffer; - buffer = temp; - - int currPredictor; - int cp = in.read(); - if (cp < 0) return -1; - // I've seen code that conditionally updates currPredictor: - // if predictor == PREDICTOR_PNG_OPTIMUM - // currPredictor = cp + PREDICTOR_PNG_NONE - //if( predictor == PREDICTOR_PNG_OPTIMUM ) - currPredictor = cp + PREDICTOR_PNG_NONE; - - // fill the buffer - int numRead = fillBufferFromInputStream(); - if (numRead <= 0) return -1; - - // apply predictor logic - applyPredictor(numRead, currPredictor); - - return numRead; - } - - /** - * Apply predictor logic to buffer[] using aboveBuffer[] from previous pass. - * - * @param numRead number of bytes read in last pass. - * @param currPredictor predictor to apply to buffer data. - */ - protected void applyPredictor(int numRead, int currPredictor) { - // loop back over the buffer and update with predicted values. - for (int i = 0; i < numRead; i++) { - // For current row, PNG predictor to do nothing - if (currPredictor == PREDICTOR_PNG_NONE) { - break; // We could continue, but we'd do that numRead times - } - // For current row, derive each byte from byte left-by-bpp - else if (currPredictor == PREDICTOR_PNG_SUB) { - if ((i - bytesPerPixel) >= 0) { - buffer[i] += applyLeftPredictor(buffer, bytesPerPixel, i); - } - } - // For current row, derive each byte from byte above - else if (currPredictor == PREDICTOR_PNG_UP) { - if (aboveBuffer != null) { - buffer[i] += applyAbovePredictor(aboveBuffer, i); - } - } - // For current row, derive each byte from average of byte left-by-bpp and byte above - else if (currPredictor == PREDICTOR_PNG_AVG) { - // PNG AVG: output(x) = curr_line(x) + floor((curr_line(x-bpp)+above(x))/2) - // From RFC 2083 (PNG), sum with no overflow, using >= 9 bit arithmatic - int left = 0; - if ((i - bytesPerPixel) >= 0) { - left = applyLeftPredictor(buffer, bytesPerPixel, i); - } - int above = 0; - if (aboveBuffer != null) { - above = applyAbovePredictor(aboveBuffer, i); - } - int sum = left + above; - byte avg = (byte) ((sum >>> 1) & 0xFF); - buffer[i] += avg; - } - // For current row, derive each byte from non-linear function of - // byte left-by-bpp and byte above and byte left-by-bpp of above - else if (currPredictor == PREDICTOR_PNG_PAETH) { - // From RFC 2083 (PNG) - // PNG PAETH: output(x) = curr_line(x) + PaethPredictor(curr_line(x-bpp), above(x), above(x-bpp)) - // PaethPredictor(left, above, aboveLeft) - // p = left + above - aboveLeft - // pLeft = abs(p - left) - // pAbove = abs(p - above) - // pAboveLeft = abs(p - aboveLeft) - // if( pLeft <= pAbove && pLeft <= pAboveLeft ) return left - // if( pAbove <= pAboveLeft ) return above - // return aboveLeft - int left = 0; - if ((i - bytesPerPixel) >= 0) { - left = applyLeftPredictor(buffer, bytesPerPixel, i); - } - int above = 0; - if (aboveBuffer != null) { - above = applyAbovePredictor(aboveBuffer, i); - } - int aboveLeft = 0; - if ((i - bytesPerPixel) >= 0 && aboveBuffer != null) { - aboveLeft = applyAboveLeftPredictor(aboveBuffer, bytesPerPixel, i); - } - int p = left + above - aboveLeft; - int pLeft = Math.abs(p - left); - int pAbove = Math.abs(p - above); - int pAboveLeft = Math.abs(p - aboveLeft); - int paeth = ((pLeft <= pAbove && pLeft <= pAboveLeft) - ? left - : ((pAbove <= pAboveLeft) - ? above - : aboveLeft)); - buffer[i] += ((byte) (paeth & 0xFF)); - } - } - } - - private static int applyLeftPredictor(byte[] buffer, int bytesPerPixel, int i) { - return (((int) buffer[(i - bytesPerPixel)]) & 0xFF); - } - - private static int applyAbovePredictor(byte[] aboveBuffer, int i) { - return (((int) aboveBuffer[i]) & 0xFF); - } - - private static int applyAboveLeftPredictor(byte[] aboveBuffer, int bytesPerPixel, int i) { - return (((int) aboveBuffer[i - bytesPerPixel]) & 0xFF); - } - - public static boolean isPredictor(Library library, HashMap entries) { - HashMap decodeParmsDictionary = library.getDictionary(entries, DECODE_PARMS_VALUE); - if (decodeParmsDictionary == null) { - return false; - } - int predictor = library.getInt(decodeParmsDictionary, PREDICTOR_VALUE); - if (predictor != PREDICTOR_PNG_NONE && predictor != PREDICTOR_PNG_SUB && - predictor != PREDICTOR_PNG_UP && predictor != PREDICTOR_PNG_AVG && - predictor != PREDICTOR_PNG_PAETH && predictor != PREDICTOR_PNG_OPTIMUM) { - return false; - } - return true; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/RunLengthDecode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/RunLengthDecode.java deleted file mode 100644 index 988161df3d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/filters/RunLengthDecode.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.filters; - -import java.io.IOException; -import java.io.InputStream; - -/** - * @author Mark Collette - * @since 2.0 - */ -public class RunLengthDecode extends ChunkingInputStream { - public RunLengthDecode(InputStream input) { - super(); - - setInputStream(input); - setBufferSize(4096); - } - - protected int fillInternalBuffer() throws IOException { - int numRead = 0; - - while (numRead < (buffer.length - 260)) { // && i != 128) { - int i = in.read(); - if (i < 0) - break; - if (i < 128) { - numRead += fillBufferFromInputStream(numRead, i + 1); - } else { - int count = (257 - i); - int j = in.read(); - byte jj = (byte) (j & 0xFF); - for (int k = 0; k < count; k++) { - buffer[numRead++] = jj; - } - } - } - - if (numRead == 0) - return -1; - return numRead; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/AFM.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/AFM.java deleted file mode 100644 index e531504863..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/AFM.java +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts; - -import java.io.*; -import java.util.HashMap; -import java.util.StringTokenizer; -import java.util.logging.Level; -import java.util.logging.Logger; - - -/** - * This class parses and stores data on the 14 PostScript AFM files. - * - * @since 1.0 - */ -public class AFM { - - private static final Logger logger = - Logger.getLogger(AFM.class.toString()); - - public static final int COURIER = 0; - public static final int COURIER_BOLD = 1; - public static final int COURIER_OBLIQUE = 2; - public static final int COURIER_BOLD_OBLIQUE = 3; - public static final int HELVETICA = 4; - public static final int HELVETICA_BOLD = 5; - public static final int HELVETICA_OBLIQUE = 6; - public static final int HELVETICA_BOLD_OBLIQUE = 7; - public static final int TIMES_ROMAN = 8; - public static final int TIMES_BOLD = 9; - public static final int TIMES_ITALIC = 10; - public static final int TIMES_BOLD_ITALIC = 11; - public static final int ZAPF_DINGBATS = 12; - public static final int SYMBOL = 13; - - - public static String[] AFMnames = { - "Courier.afm", - "Courier-Bold.afm", - "Courier-Oblique.afm", - "Courier-BoldOblique.afm", - - "Helvetica.afm", - "Helvetica-Bold.afm", - "Helvetica-Oblique.afm", - "Helvetica-BoldOblique.afm", - - "Times-Roman.afm", - "Times-Bold.afm", - "Times-Italic.afm", - "Times-BoldItalic.afm", - - "ZapfDingbats.afm", - "Symbol.afm" - }; - /** - *

The value of the Flags entry in a font descriptor is an - * unsized 32-bit integer containg flags specifying various characteristics - * of the font.

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Bit PositionNameMeaning
1FixedPitchAll glyphs have the same width (as opposed to proportional or - * variable-pitch fonts, which have different widths).
2SerifGlyphs have serifs, which are short strokes drawn at an angle on - * the top and bottom of glyph stems. ( Sans serif fonts do not have serifs.)
3SymbolicFont contains glyphs outside the Adobe standard Latin character - * set. This flag and the Nonsymbolic flag cannot both be set or both be clear.
4ScriptGlyphs resemble cursive handwriting.
6NonsymbolicFont uses the Adobe standard Latin character set or a subset of it.
7ItalicGlyphs have dominant vertical strokes that are slanted.
17AllCapFont contains no lowercase letters; typically used for display - * purposes, such as for titles or headlines.
18SmallCapFont contains both uppercase and lowercase letters. The uppercase - * letters are similar to those in the regular version of the same - * typeface family. The glyphs for the lowercase letters have the same - * shapes as the corresponding uppercase letters, but they are sized - * and their proportions adjusted so that they have the same size and - * stroke weight as lowercase glyphs in the same typeface family.
19ForceBold
- * Bit Position name Meaning - */ - - private static int[] AFMFlags = { - 35, // 0x100011 "Courier.afm", - 35, // 0x100011 "Courier-Bold.afm", - 99, // 0x1100011 "Courier-Oblique.afm", - 99, // 0x1100011 "Courier-BoldOblique.afm", - // - 32, // 0x100000 "Helvetica.afm", - 32, // 0x100000 "Helvetica-Bold.afm", - 96, // 0x1100000 "Helvetica-Oblique.afm", - 96, // 0x1100000 "Helvetica-BoldOblique.afm", - // - 34, // 0x100010 "Times-Roman.afm", - 34, // 0x100010 "Times-Bold.afm", - 98, // 0x1100010 "Times-Italic.afm", - 98, // 0x1100010 "Times-BoldItalic.afm", - // - 4, // 0x100 "ZapfDingbats.afm", - 4 // 0x100 "Symbol.afm" - }; - - - public static final HashMap AFMs = new HashMap(14); - - - private String fontName; - private String familyName; - private String fullName; - private float[] widths = new float[255]; - private int[] fontBBox = new int[4]; - private float italicAngle = 0; - private float maxWidth = 0; - private int avgWidth = 0; - private int flags = 0; - - /** - * Reader and parse all the core 14 AFM font descriptors - */ - static { - try { - for (int i = 0; i < AFMnames.length; i++) { - AFM afm = AFM.loadFont("afm/" + AFMnames[i]); - if (afm != null) { - afm.setFlags(AFMFlags[i]); - AFMs.put(afm.fontName.toLowerCase(), afm); - } - } - } catch (Exception ex) { - logger.log(Level.WARNING, "Error load AFM CMap files", ex); - } - } - - /** - * Creates a new AFM file based on the - * - * @param resource name of desired resource. - * @throws IOException if the specified resource could not be found or o - * pened. - */ - public static AFM loadFont(String resource) throws IOException { - InputStream in = AFM.class.getResourceAsStream(resource); - if (in != null) { - AFM afm = new AFM(); - afm.parse(new InputStreamReader(in)); - return afm; - } else { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Could not find AFM File: " + resource); - } - return null; - } - } - - private AFM() { - } - - public String getFontName() { - return fontName; - } - - public String getFullName() { - return fullName; - } - - public String getFamilyName() { - return familyName; - } - - public int[] getFontBBox() { - return fontBBox; - } - - public float getItalicAngle() { - return italicAngle; - } - - public float[] getWidths() { - return widths; - } - - public float getMaxWidth() { - return maxWidth; - } - - public int getAvgWidth() { - return avgWidth; - } - - public int getFlags() { - return flags; - } - - private void setFlags(int value) { - flags = value; - } - - /** - * Utility class for parsing the contents of the care AFM files. - * - * @param i stream to read - * @throws java.io.IOException if the reader can not find the specified - * afm file. - */ - private void parse(Reader i) throws IOException { - BufferedReader r = new BufferedReader(i); - String s; - int count = 0; - avgWidth = 0; - maxWidth = 0; - while ((s = r.readLine()) != null) { - StringTokenizer st = new StringTokenizer(s, " ;\t\n\r\f"); - String s1 = st.nextToken(); - if (s1.equalsIgnoreCase("FontName")) { - fontName = st.nextToken(); - } else if (s1.equalsIgnoreCase("FullName")) { - fullName = st.nextToken(); - } else if (s1.equalsIgnoreCase("FamilyName")) { - familyName = st.nextToken(); - } else if (s1.equalsIgnoreCase("FontBBox")) { - fontBBox[0] = new Integer(st.nextToken()); - fontBBox[1] = new Integer(st.nextToken()); - fontBBox[2] = new Integer(st.nextToken()); - fontBBox[3] = new Integer(st.nextToken()); - } else if (s1.equalsIgnoreCase("ItalicAngle")) { - italicAngle = new Float(st.nextToken()); - } - // font width data - else if (s1.equalsIgnoreCase("C")) { - int c = Integer.parseInt(st.nextToken()); - while (!st.nextToken().equals("WX")) ; - float wx = Integer.parseInt(st.nextToken()) / 1000f; - if (c >= 0 && c < 255) { - widths[count] = wx; - // update max - if (wx > maxWidth) { - maxWidth = wx; - } - // update average - avgWidth += wx; - count++; - } - } - } - // finalized average - avgWidth = avgWidth / count; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/CMap.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/CMap.java deleted file mode 100644 index 0b813560c6..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/CMap.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts; - -import org.icepdf.core.pobjects.Name; - -/** - * CMap inteface. - * - * @since 3.0 - */ -public interface CMap { - - public static final Name TYPE = new Name("CMap"); - - /** - * Maps the character id to an underlying unicode value if available. - * - * @param ch character code to find unicode value of. - * @return unicode value of ch if available otherwise original ch is returned unaltered. - */ - public char toSelector(char ch); - - public char toSelector(char ch, boolean isCFF); - - /** - * Maps the character id to an underlying to unicode table. This method should - * be called when looking for a unicode value for a CID. This method differs - * slightly from #toSelector in that it can return at String rather then a - * single character code. - * - * @param ch character id to look for corresponding unicode values. - * @return unicode value of specified character code. - */ - public String toUnicode(char ch); - - /** - * Determines if the cid should be interpreted as a one or two byte character. - * Some CID fonts use the one byte notation but the two byte is the most - * common bar far. - * - * @return true if the cid should be considered as having a one byte length. - */ - public boolean isOneByte(); - - /** - * Determines if the cid should be interpreted as a one or two byte character. - * Some CID fonts use the one byte notation but the two byte is the most - * common bar far. - * - * @return true if the cid should be considered as having a two byte length. - */ - public boolean isTwoByte(); - - /** - * Determines if the cid should be interpreted as a one or two byte character. - * Some CID fonts use the one byte notation but the two byte is the most - * common bar far. A mixed byte string must be parsed differently as the font - * can be used to determine the number of bytes used for each character. - * - * @return true if the cid should be considered as having a mixed byte length. - */ - public boolean isMixedByte(); - - /** - * Utility method ot check if a CMap contain s any data, specifically usable toUnicode data. - * - * @return true if the mapping contains at least one entry. - */ - public boolean isEmptyMapping(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/Encoding.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/Encoding.java deleted file mode 100644 index 02a383d836..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/Encoding.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts; - -/** - * Encoding interface - * - * @since 3.0 - */ -public interface Encoding { - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/Font.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/Font.java deleted file mode 100644 index a273f481bb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/Font.java +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts; - - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - *

This class represents a PDF object which has a subtype value equal to "Font". - * The class does the necessary encoding and Cmap manipulation to allow the proper - * display of text that uses this font object.

- *

- *

This class is generally only used by the ContentParser for laying out - * text for display and for text extraction. There are two categories of PDF fonts: - * Simple and Composite.

- *

- *

Simple Fonts

- *

There are several types of simple font; all of which have the following - * properties:

- *
    - *
  • Glyphs in the font are selected by single-byte character codes obtained from a - * string that is shown by the text-showing operators. Logically, these codes - * index into a table of 256 glyphs; the mapping from codes to glyphs is called - * the font's encoding. Each font program has a built-in encoding. Under some - * circumstances, the encoding can be altered by means described in Section - * 5.5.5, "Character Encoding."
  • - *

    - *

  • Each glyph has a single set of metrics, including a horizontal displacement - * or width, as described in Section 5.1.3, "Glyph Positioning and Metrics." - * That is, simple fonts support only horizontal writing mode.
  • - *

    - *

  • Except for Type 3 fonts and certain standard Type 1 fonts, every font - * dictionary contains a subsidiary dictionary, the font descriptor, - * containing fontwide metrics and other attributes of the font; see Section - * 5.7, "Font Descriptors." Among those attributes is an optional font file - * stream containing the font program itself.
  • - *
- *

- *

Composite Fonts

- *

A composite font, also called Type0 font, is one whose glyphs are obtained - * from a font like object called a CIDFont. A composite font is represented by - * a font dictionary whose Subtype value is Type0. The Type 0 font is known as - * the root font, and its associated CID Font is called its descendant.

- * - * @since 1.0 - */ -public abstract class Font extends Dictionary { - - public static final Name TYPE = new Name("Font"); - - public static final Name NAME_KEY = new Name("Name"); - public static final Name BASEFONT_KEY = new Name("BaseFont"); - public static final Name ENCODING_KEY = new Name("Encoding"); - public static final Name FIRST_CHAR_KEY = new Name("FirstChar"); - public static final Name LAST_CHAR_KEY = new Name("LastChar"); - - /** - * All glyphs have the same width (as opposed to proportional or - * variable-pitch fonts, which have different widths). - */ - public static final int FONT_FLAG_FIXED_PITCH = 0x1; // bit 1 - - /** - * Glyphs have serifs, which are short strokes drawn at an angle on the top - * and bottom of glyph stems. (Sans serif fonts do not have serifs.) - */ - public static final int FONT_FLAG_SERIF = 0x2; // bit 2 - - /** - * Font contains glyphs outside the Adobe standard Latin character set. - * This flag and the Nonsymbolic flag shall not both be set or both be clear. - */ - public static final int FONT_FLAG_SYMBOLIC = 0x4; // bit 3 - - /** - * Glyphs resemble cursive handwriting. - */ - public static final int FONT_FLAG_SCRIPT = 0x8; // bit 4 - - /** - * Font uses the Adobe standard Latin character set or a subset of it. - */ - public static final int FONT_FLAG_NON_SYMBOLIC = 0x20; // bit 6 - - /** - * Glyphs have dominant vertical strokes that are slanted. - */ - public static final int FONT_FLAG_ITALIC = 0x40; // bit 7 - - /** - * Font contains no lowercase letters; typically used for display purposes, - * such as for titles or headlines. - */ - public static final int FONT_FLAG_ALL_CAP = 0x10000; // bit 17 - - /** - * Glyphs have dominant vertical strokes that are slanted. - */ - public static final int FONT_FLAG_SMALL_CAP = 0x20000; // bit 18 - - /** - * Font contains no lowercase letters; typically used for display purposes, - * such as for titles or headlines. - */ - public static final int FONT_FLAG_FORCE_BOLD = 0x40000; // bit 19 - - // Object name always "Font" - protected Name name; - - // The name of the object, Font - protected String basefont; - - // The font subtype, type 0, 1, 2 etc. - protected Name subtype; - - // the encoding name associated with font. - protected Name encoding; - - /** - *

Indicates that the font used to render this String object is in the - * Simple Font family and thus each glyph is represented by one byte.

- */ - public static final int SIMPLE_FORMAT = 1; - - /** - *

Indicates that the font used to render this String object is in the - * Composite Font family and thus each glyph is represented by at least - * one byte.

- */ - public static final int CID_FORMAT = 2; - - // supType Format, either simple or CID. - protected int subTypeFormat = SIMPLE_FORMAT; - - // The actual Java font that will be used to display the Glyphs - protected FontFile font; - - // The first character code defined in the font's Widths array. - protected int firstchar = 32; - protected int lastchar = 255; - - // Font Descriptor used - protected FontDescriptor fontDescriptor; - - // initiated flag - protected boolean inited; - - // AFM flag - protected boolean isAFMFont; - - // vertical writing flag; - protected boolean isVerticalWriting; - - // font substitution being used - protected boolean isFontSubstitution; - - // parent resource, needed by some type3 fonts to access resources. - protected Resources parentResource; - - /** - * Map named CMap to Unicode mapping. - */ - protected static final String[][] TO_UNICODE = { - // format: ... - // Chinese (Simplified) - {"GBpc-EUC-UCS2", "GBpc-EUC-H", "GBpc-EUC-V"}, - {"GBK-EUC-UCS2", "GBK-EUC-H", "GBK-EUC-V"}, - {"UniGB-UCS2-H", "GB-EUC-H", "GBT-EUC-H", "GBK2K-H", "GBKp-EUC-H"}, - {"UniGB-UCS2-V", "GB-EUC-V", "GBT-EUC-V", "GBK2K-V", "GBKp-EUC-V"}, - - // Chinese (Traditional) - {"B5pc-UCS2", "B5pc-H", "B5pc-V"}, - {"ETen-B5-UCS2", "ETen-B5-H", "ETen-B5-V", "ETenms-B5-H", "ETenms-B5-V"}, - {"UniCNS-UCS2-H", "HKscs-B5-H", "CNS-EUC-H"}, - {"UniCNS-UCS2-V", "HKscs-B5-V", "CNS-EUC-V"}, - - // Japanese - {"90pv-RKSJ-UCS2", "90pv-RKSJ-H", "83pv-RKSJ-H"}, - {"90ms-RKSJ-UCS2", "90ms-RKSJ-H", "90ms-RKSJ-V", "90msp-RKSJ-H", "90msp-RKSJ-V"}, - {"UniJIS-UCS2-H", "Ext-RKSJ-H", "H", "Add-RKSJ-H", "EUC-H"}, - {"UniJIS-UCS2-V", "Ext-RKSJ-V", "V", "Add-RKSJ-V", "EUC-V"}, - - // Korean - {"KSCms-UHC-UCS2", "KSCms-UHC-H", "KSCms-UHC-V", "KSCms-UHC-HW-H", "KSCms-UHC-HW-V"}, - {"KSCpc-EUC-UCS2", "KSCpc-EUC-H"}, - {"UniKS-UCS2-H", "KSC-EUC-H"}, - {"UniKS-UCS2-V", "KSC-EUC-V"} - }; - - // core 14 AFM names - protected static final String[] CORE14 = { - "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", - "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", - "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", - "Symbol", - "ZapfDingbats" - }; - - // type1 font names. - protected static final String[][] TYPE1_FONT_NAME = { - {"Times-Roman", "Times New Roman", "TimesNewRoman", "TimesNewRomanPS", "TimesNewRomanPSMT"}, - {"Times-Bold", "TimesNewRoman,Bold", "TimesNewRoman-Bold", "TimesNewRomanPS-Bold", "TimesNewRomanPS-BoldMT"}, - {"Times-Italic", "TimesNewRoman,Italic", "TimesNewRoman-Italic", "TimesNewRomanPS-Italic", "TimesNewRomanPS-ItalicMT"}, - {"Times-BoldItalic", "TimesNewRoman,BoldItalic", "TimesNewRoman-BoldItalic", "TimesNewRomanPS-BoldItalic", "TimesNewRomanPS-BoldItalicMT"}, - {"Helvetica", "Arial", "ArialMT"}, - {"Helvetica-Bold", "Helvetica,Bold", "Arial,Bold", "Arial-Bold", "Arial-BoldMT"}, - {"Helvetica-Oblique", "Helvetica,Italic", "Helvetica-Italic", "Arial,Italic", "Arial-Italic", "Arial-ItalicMT"}, - {"Helvetica-BoldOblique", "Helvetica,BoldItalic", "Helvetica-BoldItalic", "Arial,BoldItalic", "Arial-BoldItalic", "Arial-BoldItalicMT"}, - {"Courier", "CourierNew", "CourierNewPSMT"}, - {"Courier-Bold", "Courier,Bold", "CourierNew,Bold", "CourierNew-Bold", "CourierNewPS-BoldMT"}, - {"Courier-Oblique", "Courier,Italic", "CourierNew-Italic", "CourierNew,Italic", "CourierNewPS-ItalicMT"}, - {"Courier-BoldOblique", "Courier,BoldItalic", "CourierNew-BoldItalic", "CourierNew,BoldItalic", "CourierNewPS-BoldItalicMT"}, - {"Symbol"}, - {"ZapfDingbats", "Zapf-Dingbats", "Dingbats"} - }; - - /** - * Creates a new instance of a PDF Font. - * - * @param library Libaray of all objects in PDF - * @param entries hash of parsed font attributes - */ - public Font(Library library, HashMap entries) { - super(library, entries); - - // name of object "Font" - name = library.getName(entries, NAME_KEY); - - // Type of the font, type 0, 1, 2, 3 etc. - subtype = library.getName(entries, SUBTYPE_KEY); - - encoding = library.getName(entries, ENCODING_KEY); - - // figure out type - if (subtype != null) { - subTypeFormat = (subtype.getName().toLowerCase().equals("type0") || - subtype.getName().toLowerCase().contains("cid")) ? - CID_FORMAT : SIMPLE_FORMAT; - } - - int tmpInt = library.getInt(entries, FIRST_CHAR_KEY); - if (tmpInt != 0) { - firstchar = tmpInt; - } - tmpInt = library.getInt(entries, LAST_CHAR_KEY); - if (tmpInt != 0) { - lastchar = tmpInt; - } - - - // font name, SanSerif is used as it has a a robust CID, and it - // is the most commonly used font family for pdfs - basefont = "Serif"; - Object tmp = entries.get(BASEFONT_KEY); - if (tmp != null && tmp instanceof Name) { - basefont = ((Name) tmp).getName(); - } - } - - /** - * Initiate the font. Retrieve any needed attributes, basically set up the - * font so it can be used by the content parser. - */ - public abstract void init(); - - /** - * Gets the base name of the core 14 fonts, null if it does not match - * - * @param name name of font to search for canonical name - */ - protected String getCanonicalName(String name) { - for (String[] aTYPE1_FONT_NAME : TYPE1_FONT_NAME) { - for (String anATYPE1_FONT_NAME : aTYPE1_FONT_NAME) { - if (name.startsWith(anATYPE1_FONT_NAME)) { - return aTYPE1_FONT_NAME[0]; - } - } - } - return null; - } - - /** - * Gets the fonts base name. - * - * @return fonts base name, "Serif" if none specified. - */ - public String getBaseFont() { - return basefont; - } - - /** - * Gets the font name. - * - * @return string representing the font name - */ - public Name getName() { - return name; - } - - /** - * Gets the font subtype value. - * - * @return string representing the font subtype - */ - public Name getSubType() { - return subtype; - } - - /** - * Gets the font subtype format - * - * @return SIMPLE_FORMAT or CID_FORMAT. - */ - public int getSubTypeFormat() { - return subTypeFormat; - } - - /** - * Gets the font encoding name. - * - * @return font encoding name. - */ - public Name getEncoding() { - return encoding; - } - - /** - *

Returns a font which can be used to paint the glyphs in the character - * set.

- * - * @return value of embedded font. - */ - public FontFile getFont() { - return font; - } - - /** - *

Returns true if the writing mode is vertical; false, otherwise

- * - * @return true if the writing mode is vertical; false, otherwise. - */ - public boolean isVerticalWriting() { - return isVerticalWriting; - } - - /** - *

Indicates that this font is an Adobe Core 14 font.

- * - * @return true, if font is a core 14 font; false otherwise. - */ - public boolean isAFMFont() { - return isAFMFont; - } - - public boolean isFontSubstitution() { - return isFontSubstitution; - } - - /** - *

Returns true if the font name is one of the core 14 fonts specified by - * Adobe.

- * - * @param fontName name to test if a core 14 font. - * @return true, if font name is a core 14 font; false, otherwise. - */ - public boolean isCore14(String fontName) { - for (String aCORE14 : CORE14) { - if (fontName.startsWith(aCORE14)) { - return true; - } - } - return false; - } - - /** - * String representation of the Font object. - * - * @return string representing Font object attributes. - */ - public String toString() { - return getPObjectReference() + " FONT= " + basefont + " " + entries.toString(); - } - - public Resources getParentResource() { - return parentResource; - } - - public void setParentResource(Resources parentResource) { - this.parentResource = parentResource; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontDescriptor.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontDescriptor.java deleted file mode 100644 index 2de1b05bfb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontDescriptor.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.util.Library; - -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * This class represents a PDF FontDescriptor. A FontDescriptor object - * holds extra information about a particular parent Font object. In particular - * information on font widths, flags, to unicode and embedded font program streams. - * - * @see org.icepdf.core.pobjects.fonts.Font - */ -public class FontDescriptor extends Dictionary { - - private static final Logger logger = - Logger.getLogger(FontDescriptor.class.toString()); - - private FontFile font; - - public static final Name TYPE = new Name("FontDescriptor"); - public static final Name FONT_NAME = new Name("FontName"); - public static final Name FONT_FAMILY = new Name("FontFamily"); - public static final Name MISSING_Stretch = new Name("FontStretch"); - public static final Name FONT_WEIGHT = new Name("FontWeight"); - public static final Name FLAGS = new Name("Flags"); - public static final Name FONT_BBOX = new Name("FontBBox"); - public static final Name ITALIC_ANGLE = new Name("ItalicAngle"); - public static final Name ASCENT = new Name("Ascent"); - public static final Name DESCENT = new Name("Descent"); - public static final Name LEADING = new Name("Leading"); - public static final Name CAP_HEIGHT = new Name("CapHeight"); - public static final Name X_HEIGHT = new Name("XHeight"); - public static final Name STEM_V = new Name("StemV"); - public static final Name STEM_H = new Name("StemH"); - public static final Name AVG_WIDTH = new Name("AvgWidth"); - public static final Name MAX_WIDTH = new Name("MaxWidth"); - public static final Name MISSING_WIDTH = new Name("MissingWidth"); - public static final Name FONT_FILE = new Name("FontFile"); - public static final Name FONT_FILE_2 = new Name("FontFile2"); - public static final Name FONT_FILE_3 = new Name("FontFile3"); - public static final Name FONT_FILE_3_TYPE_1C = new Name("Type1C"); - public static final Name FONT_FILE_3_CID_FONT_TYPE_0 = new Name("CIDFontType0"); - public static final Name FONT_FILE_3_CID_FONT_TYPE_2 = new Name("CIDFontType2"); - public static final Name FONT_FILE_3_CID_FONT_TYPE_0C = new Name("CIDFontType0C"); - public static final Name FONT_FILE_3_OPEN_TYPE = new Name("OpenType"); - - /** - * Creates a new instance of a FontDescriptor. - * - * @param l Libaray of all objects in PDF - * @param h hash of parsed FontDescriptor attributes - */ - public FontDescriptor(Library l, HashMap h) { - super(l, h); - } - - /** - * Utility method for creating a FontDescriptor based on the font metrics - * of the AFM - * - * @param library document library - * @param afm adobe font metrics data - * @return new instance of a FontDescriptor - */ - public static FontDescriptor createDescriptor(Library library, AFM afm) { - HashMap properties = new HashMap(7); - properties.put(FONT_NAME, afm.getFontName()); - properties.put(FONT_FAMILY, afm.getFamilyName()); - properties.put(FONT_BBOX, afm.getFontBBox()); - properties.put(ITALIC_ANGLE, afm.getItalicAngle()); - properties.put(MAX_WIDTH, afm.getMaxWidth()); - properties.put(AVG_WIDTH, afm.getAvgWidth()); - properties.put(FLAGS, afm.getFlags()); - return new FontDescriptor(library, properties); - } - - /** - * Returns the PostScript name of the font. - * - * @return PostScript name of font. - */ - public String getFontName() { - Object value = library.getObject(entries, FONT_NAME); - if (value instanceof Name) { - return ((Name) value).getName(); - } else if (value instanceof String) { - return (String) value; - } - return null; - } - - /** - * Gets a string specifying the preferred font family name. For example, the font - * "Time Bold Italic" would have a font family of Times. - * - * @return preferred font family name. - */ - public String getFontFamily() { - Object value = library.getObject(entries, FONT_FAMILY); - if (value instanceof StringObject) { - StringObject familyName = (StringObject) value; - return familyName.getDecryptedLiteralString(library.getSecurityManager()); - } - return FONT_NAME.getName(); - } - - /** - * Gets the weight (thickness) component of the fully-qualified font name or - * font specifier. The default value is zero. - * - * @return the weight of the font name. - */ - public float getFontWeight() { - Object value = library.getObject(entries, FONT_WEIGHT); - if (value instanceof Number) { - return ((Number) value).floatValue(); - } - return 0.0f; - } - - /** - * Gets the width to use for character codes whose widths are not specifed in - * the font's dictionary. The default value is zero. - * - * @return width of non-specified characters. - */ - public float getMissingWidth() { - Object value = library.getObject(entries, MISSING_WIDTH); - if (value instanceof Number) { - return ((Number) value).floatValue(); - } - return 0.0f; - } - - /** - * Gets the average width of glyphs in the font. The default value is zero. - * - * @return average width of glyphs. - */ - public float getAverageWidth() { - Object value = library.getObject(entries, AVG_WIDTH); - if (value instanceof Number) { - return ((Number) value).floatValue(); - } - return 0.0f; - } - - /** - * Gets the maximum width of glyphs in the font. The default value is zero. - * - * @return maximum width of glyphs. - */ - public float getMaxWidth() { - Object value = library.getObject(entries, MAX_WIDTH); - if (value instanceof Number) { - return ((Number) value).floatValue(); - } - return 0.0f; - } - - /** - * Gets the ascent of glyphs in the font. The default value is zero. - * - * @return ascent of glyphs. - */ - public float getAscent() { - Object value = library.getObject(entries, ASCENT); - if (value instanceof Number) { - return ((Number) value).floatValue(); - } - return 0.0f; - } - - /** - * Gets the descent of glyphs in the font. The default value is zero. - * - * @return descent of glyphs. - */ - public float getDescent() { - Object value = library.getObject(entries, DESCENT); - if (value instanceof Number) { - return ((Number) value).floatValue(); - } - return 0.0f; - } - - /** - * Gets the embeddedFont if any. - * - * @return embedded font; null, if there is no valid embedded font. - */ - public FontFile getEmbeddedFont() { - return font; - } - - /** - * Gets the fonts bounding box. - * - * @return bounding box in PDF coordinate space. - */ - public PRectangle getFontBBox() { - Object value = library.getObject(entries, FONT_BBOX); - if (value instanceof List) { - List rectangle = (List) value; - return new PRectangle(rectangle); - } - return null; - } - - /** - * Gets the font flag value, which is a collection of various characteristics - * that describe the font. - * - * @return int value representing the flags; bits must be looked at to get - * attribute values. - */ - public int getFlags() { - Object value = library.getObject(entries, FLAGS); - if (value instanceof Number) { - return ((Number) value).intValue(); - } - return 0; - } - - /** - * Initiate the Font Descriptor object. Reads embedded font programs - * or CMap streams. - */ - public synchronized void init() { - - if (inited) { - return; - } - - /** - * FontFile1 = A stream containing a Type 1 font program - * FontFile2 = A stream containing a TrueType font program - * FontFile3 = A stream containing a font program other than Type 1 or - * TrueType. The format of the font program is specified by the Subtype entry - * in the stream dictionary - */ - try { - - // get an instance of our font factory - FontFactory fontFactory = FontFactory.getInstance(); - - if (entries.containsKey(FONT_FILE)) { - Stream fontStream = (Stream) library.getObject(entries, FONT_FILE); - if (fontStream != null) { - font = fontFactory.createFontFile( - fontStream, FontFactory.FONT_TYPE_1, null); - } - } - - if (entries.containsKey(FONT_FILE_2)) { - Stream fontStream = (Stream) library.getObject(entries, FONT_FILE_2); - if (fontStream != null) { - font = fontFactory.createFontFile( - fontStream, FontFactory.FONT_TRUE_TYPE, null); - } - } - - if (entries.containsKey(FONT_FILE_3)) { - - Stream fontStream = (Stream) library.getObject(entries, FONT_FILE_3); - Name subType = (Name) fontStream.getObject(SUBTYPE_KEY); - if (subType != null && - (subType.equals(FONT_FILE_3_TYPE_1C) || - subType.equals(FONT_FILE_3_CID_FONT_TYPE_0) || - subType.equals(FONT_FILE_3_CID_FONT_TYPE_0C)) - ) { - font = fontFactory.createFontFile( - fontStream, FontFactory.FONT_TYPE_1, subType.getName()); - } - if (subType != null && subType.equals(FONT_FILE_3_OPEN_TYPE)) { -// font = new NFontOpenType(fontStreamBytes); - font = fontFactory.createFontFile( - fontStream, FontFactory.FONT_OPEN_TYPE, subType.getName()); - } - } - } - // catch everything, we can fall back to font substitution if a failure - // occurs. - catch (Throwable e) { - logger.log(Level.FINE, "Error Reading Embedded Font ", e); - } - - inited = true; - } - - /** - * Return a string representation of the all the FontDescriptor object's - * parsed attributes. - * - * @return all of FontDescriptors parsed attributes. - */ - public String toString() { - String name = null; - if (font != null) - name = font.getName(); - return super.getPObjectReference() + " FONTDESCRIPTOR= " + entries.toString() + " - " + name; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontFactory.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontFactory.java deleted file mode 100644 index 5f9def1208..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontFactory.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts; - -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.fonts.ofont.OFont; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Constructor; -import java.net.URL; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Simple Factory for loading of font library if present. - */ -public class FontFactory { - - private static final Logger logger = - Logger.getLogger(FontFactory.class.toString()); - - // allow scaling of large images to improve clarity on screen - private static boolean awtFontLoading; - - // dynamic property to switch between font engine and awt font substitution. - private static boolean awtFontSubstitution; - - static { - // turn on font file loading using awt, can cause the jvm to crash - // if the font file is corrupt. - awtFontLoading = - Defs.sysPropertyBoolean("org.icepdf.core.awtFontLoading", - false); - - } - - public static final int FONT_OPEN_TYPE = 5; - public static final int FONT_TRUE_TYPE = java.awt.Font.TRUETYPE_FONT; - public static final int FONT_TYPE_0 = 6; - public static final int FONT_TYPE_1 = java.awt.Font.TYPE1_FONT; - public static final int FONT_TYPE_3 = 7; - - // Singleton instance of class - private static FontFactory fontFactory; - - // NFont class path - private static final String FONT_CLASS = - "org.icepdf.core.pobjects.fonts.nfont.Font"; - private static final String NFONT_CLASS = - "org.icepdf.core.pobjects.fonts.nfont.NFont"; - private static final String NFONT_OPEN_TYPE = - "org.icepdf.core.pobjects.fonts.nfont.NFontOpenType"; - private static final String NFONT_TRUE_TYPE = - "org.icepdf.core.pobjects.fonts.nfont.NFontTrueType"; - private static final String NFONT_TRUE_TYPE_0 = - "org.icepdf.core.pobjects.fonts.nfont.NFontType0"; - private static final String NFONT_TRUE_TYPE_1 = - "org.icepdf.core.pobjects.fonts.nfont.NFontType1"; - private static final String NFONT_TRUE_TYPE_3 = - "org.icepdf.core.pobjects.fonts.nfont.NFontType3"; - static { - // check class bath for NFont library, and declare results. - try { - Class.forName(NFONT_CLASS); - } catch (ClassNotFoundException e) { - logger.log(Level.FINE, "NFont font library was not found on the class path"); - } - } - - private static boolean foundNFont; - - - /** - *

Returns a static instance of the FontManager class.

- * - * @return instance of the FontManager. - */ - public static FontFactory getInstance() { - // make sure we have initialized the manager - if (fontFactory == null) { - fontFactory = new FontFactory(); - } - return fontFactory; - } - - - private FontFactory() { - } - - public Font getFont(Library library, HashMap entries) { - - Font fontDictionary = null; - - if (foundFontEngine()) { - // load each know file type reflectively. - try { - Class fontClass = Class.forName(FONT_CLASS); - Class[] fontArgs = {Library.class, HashMap.class}; - Constructor fontClassConstructor = - fontClass.getDeclaredConstructor(fontArgs); - Object[] fontUrl = {library, entries}; - fontDictionary = (Font) fontClassConstructor.newInstance(fontUrl); - } catch (Throwable e) { - logger.log(Level.FINE, "Could not load font dictionary class", e); - } - } else { - // create OFont implementation. - fontDictionary = - new org.icepdf.core.pobjects.fonts.ofont.Font(library, entries); - } - return fontDictionary; - } - - public FontFile createFontFile(Stream fontStream, int fontType, String fontSubType) { - FontFile fontFile = null; - if (foundFontEngine()) { - try { - Class fontClass = getNFontClass(fontType); - if (fontClass != null) { - // convert the stream to byte[] - Class[] bytArrayArg = {byte[].class, String.class}; - Constructor fontClassConstructor = - fontClass.getDeclaredConstructor(bytArrayArg); - byte[] data = fontStream.getDecodedStreamBytes(0); - Object[] fontStreamBytes = {data, fontSubType}; - if (data.length > 0) { - fontFile = (FontFile) fontClassConstructor - .newInstance(fontStreamBytes); - } - } - } catch (Throwable e) { - logger.log(Level.FINE, "Could not create instance of font file " + fontType); - if (fontType == FONT_TRUE_TYPE) { - // we might have a very rare corner case where the file2 definition is actually a Open type font - if (logger.isLoggable(Level.FINE)) { - logger.fine("Trying to reload TrueType definition as OpenType."); - } - try { - // force a OpentType font load. - Class fontClass = getNFontClass(FONT_OPEN_TYPE); - if (fontClass != null) { - // convert the stream to byte[] - Class[] bytArrayArg = {byte[].class, String.class}; - Constructor fontClassConstructor = - fontClass.getDeclaredConstructor(bytArrayArg); - byte[] data = fontStream.getDecodedStreamBytes(0); - Object[] fontStreamBytes = {data, fontSubType}; - if (data.length > 0) { - fontFile = (FontFile) fontClassConstructor - .newInstance(fontStreamBytes); - } - } - } catch (Exception ex) { - logger.log(Level.FINE, "Could not create instance of font file as OpenType." + fontType); - } - } - } - } else if (awtFontLoading) { - // see if the font file can be loaded with Java Fonts - InputStream in = null; - try { - in = fontStream.getDecodedByteArrayInputStream(); - // make sure we try to load open type fonts as well, done as true type. - if (fontType == FONT_OPEN_TYPE) fontType = FONT_TRUE_TYPE; - java.awt.Font javaFont = java.awt.Font.createFont(fontType, in); - if (javaFont != null) { - // create instance of OFont. - fontFile = new OFont(javaFont); - if (logger.isLoggable(Level.FINE)) { - logger.fine("Successfully created embedded OFont: " + fontTypeToString(fontType)); - } - try { - in.close(); - } catch (IOException e) { - logger.log(Level.FINE, "Error closing font stream.", e); - } - } - } catch (Throwable e) { - logger.log(Level.FINE, "Error reading font file with ", e); - try { - if (in != null) in.close(); - } catch (Throwable e1) { - logger.log(Level.FINE, "Error closing font stream.", e); - } - } - } - return fontFile; - } - - public FontFile createFontFile(File file, int fontType, String fontSubType) { - try { - return createFontFile(file.toURI().toURL(), fontType, fontSubType); - } catch (Throwable e) { - logger.log(Level.FINE, "Could not create instance of font file " + fontType, e); - } - return null; - } - - public FontFile createFontFile(URL url, int fontType, String fontSubType) { - FontFile fontFile = null; - if (foundFontEngine()) { - try { - Class fontClass = getNFontClass(fontType); - if (fontClass != null) { - // convert the stream to byte[] - Class[] urlArg = {URL.class, String.class}; - Constructor fontClassConstructor = - fontClass.getDeclaredConstructor(urlArg); - Object[] fontUrl = {url, fontSubType}; - fontFile = (FontFile) fontClassConstructor.newInstance(fontUrl); - } - } catch (Throwable e) { - logger.log(Level.FINE, "Could not create instance of font file " + fontType, e); - } - } else { - // see if the font file can be loaded with Java Fonts - try { - // make sure we try to load open type fonts as well, done as true type. - if (fontType == FONT_OPEN_TYPE) fontType = FONT_TRUE_TYPE; - java.awt.Font javaFont = java.awt.Font.createFont(fontType, url.openStream()); - if (javaFont != null) { - - // create instance of OFont. - fontFile = new OFont(javaFont); - - if (logger.isLoggable(Level.FINE)) { - logger.fine("Successfully loaded OFont: " + url); - } - } - } catch (Throwable e) { - logger.log(Level.FINE, "Error reading font file with ", e); - } - } - return fontFile; - } - - public boolean isAwtFontSubstitution() { - return awtFontSubstitution; - } - - public void setAwtFontSubstitution(boolean awtFontSubstitution) { - FontFactory.awtFontSubstitution = awtFontSubstitution; - } - - public void toggleAwtFontSubstitution() { - FontFactory.awtFontSubstitution = !FontFactory.awtFontSubstitution; - } - - private Class getNFontClass(int fontType) throws ClassNotFoundException { - Class fontClass = null; - if (FONT_OPEN_TYPE == fontType) { - fontClass = Class.forName(NFONT_OPEN_TYPE); - } else if (FONT_TRUE_TYPE == fontType) { - fontClass = Class.forName(NFONT_TRUE_TYPE); - } else if (FONT_TYPE_0 == fontType) { - fontClass = Class.forName(NFONT_TRUE_TYPE_0); - } else if (FONT_TYPE_1 == fontType) { - fontClass = Class.forName(NFONT_TRUE_TYPE_1); - } else if (FONT_TYPE_3 == fontType) { - fontClass = Class.forName(NFONT_TRUE_TYPE_3); - } - return fontClass; - } - - private String fontTypeToString(int fontType) { - - if (fontType == FONT_OPEN_TYPE) { - return "Open Type Font"; - } else if (fontType == FONT_TRUE_TYPE) { - return "True Type Font"; - } else if (fontType == FONT_TYPE_0) { - return "Type 0 Font"; - } else if (fontType == FONT_TYPE_1) { - return "Type 1 Font"; - } else if (fontType == FONT_TYPE_3) { - return "Type 3 Font"; - } else { - return "unknown font type: " + fontType; - } - } - - /** - * Test if font engine is available on the class path and it has been - * disabled with the property awtFontSubstitution. - * - * @return true if font engine was found, false otherwise. - */ - public boolean foundFontEngine() { - // check class bath for NFont library - try { - Class.forName(NFONT_CLASS); - foundNFont = true; - } catch (ClassNotFoundException e) { - // keep quiet - } - - return foundNFont && !awtFontSubstitution; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontFile.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontFile.java deleted file mode 100644 index 2e5ca93794..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontFile.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.net.URL; -import java.util.Map; - -/** - * Font file interfaces. Common methods which encapsulate NFont and OFont - * font rendering libraries. - * - * @since 3.0 - */ -public interface FontFile { - - /** - * Possible encoding format of string that was designed to work with this - * font. Type is determined by queues in the parent Cmap definition. - */ - public enum ByteEncoding { - ONE_BYTE, TWO_BYTE, MIXED_BYTE - } - - public static final long LAYOUT_NONE = 0; - - public Point2D echarAdvance(char ech); - - public FontFile deriveFont(AffineTransform at); - - public FontFile deriveFont(Encoding encoding, CMap toUnicode); - - public FontFile deriveFont(float[] widths, int firstCh, float missingWidth, - float ascent, float descent, char[] diff); - - public FontFile deriveFont(Map widths, int firstCh, float missingWidth, - float ascent, float descent, char[] diff); - - /** - * Can the character ch in the nfont's encoding be rendered? - */ - public boolean canDisplayEchar(char ech); - - public void setIsCid(); - - /** - * Creates nfont a new pointsize, assuming 72 ppi. - * Note to subclassers: you must make a complete independent instance of the nfont here, - * even if pointsize and everything else is the same, as other deriveFont methods use this to make a clone and might make subsequent changes. - */ - public FontFile deriveFont(float pointsize); - - public CMap getToUnicode(); - - public String toUnicode(String displayText); - - public String toUnicode(char displayChar); - - /** - * Returns name of nfont, such as "Times". - */ - public String getFamily(); - - public float getSize(); - - /** - * Returns maximum ascent glyphs above baseline. - */ - public double getAscent(); - - /** - * Returns maximum descent of glyphs below baseline. - */ - public double getDescent(); - - /** - * Returns left in rectangle's x, ascent in y, width in width, height in height. - */ - public Rectangle2D getMaxCharBounds(); - - /** - * Returns a copy of the transform associated with this font file. - */ - public AffineTransform getTransform(); - - /** - * Returns nfont usage rights bit mask. - */ - public int getRights(); - - /** - * Returns name of nfont, such as "Times-Roman", which is different than the filename. - */ - public String getName(); - - /** - * Returns true iff nfont has hinted outlines, which is Type 1 and TrueType is a sign of higher quality. - */ - public boolean isHinted(); - - /** - * Returns number of glyphs defined in nfont. - */ - public int getNumGlyphs(); - - public int getStyle(); - - /** - * Returns the character that seems to be used as a space in the current encoding, or NOTDEF_CHAR if no such character. - */ - public char getSpaceEchar(); - - public Rectangle2D getEstringBounds(String estr, int beginIndex, int limit); - - /** - * Returns primary format, such as "Type1" or "OpenType". - */ - public String getFormat(); - - public abstract void drawEstring(Graphics2D g, String estr, float x, - float y, long layout, int mode, - Color strokecolor); - - /** - * Get the glyph outline shape for the given estr translated to x,y. - * - * @param estr text to calculate glyph outline shape - * @param x x coordinate to translate outline shape. - * @param y y coordinate to translate outline shape. - * @return glyph outline of the estr. - */ - public Shape getEstringOutline(String estr, float x, float y); - - public ByteEncoding getByteEncoding(); - - /** - * Gets the source url of the underlying file if any. Embedded fonts will - * not have a source. - * - * @return null if the font is embedded, otherwise the font system path. - */ - public URL getSource(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontManager.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontManager.java deleted file mode 100644 index bd3e64a0f6..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/FontManager.java +++ /dev/null @@ -1,1201 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts; - -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.FontUtil; - -import java.awt.Font; -import java.awt.*; -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.security.AccessControlException; -import java.util.*; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

The FontManager class is responsible for finding available - * fonts on the client operating system. This class will detect fonts the OS - * and try and load fonts in the known locations for the particular OS. The - * FontManager also does a recursive descent into base folders to try and find - * more fonts which is extremely important on Linux systems.

- *

It is possible to specify other directories to search for fonts via the - * readSystemFonts methods extraFontPaths parameter {@link #readSystemFonts}. - * Reading all of an operating systems font's can be time consuming. To help - * speed up this process the method getFontProperties exports font data via a - * Properties object. The font Properties object can then be saved to disk or - * be read back into the FontManager via the setFontProperties method.

- * - * @since 2.0 - */ -public class FontManager { - - private static final Logger logger = - Logger.getLogger(FontManager.class.toString()); - - // stores all font data - private static List fontList; - - // stores fonts loaded from jar, these won't be cached - private static List fontJarList; - - // flags for detecting font decorations - private static int PLAIN = 0xF0000001; - private static int BOLD = 0xF0000010; - private static int ITALIC = 0xF0000100; - private static int BOLD_ITALIC = 0xF0001000; - - // Differences for type1 fonts which match adobe core14 metrics - private static final String TYPE1_FONT_DIFFS[][] = - {{"Bookman-Demi", "URWBookmanL-DemiBold", "Arial"}, - {"Bookman-DemiItalic", "URWBookmanL-DemiBoldItal", "Arial"}, - {"Bookman-Light", "URWBookmanL-Ligh", "Arial"}, - {"Bookman-LightItalic", "URWBookmanL-LighItal", "Arial"}, - {"Courier", "NimbusMonL-Regu", "Nimbus Mono L", "CourierNew", "CourierNewPSMT"}, - {"Courier-Oblique", "NimbusMonL-ReguObli", "Nimbus Mono L", "Courier,Italic", "CourierNew-Italic", "CourierNew,Italic", "CourierNewPS-ItalicMT"}, - {"Courier-Bold", "NimbusMonL-Bold", "Nimbus Mono L", "Courier,Bold", "CourierNew,Bold", "CourierNew-Bold", "CourierNewPS-BoldMT"}, - {"Courier-BoldOblique", "NimbusMonL-BoldObli", "Nimbus Mono L", "Courier,BoldItalic", "CourierNew-BoldItalic", "CourierNew,BoldItalic", "CourierNewPS-BoldItalicMT"}, - {"AvantGarde-Book", "URWGothicL-Book", "Arial"}, - {"AvantGarde-BookOblique", "URWGothicL-BookObli", "Arial"}, - {"AvantGarde-Demi", "URWGothicL-Demi", "Arial"}, - {"AvantGarde-DemiOblique", "URWGothicL-DemiObli", "Arial"}, - {"Helvetica", "Helvetica", "Arial", "ArialMT", "NimbusSanL-Regu", "Nimbus Sans L"}, -// {"Helvetica", "NimbusSanL-Regu", "Nimbus Sans L", "Arial", "ArialMT"}, // known problem in Phelps nfont engine - {"Helvetica-Oblique", "NimbusSanL-ReguItal", "Nimbus Sans L", "Helvetica,Italic", "Helvetica-Italic", "Arial,Italic", "Arial-Italic", "Arial-ItalicMT"}, -// {"Helvetica-Bold", "NimbusSanL-Bold", "Nimbus Sans L", "Helvetica-Black", "Helvetica,Bold", "Arial,Bold", "Arial-Bold", "Arial-BoldMT"}, // known problem in Phelps nfont engine - {"Helvetica-Bold", "Helvetica,Bold", "Arial,Bold", "Arial-Bold", "Arial-BoldMT", "NimbusSanL-Bold", "Nimbus Sans L"}, - {"Helvetica-BoldOblique", "NimbusSanL-BoldItal", "Helvetica-BlackOblique", "Nimbus Sans L", "Helvetica,BoldItalic", "Helvetica-BoldItalic", "Arial,BoldItalic", "Arial-BoldItalic", "Arial-BoldItalicMT"}, - {"Helvetica-Black", "Helvetica,Bold", "Arial,Bold", "Arial-Bold", "Arial-BoldMT", "NimbusSanL-Bold", "Nimbus Sans L"}, - {"Helvetica-BlackOblique", "NimbusSanL-BoldItal", "Helvetica-BlackOblique", "Nimbus Sans L", "Helvetica,BoldItalic", "Helvetica-BoldItalic", "Arial,BoldItalic", "Arial-BoldItalic", "Arial-BoldItalicMT"}, - {"Helvetica-Narrow", "NimbusSanL-ReguCond", "Nimbus Sans L"}, - {"Helvetica-Narrow-Oblique", "NimbusSanL-ReguCondItal", "Nimbus Sans L"}, - {"Helvetica-Narrow-Bold", "NimbusSanL-BoldCond", "Nimbus Sans L"}, - {"Helvetica-Narrow-BoldOblique", "NimbusSanL-BoldCondItal", "Nimbus Sans L"}, - {"Helvetica-Condensed", "NimbusSanL-ReguCond", "Nimbus Sans L"}, - {"Helvetica-Condensed-Oblique", "NimbusSanL-ReguCondItal", "Nimbus Sans L"}, - {"Helvetica-Condensed-Bold", "NimbusSanL-BoldCond", "Nimbus Sans L"}, - {"Helvetica-Condensed-BoldOblique", "NimbusSanL-BoldCondItal", "Nimbus Sans L"}, - {"Palatino-Roman", "URWPalladioL-Roma", "Arial"}, - {"Palatino-Italic", "URWPalladioL-Ital", "Arial"}, - {"Palatino-Bold", "URWPalladioL-Bold", "Arial"}, - {"Palatino-BoldItalic", "URWPalladioL-BoldItal", "Arial"}, - {"NewCenturySchlbk-Roman", "CenturySchL-Roma", "Arial"}, - {"NewCenturySchlbk-Italic", "CenturySchL-Ital", "Arial"}, - {"NewCenturySchlbk-Bold", "CenturySchL-Bold", "Arial"}, - {"NewCenturySchlbk-BoldItalic", "CenturySchL-BoldItal", "Arial"}, - {"Times-Roman", "NimbusRomNo9L-Regu", "Nimbus Roman No9 L", "TimesNewRoman", "TimesNewRomanPSMT", "TimesNewRomanPS"}, - {"Times-Italic", "NimbusRomNo9L-ReguItal", "Nimbus Roman No9 L", "TimesNewRoman,Italic", "TimesNewRoman-Italic", "TimesNewRomanPS-Italic", "TimesNewRomanPS-ItalicMT"}, - {"Times-Bold", "NimbusRomNo9L-Medi", "Nimbus Roman No9 L", "TimesNewRoman,Bold", "TimesNewRoman-Bold", "TimesNewRomanPS-Bold", "TimesNewRomanPS-BoldMT"}, - {"Times-BoldItalic", "NimbusRomNo9L-MediItal", "Nimbus Roman No9 L", "TimesNewRoman,BoldItalic", "TimesNewRoman-BoldItalic", "TimesNewRomanPS-BoldItalic", "TimesNewRomanPS-BoldItalicMT"}, - {"Symbol", "StandardSymL", "Standard Symbols L"}, - {"ZapfChancery-MediumItalic", "URWChanceryL-MediItal", "Arial"}, - {"ZapfDingbats", "Dingbats", "Zapf-Dingbats"} - }; - - private static final String[] JAPANESE_FONT_NAMES = { - "Arial Unicode MS", "PMingLiU", "MingLiU", - "MS PMincho", "MS Mincho", "Kochi Mincho", "Hiragino Mincho Pro", - "KozMinPro Regular Acro", "HeiseiMin W3 Acro", "Adobe Ming Std Acro" - }; - - private static final String[] CHINESE_SIMPLIFIED_FONT_NAMES = { - "Arial Unicode MS", "PMingLiU", "MingLiU", - "SimSun", "NSimSun", "Kochi Mincho", "STFangsong", "STSong Light Acro", - "Adobe Song Std Acro" - }; - - private static final String[] CHINESE_TRADITIONAL_FONT_NAMES = { - "Arial Unicode MS", "PMingLiU", "MingLiU", - "SimSun", "NSimSun", "Kochi Mincho", "BiauKai", "MSungStd Light Acro", - "Adobe Song Std Acro" - }; - - private static final String[] KOREAN_FONT_NAMES = { - "Arial Unicode MS", "Dotum", "Gulim", "New Gulim", "GulimChe", "Batang", - "BatangChe", "HYSMyeongJoStd Medium Acro", "Adobe Myungjo Std Acro", - "AppleGothic", "Malgun Gothic", "UnDotum", "UnShinmun", "Baekmuk Gulim" - }; - - /** - * Java base font class, generally ${java.home}\lib\fonts. This is the base font directory that is used - * for searching for system fonts. If all else fails this should be the fall back directory. - */ - public static String JAVA_FONT_PATH = Defs.sysProperty("java.home") + "/lib/fonts"; - - /** - * Default search path for fonts on windows systems. - */ - public static List WINDOWS_FONT_PATHS = Arrays.asList( - // windir works for winNT and older 9X system, same as "systemroot" - JAVA_FONT_PATH, - System.getenv("WINDIR") + "\\Fonts"); - - /** - * Default search path for fonts on Apple systems. - */ - public static List MAC_FONT_PATHS = Arrays.asList( - Defs.sysProperty("user.home") + "/Library/Fonts/", - "/Library/Fonts/", - JAVA_FONT_PATH, - "/Network/Library/Fonts/", - "/System/Library/Fonts/", - "/System Folder/Fonts", - "/usr/local/share/ghostscript/"); - - /** - * Default search path for fonts on Linux/Unix systems. - */ - public static List LINUX_FONT_PATHS = Arrays.asList( - "/usr/share/fonts/", - JAVA_FONT_PATH, - "/usr/X11R6/lib/X11/fonts/", - "/usr/openwin/lib/", - "/usr/sfw/share/a2ps/afm/", - "/usr/sfw/share/ghostscript/fonts/"); - - /** - * Change the base font name from lucidasans which is a Java Physical Font - * name. The name should be change to one of Java's logical font names: - * Dialog, DialogInput, Monospaced, Serif, SansSerif. The closest logical - * name that match LucidaSans is SansSerif. - */ - private static String baseFontName; - - static { - baseFontName = Defs.property("org.icepdf.core.font.basefont", "lucidasans"); - } - - // Singleton instance of class - private static FontManager fontManager; - - - /** - *

Returns a static instance of the FontManager class.

- * - * @return instance of the FontManager. - */ - public static FontManager getInstance() { - // make sure we have initialized the manager - if (fontManager == null) { - fontManager = new FontManager(); - } - return fontManager; - } - - /** - *

Initializes the fontList by reading the system fonts paths via readSystemFonts() - * but only if the fontList is null or is empty. Generally the fontManager - * is used with the {@link org.icepdf.ri.util.FontPropertiesManager } - *

- * - * @return instance of the singleton fontManager. - */ - public FontManager initialize() { - if (fontList == null || fontList.size() == 0) { - readSystemFonts(null); - } - return fontManager; - } - - /** - *

Gets a Properties object containing font information for the operating - * system which the FontManager is running on. This Properties object - * can be saved to disk and read at a later time using the {@see #setFontProperties} - * method.

- * - * @return Properties object containing font data information. - */ - public Properties getFontProperties() { - Properties fontProperites; - // make sure we are initialized - if (fontList == null) { - fontList = new ArrayList(); - } - // copy all data from fontList into the properties file - fontProperites = new Properties(); - Iterator fontIterator = fontList.iterator(); - Object[] currentFont; - String name; - String family; - Integer decorations; - String path; - // Build the properties file using the font name as the key and - // the value is the family, decoration and path information - // separated by the "|" character. - while (fontIterator.hasNext()) { - currentFont = (Object[]) fontIterator.next(); - name = (String) currentFont[0]; - family = (String) currentFont[1]; - decorations = (Integer) currentFont[2]; - path = (String) currentFont[3]; - // add the new entry - fontProperites.put(name, family + "|" + decorations + "|" + path); - } - return fontProperites; - } - - /** - *

Reads font data from the Properties file. All name and key data replaces - * any existing font information.

- * - * @param fontProperties Properties object containing valid font information. - * @throws IllegalArgumentException thrown, if there is a problem parsing the - * Properties file. If thrown, the calling application should re-read - * the system fonts. - */ - public void setFontProperties(Properties fontProperties) - throws IllegalArgumentException { - String errorString = "Error parsing font properties "; - try { - fontList = new ArrayList(150); - Enumeration fonts = fontProperties.propertyNames(); - String name; - String family; - Integer decorations; - String path; - StringTokenizer tokens; - // read in font information - while (fonts.hasMoreElements()) { - name = (String) fonts.nextElement(); - tokens = new StringTokenizer((String) fontProperties.get(name), "|"); - // get family, decoration and path tokens - family = tokens.nextToken(); - decorations = new Integer(tokens.nextToken()); - path = tokens.nextToken(); - if (name != null && family != null && path != null) { - fontList.add(new Object[]{name, family, decorations, path}); - } else { - throw new IllegalArgumentException(errorString); - } - } - sortFontListByName(); - } catch (Throwable e) { - logger.log(Level.FINE, "Error setting font properties ", e); - throw new IllegalArgumentException(errorString); - } - } - - /** - * Clears internal font list of items. Used to clean list while constructing - * a new list. - */ - public void clearFontList() { - if (fontList != null) { - fontList.clear(); - } - } - - /** - *

Reads font from the specified array of file paths only, no . This font data is used to substitute fonts which are not - * embedded inside a PDF document.

- * - * @param extraFontPaths array String object where each entry represents - * a system directory path containing font programs. - */ - public synchronized void readFonts(String[] extraFontPaths) { - readSystemFonts(extraFontPaths, true); - } - - /** - * Reads system fonts as defined in SYSTEM_FONT_PATHS plush any extra fonts paths. The reading - * of system fonts can be suspended with the param skipSystemFonts. - * - * @param extraFontPaths optional, extra fonts path to read. - * @param skipSystemFonts true to skip system fonts, extraFontsPaths should not be null if skipSystemFonts=true. - */ - private synchronized void readSystemFonts(String[] extraFontPaths, boolean skipSystemFonts) { - // create a new font list if needed. - if (fontList == null) { - fontList = new ArrayList(150); - } - - - ArrayList fontDirectories = new ArrayList(); - // load the appropriate font set for the OS. - if (!skipSystemFonts) { - String operationSystem = System.getProperty("os.name"); - if (operationSystem != null) { - operationSystem = operationSystem.toLowerCase(); - if (operationSystem.contains("win")) { - logger.finer("Detected Windows loading appropriate font paths."); - fontDirectories.addAll(WINDOWS_FONT_PATHS); - } else if (operationSystem.contains("mac")) { - logger.finer("Detected OSX loading appropriate font paths."); - fontDirectories.addAll(MAC_FONT_PATHS); - } else { - // must be an inix. - logger.finer("Detected Unix/Linux loading appropriate font paths."); - fontDirectories.addAll(LINUX_FONT_PATHS); - } - } - - } - // tack on the extraFontPaths - if (extraFontPaths != null) { - logger.finer("Loading extraFontPaths specified by users"); - fontDirectories.addAll(Arrays.asList(extraFontPaths)); - } - - // check to make sure we have at least a few fonts. - if (fontDirectories.size() == 0) { - // fall back to at least a few fonts. - logger.finer("No fonts specified or detected falling back to JAVA font paths."); - fontDirectories.add(JAVA_FONT_PATH); - } - - if (logger.isLoggable(Level.FINER)) { - logger.finer("Starting recursive scan of specified font directories for system fonts."); - } - loadSystemFont(fontDirectories); - } - - /** - *

Searches all default system font paths and any font paths - * specified by the extraFontPaths parameter, and records data about all - * found fonts. This font data is used to substitute fonts which are not - * embedded inside a PDF document.

- * - * @param extraFontPaths array String object where each entry represents - * a system directory path containing font programs. - */ - public synchronized void readSystemFonts(String[] extraFontPaths) { - readSystemFonts(extraFontPaths, false); - } - - private void loadSystemFont(List fontDirectories) { - try { - for (String fontDirectory : fontDirectories) { - File directory = new File(fontDirectory); - if (directory.canRead() && directory.isDirectory()) { - logger.finer("looking into directory " + directory.getAbsolutePath()); - // load files - File[] files = directory.listFiles(); - if (files != null) { - List dirPaths = new ArrayList(); - for (File file : files) { - if (file.isFile()) { - // load the font. - evaluateFontForInsertion(file.getAbsolutePath()); - } else if (file.isDirectory()) { - dirPaths.add(file.getAbsolutePath()); - } - } - // If we have some directories, then we want ot recursively descend. - loadSystemFont(dirPaths); - } - } else if (directory.canRead() && directory.isFile()) { - // load the font. - evaluateFontForInsertion(directory.getAbsolutePath()); - } - } - } catch (AccessControlException e) { - logger.log(Level.WARNING, "SecurityException: failed to load fonts from directory: ", e); - } catch (Throwable e) { - logger.log(Level.FINE, "Failed to load fonts from directory: ", e); - } - } - - private void evaluateFontForInsertion(String fontPath) { - // try loading the font - FontFile font = buildFont(fontPath); - // if a readable font was found - if (font != null) { - logger.finer("Found font file" + fontPath); - // normalize name - String fontName = font.getName().toLowerCase(); - // Add new font data to the font list - fontList.add(new Object[]{font.getName().toLowerCase(), // original PS name - FontUtil.normalizeString(font.getFamily()), // family name - guessFontStyle(fontName), // weight and decorations, mainly bold,italic - fontPath}); // path to font on OS - if (logger.isLoggable(Level.FINER)) { - logger.finer("Adding system font: " + font.getName() + " " + fontPath); - } - } - } - - /** - *

Utility method for guessing a font family name from its base name.

- * - * @param name base name of font. - * @return guess of the base fonts name. - */ - public static String guessFamily(String name) { - String fam = name; - int inx; - // Family name usually precedes a common, ie. "Arial,BoldItalic" - if ((inx = fam.indexOf(',')) > 0) - fam = fam.substring(0, inx); - // Family name usually precedes a dash, example "Times-Bold", - if ((inx = fam.lastIndexOf('-')) > 0) - fam = fam.substring(0, inx); - return fam; - } - - /** - *

Gets all available font names on the operating system.

- * - * @return font names of all found fonts. - */ - public String[] getAvailableNames() { - if (fontList != null) { - String[] availableNames = new String[fontList.size()]; - Iterator nameIterator = fontList.iterator(); - Object[] fontData; - for (int i = 0; nameIterator.hasNext(); i++) { - fontData = (Object[]) nameIterator.next(); - availableNames[i] = fontData[0].toString(); - } - return availableNames; - } - return null; - } - - /** - *

Gets all available font family names on the operating system.

- * - * @return font family names of all found fonts. - */ - public String[] getAvailableFamilies() { - if (fontList != null) { - String[] availableNames = new String[fontList.size()]; - Iterator nameIterator = fontList.iterator(); - Object[] fontData; - for (int i = 0; nameIterator.hasNext(); i++) { - fontData = (Object[]) nameIterator.next(); - availableNames[i] = fontData[1].toString(); - } - return availableNames; - } - return null; - } - - /** - *

Gets all available font styles on the operating system.

- * - * @return font style names of all found fonts. - */ - public String[] getAvailableStyle() { - if (fontList != null) { - String[] availableStyles = new String[fontList.size()]; - Iterator nameIterator = fontList.iterator(); - Object[] fontData; - int decorations; - String style = ""; - for (int i = 0; nameIterator.hasNext(); i++) { - fontData = (Object[]) nameIterator.next(); - decorations = (Integer) fontData[2]; - if ((decorations & BOLD_ITALIC) == BOLD_ITALIC) { - style += " BoldItalic"; - } else if ((decorations & BOLD) == BOLD) { - style += " Bold"; - } else if ((decorations & ITALIC) == ITALIC) { - style += " Italic"; - } else if ((decorations & PLAIN) == PLAIN) { - style += " Plain"; - } - availableStyles[i] = style; - style = ""; - } - return availableStyles; - } - return null; - } - - public FontFile getJapaneseInstance(String name, int fontFlags) { - return getAsianInstance(fontList, name, JAPANESE_FONT_NAMES, fontFlags); - } - - public FontFile getKoreanInstance(String name, int fontFlags) { - return getAsianInstance(fontList, name, KOREAN_FONT_NAMES, fontFlags); - } - - public FontFile getChineseTraditionalInstance(String name, int fontFlags) { - return getAsianInstance(fontList, name, CHINESE_TRADITIONAL_FONT_NAMES, fontFlags); - } - - public FontFile getChineseSimplifiedInstance(String name, int fontFlags) { - return getAsianInstance(fontList, name, CHINESE_SIMPLIFIED_FONT_NAMES, fontFlags); - } - - private FontFile getAsianInstance(List fontList, String name, String[] list, int flags) { - - if (fontList == null) { - fontList = new ArrayList(150); - } - - FontFile font = null; - if (list != null) { - // search for know list of fonts - for (int i = list.length - 1; i >= 0; i--) { - // try and find an instance of the name and family from the font list - font = findFont(fontList, name, flags); - if (font != null) { - if (logger.isLoggable(Level.FINER)) { - logger.finer("Font Substitution: Found Asian font: " + font.getName() + " for named font " + name); - } - return font; - } - } - - // lastly see if we can't a system font that matches the list names. - // search for know list of fonts - for (int i = list.length - 1; i >= 0; i--) { - // try and find an instance of the name and family from the font list - font = findFont(fontList, list[i], flags); - if (font != null) { - if (logger.isLoggable(Level.FINER)) { - logger.finer("Font Substitution: Found Asian font: " + font.getName() + " for named font " + name); - } - return font; - } - } - } - - return font; - } - - /** - * Reads the specified resources from the specified package. This method - * is intended to aid in the packaging of fonts used for font substitution - * and avoids the need to install fonts on the client operating system. - *

- * The following font resource types are supported are support: - *

    - *
  • TrueType - *.ttf, *.dfont, *.ttc
  • - *
  • Type1 - *.pfa, *.pfb
  • - *
  • OpenType - *.otf, *.otc
  • - *
- * - * @param fontResourcePackage package to look for the resources in. - * @param resources file names of font resources to load. - */ - public void readFontPackage(String fontResourcePackage, List resources) { - if (fontJarList == null) { - fontJarList = new ArrayList(35); - } - URL resourcePath; - FontFile font; - String fontName; - for (String resourceName : resources) { - // build the url and add the font to the font list. - resourcePath = FontManager.class.getResource("/" + fontResourcePackage + "/" + resourceName); - // try loading the font - font = buildFont(resourcePath); - // if a readable font was found - if (font != null) { - // normalize name - fontName = font.getName().toLowerCase(); - // Add new font data to the font list - fontJarList.add(new Object[]{font.getName().toLowerCase(), // original PS name - FontUtil.normalizeString(font.getFamily()), // family name - guessFontStyle(fontName), // weight and decorations, mainly bold,italic - resourcePath.toString()}); // path to font on OS - if (logger.isLoggable(Level.FINER)) { - logger.finer("Adding system font: " + font.getName() + " " + resourcePath.toString()); - } - } - } - } - - /** - *

Get an instance of a NFont from the given font name and flag decoration - * information.

- * - * @param name base name of font. - * @param flags flags used to describe font. - * @return a new instance of NFont which best approximates the font described - * by the name and flags attribute. - */ - public FontFile getInstance(String name, int flags) { - - if (fontList == null) { - fontList = new ArrayList(); - } - - FontFile font; - - // try any attached jars first as they are likely controlled. - if (fontJarList != null) { - font = getType1Fonts(fontJarList, name, flags); - if (font != null) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Font Substitution: Found type1 font: " + font.getName() + " for named font " + name); - } - return font; - } - } - - // try and find equivalent type1 font - font = getType1Fonts(fontList, name, flags); - if (font != null) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Font Substitution: Found type1 font: " + font.getName() + " for named font " + name); - } - return font; - } - - // check the font name first against the jars list. - if (fontJarList != null) { - font = findFont(fontJarList, name, flags); - if (font != null) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Font Substitution: Found type1 font: " + font.getName() + " for named font " + name); - } - return font; - } - } - - // try and find an instance of the name and family from the font list - font = findFont(fontList, name, flags); - if (font != null) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Font Substitution: Found system font: " + font.getName() + " for named font " + name); - } - return font; - } - - // try and find an equivalent java font - font = getCoreJavaFont(name, flags); - if (font != null) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Font Substitution: Found java font: " + font.getName() + " for named font " + name); - } - return font; - } - - // if all else fails return first font in fontList with matching style, - // this should never happen, but just in case. - if (fontList.size() > 0) { - Object[] fontData; - boolean found = false; - int decorations = guessFontStyle(name); - int style; - // get first font that has a matching style - for (int i = fontList.size() - 1; i >= 0; i--) { - fontData = fontList.get(i); - style = (Integer) fontData[2]; - if (((decorations & BOLD_ITALIC) == BOLD_ITALIC) && - ((style & BOLD_ITALIC) == BOLD_ITALIC)) { - found = true; - } else if (((decorations & BOLD) == BOLD) && - ((style & BOLD) == BOLD)) { - found = true; - } else if (((decorations & ITALIC) == ITALIC) && - ((style & ITALIC) == ITALIC)) { - found = true; - } else if (((decorations & PLAIN) == PLAIN) && - ((style & PLAIN) == PLAIN)) { - found = true; - } - if (found) { - font = buildFont((String) fontData[3]); - break; - } - } - if (!found) { - fontData = fontList.get(0); - font = buildFont((String) fontData[3]); - } - if (logger.isLoggable(Level.FINE)) { - logger.fine("Font Substitution: Found failed " + name + " " + font.getName()); - } - } - if (font == null) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("No Fonts can be found on your system. "); - } - } - - return font; - } - - /** - * Utility method for search the fontList array for an particular font name - * that has the specified style. - * - * @param fontName font name with any decoration information still appended to name. - * @param flags flags from content parser, to help guess style. - * @return a valid font if found, null otherwise - */ - private FontFile findFont(List fontList, String fontName, int flags) { - - FontFile font = null; - // references for system font list. - Object[] fontData; - String baseName; - String familyName; - String path; - // normalize the fontName we are trying to find a match for - int decorations = guessFontStyle(fontName); - String name = FontUtil.normalizeString(fontName); - int style; - - if (fontList != null) { - for (int i = fontList.size() - 1; i >= 0; i--) { - fontData = fontList.get(i); - baseName = (String) fontData[0]; - familyName = (String) fontData[1]; - path = (String) fontData[3]; - if (logger.isLoggable(Level.FINEST)) { - logger.finest(baseName + " : " + familyName + " : " + name); - } - if (name.contains(familyName) || -// familyName.contains(name) || - fontName.toLowerCase().contains(baseName)) { - style = (Integer) fontData[2]; - boolean found = false; - // ignore this font, as the cid mapping are not correct, or ther is - // just look and feel issues with them. - if (baseName.equals("opensymbol") || - baseName.equals("starsymbol") - || baseName.equals("symbolmt") - || baseName.equals("arial-black") - || baseName.equals("arial-blackitalic") - || baseName.equals("new") - // mapping issue with standard ascii, not sure why, TimesNewRomanPSMT is ok. - || baseName.equals("timesnewromanps") - // doesn't seem to the correct cid mapping otf version anyways. - || baseName.equals("kozminpro-regular") - ) { - //found = false; - } else if (((decorations & BOLD_ITALIC) == BOLD_ITALIC) && - ((style & BOLD_ITALIC) == BOLD_ITALIC)) { - found = true; - } else if (((decorations & BOLD) == BOLD) && - ((style & BOLD) == BOLD)) { - found = true; - } else if (((decorations & ITALIC) == ITALIC) && - ((style & ITALIC) == ITALIC)) { - found = true; - } else if (((decorations & PLAIN) == PLAIN) && - ((style & PLAIN) == PLAIN)) { - found = true; - } - // symbol type fonts don't have an associated style, so - // no point trying to match them based on style. - else if (baseName.contains("wingdings") || - baseName.contains("zapfdingbats") || - baseName.contains("dingbats") || - baseName.contains("symbol")) { - found = true; - } - - if (found) { - if (logger.isLoggable(Level.FINER)) { - logger.finer("Match Found for: " + fontName + ":" + getFontStyle(style, 0).trim() + - " Substituting " + baseName + ":" + path); - } - font = buildFont((String) fontData[3]); - // make sure the font does indeed exist - if (font != null) { - break; - } - } - } - } - } - return font; - } - - /** - * Loads a font specified by the fontpath parameter. If font path is invalid - * or the file can not be loaded, null is returned. - * - * @param fontPath font path of font program to laod - * @return a valid font if loadable, null otherwise - */ - private FontFile buildFont(String fontPath) { - FontFile font = null; - try { - if (fontPath.startsWith("jar:file")) { - font = buildFont(new URL(fontPath)); - } else { - File file = new File(fontPath); - if (!file.canRead()) { - return null; - } - font = buildFont(file); - } - } catch (Throwable e) { - logger.log(Level.FINE, "Error reading font program.", e); - } - return font; - } - - private FontFile buildFont(File fontFile) { - String fontPath = fontFile.getPath(); - FontFactory fontFactory = FontFactory.getInstance(); - FontFile font = null; - // found true type font - if ((fontPath.endsWith(".ttf") || fontPath.endsWith(".TTF")) || - (fontPath.endsWith(".dfont") || fontPath.endsWith(".DFONT")) || - (fontPath.endsWith(".ttc") || fontPath.endsWith(".TTC"))) { - font = fontFactory.createFontFile(fontFile, FontFactory.FONT_TRUE_TYPE, null); - } - // found Type 1 font - else if ((fontPath.endsWith(".pfa") || fontPath.endsWith(".PFA")) || - (fontPath.endsWith(".pfb") || fontPath.endsWith(".PFB"))) { - font = fontFactory.createFontFile(fontFile, FontFactory.FONT_TYPE_1, null); - } - // found OpenType font - else if ((fontPath.endsWith(".otf") || fontPath.endsWith(".OTF")) || - (fontPath.endsWith(".otc") || fontPath.endsWith(".OTC"))) { - font = fontFactory.createFontFile(fontFile, FontFactory.FONT_OPEN_TYPE, null); - } - return font; - } - - private FontFile buildFont(URL fontUri) { - FontFile font = null; - try { - String fontPath = fontUri.getPath(); - FontFactory fontFactory = FontFactory.getInstance(); - // found true type font - if ((fontPath.endsWith(".ttf") || fontPath.endsWith(".TTF")) || - (fontPath.endsWith(".dfont") || fontPath.endsWith(".DFONT")) || - (fontPath.endsWith(".ttc") || fontPath.endsWith(".TTC"))) { - font = fontFactory.createFontFile(fontUri, FontFactory.FONT_TRUE_TYPE, null); - } - // found Type 1 font - else if ((fontPath.endsWith(".pfa") || fontPath.endsWith(".PFA")) || - (fontPath.endsWith(".pfb") || fontPath.endsWith(".PFB"))) { - font = fontFactory.createFontFile(fontUri, FontFactory.FONT_TYPE_1, null); - } - // found OpenType font - else if ((fontPath.endsWith(".otf") || fontPath.endsWith(".OTF")) || - (fontPath.endsWith(".otc") || fontPath.endsWith(".OTC"))) { - font = fontFactory.createFontFile(fontUri, FontFactory.FONT_OPEN_TYPE, null); - } - } catch (Throwable e) { - logger.log(Level.FINE, "Error reading font program.", e); - } - return font; - } - - /** - * Gets a NFont instance by matching against font style commonalities in the - * Java Cores libraries. - * - * @param fontName font name to search for - * @param flags style flags - * @return a valid NFont if a match is found, null otherwise. - */ - private FontFile getCoreJavaFont(String fontName, int flags) { - - int decorations = guessFontStyle(fontName); - fontName = FontUtil.normalizeString(fontName); - FontFile font; - - // read font flags as it can sometimes give us hints as to serif - // san sarif or a monospace font, there is more data we can pull if needed too. - boolean isFixedPitch = (flags & org.icepdf.core.pobjects.fonts.Font.FONT_FLAG_FIXED_PITCH) != 0; - boolean isSerif = (flags & org.icepdf.core.pobjects.fonts.Font.FONT_FLAG_SERIF) != 0; -// boolean isSymbolic = (flags & org.icepdf.core.pobjects.fonts.Font.FONT_FLAG_SYMBOLIC) != 0; -// boolean isNotSymbolic = (flags & org.icepdf.core.pobjects.fonts.Font.FONT_FLAG_NON_SYMBOLIC) != 0; - // If no name are found then match against the core java font names - // "Serif", java equivalent is "Lucida Bright" - if (fontName.contains("timesnewroman") || - fontName.contains("bodoni") || - fontName.contains("garamond") || - fontName.contains("minionweb") || - fontName.contains("stoneserif") || - fontName.contains("georgia") || - fontName.contains("bitstreamcyberbit")) { - // important, add style information - font = findFont(fontList, "lucidabright-" + getFontStyle(decorations, flags), 0); - } - // see if we working with a monospaced font, we sub "Sans Serif", - // java equivalent is "Lucida Sans" - else if (fontName.contains("helvetica") || - fontName.contains("arial") || - fontName.contains("trebuchet") || - fontName.contains("avantgardegothic") || - fontName.contains("verdana") || - fontName.contains("univers") || - fontName.contains("futura") || - fontName.contains("stonesans") || - fontName.contains("gillsans") || - fontName.contains("akzidenz") || - fontName.contains("frutiger") || - fontName.contains("grotesk")) { - // important, add style information - font = findFont(fontList, baseFontName + "-" + getFontStyle(decorations, flags), 0); - } - // see if we working with a mono spaced font "Mono Spaced" - // java equivalent is "Lucida Sans Typewriter" - else if (fontName.contains("courier") || - fontName.contains("couriernew") || - fontName.contains("prestige") || - fontName.contains("eversonmono")) { - // important, add style information - font = findFont(fontList, baseFontName + "typewriter-" + getFontStyle(decorations, flags), 0); - } - // first try get the first match based on the style type and finally on failure - // failure go with the serif as it is the most common font family - else { - if (isSerif) { - font = findFont(fontList, "lucidabright-" + getFontStyle(decorations, flags), 0); - } else if (isFixedPitch) { - // lucidatypewriter, seems to make the font engine barf, converting to other - // common fixed pitch font courier-new. - font = findFont(fontList, "couriernew-" + getFontStyle(decorations, flags), 0); - } else { - // sans serif - font = findFont(fontList, "lucidasans-" + getFontStyle(decorations, flags), 0); - } - } - - return font; - } - - /** - * Gets a NFont instance by matching against font style commonalities in the - * of know type1 fonts - * - * @param fontName font name to search for - * @param flags style flags - * @return a valid NFont if a match is found, null otherwise. - */ - private FontFile getType1Fonts(List fontList, String fontName, int flags) { - FontFile font = null; - boolean found = false; - boolean isType1Available = true; - // find a match for family in the type 1 nfont table - for (String[] TYPE1_FONT_DIFF : TYPE1_FONT_DIFFS) { - for (String aTYPE1_FONT_DIFF : TYPE1_FONT_DIFF) { - // first check to see font name matches any elements - if (TYPE1_FONT_DIFF[0].contains(fontName)) { - // next see if know type1 fonts are installed - if (isType1Available) { - font = findFont(fontList, TYPE1_FONT_DIFF[1], flags); - if (font != null) { - found = true; - break; - } else { - isType1Available = false; - } - } - // do a full search for possible matches. - font = findFont(fontList, aTYPE1_FONT_DIFF, flags); - if (font != null) { - found = true; - break; - } - } - - } - // break out of second loop - if (found) break; - } - return font; - } - - /** - * Gets a Font instance by matching against font style commonalities in the - * of know type1 fonts - * - * @param fontName font name to search for - * @return a valid AWT Font if a match is found, null otherwise. - */ - public java.awt.Font getType1AWTFont(String fontName, int fontSize) { - java.awt.Font font = null; - boolean found = false; - boolean isType1Available = true; - // find a match for family in the type 1 nfont table - for (String[] TYPE1_FONT_DIFF : TYPE1_FONT_DIFFS) { - for (String aTYPE1_FONT_DIFF : TYPE1_FONT_DIFF) { - // first check to see font name matches any elements - if (TYPE1_FONT_DIFF[0].contains(fontName)) { - // next see if know type1 fonts are installed - if (isType1Available) { - font = findAWTFont(TYPE1_FONT_DIFF[1]); - if (font != null) { - found = true; - break; - } else { - isType1Available = false; - } - } - // do a full search for possible matches. - font = findAWTFont(aTYPE1_FONT_DIFF); - if (font != null) { - found = true; - break; - } - } - } - // break out of second loop - if (found) break; - } - if (font != null) { - font = font.deriveFont((float) fontSize); - } - return font; - } - - /** - * Utility method for search the fontList array for an particular font name - * that has the specified style. - * - * @param fontName font name with any decoration information still appended to name. - * @return a valid font if found, null otherwise - */ - private java.awt.Font findAWTFont(String fontName) { - - java.awt.Font font = null; - // references for system font list. - Object[] fontData; - String baseName; - String familyName; - // normalize the fontName we are trying to find a match for - int decorations = guessFontStyle(fontName); - String name = FontUtil.normalizeString(fontName); - int style; - - if (fontList != null) { - for (int i = fontList.size() - 1; i >= 0; i--) { - fontData = fontList.get(i); - baseName = (String) fontData[0]; - familyName = (String) fontData[1]; - if (logger.isLoggable(Level.FINEST)) { - logger.finest(baseName + " : " + familyName + " : " + name); - } - if (name.contains(familyName) || - fontName.toLowerCase().contains(baseName)) { - style = (Integer) fontData[2]; - boolean found = false; - // ignore this font, as the cid mapping are not correct, or ther is - // just look and feel issues with them. - if (baseName.equals("opensymbol") || - baseName.equals("starsymbol") - || baseName.equals("arial-black") - || baseName.equals("arial-blackitalic") - || baseName.equals("new") - // mapping issue with standard ascii, not sure why, TimesNewRomanPSMT is ok. - || baseName.equals("timesnewromanps") - ) { - //found = false; - } else if (((decorations & BOLD_ITALIC) == BOLD_ITALIC) && - ((style & BOLD_ITALIC) == BOLD_ITALIC)) { - found = true; - } else if (((decorations & BOLD) == BOLD) && - ((style & BOLD) == BOLD)) { - found = true; - } else if (((decorations & ITALIC) == ITALIC) && - ((style & ITALIC) == ITALIC)) { - found = true; - } else if (((decorations & PLAIN) == PLAIN) && - ((style & PLAIN) == PLAIN)) { - found = true; - } - // symbol type fonts don't have an associated style, so - // no point trying to match them based on style. - else if (baseName.contains("wingdings") || - baseName.contains("zapfdingbats") || - baseName.contains("symbol")) { - found = true; - } - - if (found) { - if (logger.isLoggable(Level.FINER)) { - logger.finer("----> Found font: " + baseName + - " family: " + getFontStyle(style, 0) + - " for: " + fontName); - } - try { - font = java.awt.Font.createFont(Font.TRUETYPE_FONT, - new File((String) fontData[3])); - } catch (FontFormatException e) { - logger.log(Level.FINE, "Error create new font", e); - } catch (IOException e) { - logger.log(Level.FINE, "Error reading font", e); - } - // make sure the font does indeed exist - if (font != null) { - break; - } - } - } - } - } - return font; - } - - /** - * Utility method which maps know style strings to an integer value which - * is used later for efficient font searching. - * todo: move out to FontUtil and use awt constants - * - * @param name base name of font. - * @return integer representing dffs - */ - private static int guessFontStyle(String name) { - name = name.toLowerCase(); - int decorations = 0; - if ((name.indexOf("boldital") > 0) || (name.indexOf("demiital") > 0)) { - decorations |= BOLD_ITALIC; - } else if (name.indexOf("bold") > 0 || name.indexOf("black") > 0 || name.endsWith("bt") - || name.indexOf("demi") > 0) { - decorations |= BOLD; - } else if (name.indexOf("ital") > 0 || name.indexOf("obli") > 0) { - decorations |= ITALIC; - } else { - decorations |= PLAIN; - } - return decorations; - } - - /** - * Returns the string representation of a font style specified by the - * decoration and flags integers. - * - * @param sytle style specified by known offsets - * @param flags flags from pdf dictionary - * @return string representation of styles specified by the two integers. - */ - private String getFontStyle(int sytle, int flags) { - // Get any useful data from the flags integer. - String style = ""; - if ((sytle & BOLD_ITALIC) == BOLD_ITALIC) { - style += " BoldItalic"; - } else if ((sytle & BOLD) == BOLD || - (flags & org.icepdf.core.pobjects.fonts.Font.FONT_FLAG_FORCE_BOLD) != 0) { - style += " Bold"; - } else if ((sytle & ITALIC) == ITALIC || - (flags & org.icepdf.core.pobjects.fonts.Font.FONT_FLAG_FORCE_BOLD) != 0) { - style += " Italic"; - } else if ((sytle & PLAIN) == PLAIN) { - style += " Plain"; - } - return style; - } - - /** - * Sorts the fontList of system fonts by font name or the first element - * int the object[] store. - */ - private static void sortFontListByName() { - Collections.sort(fontList, new Comparator() { - public int compare(Object[] o1, Object[] o2) { - return ((String) o2[0]).compareTo((String) o1[0]); - } - }); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/CMap.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/CMap.java deleted file mode 100644 index c8c955b415..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/CMap.java +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts.ofont; - -import org.icepdf.core.io.SeekableInput; -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Parser; -import org.icepdf.core.util.Utils; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - - -/** - * The purpose of the class is to parse a CMap file. A CMap specifies the - * mapping from character codes to character selectors. A CMap file defines - * the relationship between a character code and the character description - *

- * Character selectors are always CIDs in a CIDFont. A CMap serves a function - * analogous to the Encoding dictionary for a simple font. The CMap does not - * refer directly to a specific CIDFont; instead, it is combined with it as part - * of a CIDkeyed font, represented in PDF as a Type 0 font dictionary. Within - * the CMap, the character mappings refer to the associated CIDFont by font - * number, which in PDF is always 0. - * - * @since 1.0 - */ -class CMap extends Dictionary implements org.icepdf.core.pobjects.fonts.CMap { - - private static final Logger logger = - Logger.getLogger(CMap.class.toString()); - - /** - * Dictionary containing entries that define the character collection for - * the CIDFont or CIDFonts associate with the CMap. Specifically the - * character collections registry, ordering and supplement is defined. - */ - private HashMap cIdSystemInfo; - - /** - * PostScript name of the CMap. - */ - private String cMapName; - - /** - * defines changes to the internal organization of CMap files or the - * semantics of CMap operators. The CMapType of CMaps described in - * this document. - * cMapType = 2 - indicates a ToUnicode cmap - * cMapType = 1 - indicates a CMap object - * cMapType = 0 - not sure yet, maybe CMap with external CMap reference - */ - private float cMapType; - - /** - * The name of a predefined CMap, or a stream containing a CMap, that - * is to be used as the base for this CMap. This allows the CMap to - * be defined differentially, specifying only the character mappings - * that differ from the base CMap. - */ - private Object useCMap; - - /** - * The WMode dictionary entry controls whether the CID-keyed font writes - * horizontally or vertically. It indicates which set of metrics will be - * used when a base font is shown. An entry of 0 defines horizontal - * writing from left to right; an entry of 1 defines vertical writing - * from top to bottom. - */ - private int wMode; - - /** - * Defines the source character code range. Source CMap references must - * be in this range. - */ - private int[][] codeSpaceRange; - - // determine if cmap is using one or two byte character maps. - private boolean oneByte; - - /** - * Defines mappings from character codes to Unicode characters in the - * associated font. Expressed in UTF-16BE encoding. - */ - private HashMap bfChars; - - /** - * Defines mappings from character codes to Unicode character ranges. - * Expressed in UTF-16BE encoding. - */ - private List bfRange; - - /** - * Define mappings of individual input character codes to CIDS in the - * associated CIDFont. - */ - private HashMap cIdChars; - - /** - * Similar to cIdChars but defines ranges of input codes. - */ - private HashMap cIdRange; - - /** - * Define mappings if the normal mapping produces a CID for which no glyph - * in the associated CIDFont - */ - private HashMap notDefChars; - - /** - * Similar to notDefChars but defines ranges of input codes. - */ - private HashMap notDefRange; - - /** - * Stream containing the embbeded CMap - */ - private Stream cMapStream; - private InputStream cMapInputStream; - - - /** - * Create a new CMap instance. If the CMap is created from a named object - * the dictionary property will be populated with values for the keys - * Type, CMapName and CIDSystemInfo which are also repeated in the CMap - * file itself. If the CMap file was created from a Font object then they - * previously mentioned keys values must be parsed from the CMap file. - * - * @param library pointer to default library containing all document objects - * @param entries HashMap containing all of the dictionary properties associated - * with this object. The HashMap will be empty if this object - * was created via a Font objects ToUnicode key. - * @param cMapStream stream containing CMap data. - */ - public CMap(Library library, HashMap entries, Stream cMapStream) { - super(library, entries); - this.cMapStream = cMapStream; - } - - public CMap(Library l, HashMap h, InputStream cMapInputStream) { - super(l, h); - this.cMapInputStream = cMapInputStream; - } - - public boolean isOneByte() { - return oneByte; - } - - public boolean isTwoByte() { - return !oneByte; - } - - public boolean isMixedByte() { - return false; - } - - public boolean isEmptyMapping() { - return false; - } - - /** - * Start the parsing of the CMap file. Once completed, all necessary data - * should be captured from the CMap file. - *

- * Simple CMap - * /CIDInit /ProcSet findresource - * begin - * 12 dict begin - * begincmap - * /CIDSystemInfo << - * /Registry (Adobe) - * /Ordering (UCS) - * /Supplement 0 - * >> def - * /CMapName /Adobe-Identity-UCS def - * /CMapType 2 def - * 1 begincodespacerange - * <00> - * endcodespacerange - * 7 beginbfchar - * <01> <0054> - * <02> <0065> - * <03> <0073> - * <04> <0074> - * <05> <0069> - * <06> <006E> - * <07> <0067> - * endbfchar - * 2 beginbfrange - * <0000> <005E> <0020> - * <005F> <0061>[<00660066> <0066069> <00660066006C>] - * endbfrange - * endcmap - * CMapName currentdict /CMap defineresource pop - * end - * end - */ - public void init() { - try { - // get the byes and push them through the parser to get objects in CMap - if (cMapInputStream == null) { - cMapInputStream = cMapStream.getDecodedByteArrayInputStream(); - } - - // Print CMap ASCII - if (logger.isLoggable(Level.FINER)) { - String content; - if (cMapInputStream instanceof SeekableInput) { - content = Utils.getContentFromSeekableInput((SeekableInput) cMapInputStream, false); - } else { - InputStream[] inArray = new InputStream[]{cMapInputStream}; - content = Utils.getContentAndReplaceInputStream(inArray, false); - cMapInputStream = inArray[0]; - } - - logger.finer("<------------------------ CMap"); - logger.finer(content); - logger.finer("CMap ------------------------> "); - } - - Parser parser = new Parser(cMapInputStream); - - /** - * Start gathering the data from the CMap objects, the CMap file - * is fixed in format so this routine doesn't have to be to - * complicated - */ - Object previousToken = null; - while (true) { - Object token = parser.getStreamObject(); - // break out and the end of the stream - if (token == null) { - break; - } - // find cIdSystemInfo, not always a named attribute - String nameString = token.toString(); - if (nameString.toLowerCase().indexOf("cidsysteminfo") >= 0) { - // CIDSystemInfo only has one property which should be - // always be hash by definition and our parser result - token = parser.getStreamObject(); - if (token instanceof HashMap) { - cIdSystemInfo = (HashMap) token; - // always followed by a def token; - token = parser.getStreamObject(); - } - // ignore any other format that isn't a hash - } - // find main CMap descriptors - if (token instanceof Name) { - nameString = token.toString(); - // find cMapName - if (nameString.toLowerCase().indexOf("cmapname") >= 0) { - // cmapname will always be a Name object - token = parser.getStreamObject(); - cMapName = token.toString(); - // always followed by a def token; - token = parser.getStreamObject(); - } - // find cMapType - if (nameString.toLowerCase().indexOf("cmaptype") >= 0) { - // cmapname will always be a float - token = parser.getStreamObject(); - cMapType = Float.parseFloat(token.toString()); - // always followed by a def token; - token = parser.getStreamObject(); - } - // find UseMap - if (nameString.toLowerCase().indexOf("usemap") >= 0) { - // nothing for now - } - } - // record the actual CMap mappings - if (token instanceof String) { - String stringToken = (String) token; - // find codeSpaceRange - if (stringToken.equalsIgnoreCase("begincodespacerange")) { - // before begincodespacerange, the number of ranges is defined - int numberOfRanges = (int) Float.parseFloat(previousToken.toString()); - // a range will always have two hex numbers - codeSpaceRange = new int[numberOfRanges][2]; - for (int i = 0; i < numberOfRanges; i++) { - // low end of range - token = parser.getStreamObject(); - StringObject hexToken = (StringObject) token; - int startRange = hexToken.getUnsignedInt(0, hexToken.getLength()); - - // high end of range - token = parser.getStreamObject(); - hexToken = (StringObject) token; - int length = hexToken.getLength(); - int endRange = hexToken.getUnsignedInt(0, length); - codeSpaceRange[i][0] = startRange; - codeSpaceRange[i][1] = endRange; - if (length == 2) { - oneByte = true; - } - } - } - // find bfChars - if (stringToken.equalsIgnoreCase("beginbfchar")) { - // before beginbfchar, the number of ranges is defined - int numberOfbfChar = (int) Float.parseFloat(previousToken.toString()); - // there can be multiple char maps so we don't want to override previous values. - if (bfChars == null) { - bfChars = new HashMap(numberOfbfChar); - } - // a range will always have two hex numbers - for (int i = 0; i < numberOfbfChar; i++) { - // cid value - token = parser.getStreamObject(); - StringObject hexToken = (StringObject) token; - Integer key = hexToken.getUnsignedInt(0, hexToken.getLength()); - - // cid mapping value - token = parser.getStreamObject(); - hexToken = (StringObject) token; - char[] value = null; - try { - value = convertToString(hexToken.getLiteralStringBuffer()); - } catch (NumberFormatException e) { - logger.log(Level.FINE, "CMAP: ", e); - } - bfChars.put(key, value); - } - } - // find bfRange - if (stringToken.equalsIgnoreCase("beginbfrange")) { - int numberOfbfRanges = (int) Float.parseFloat(previousToken.toString()); - if (bfRange == null) { - bfRange = new ArrayList(numberOfbfRanges); - } - StringObject hexToken; - Integer startRange; - Integer endRange; - // work through each range - for (int i = 0; i < numberOfbfRanges; i++) { - // look for start range. - token = parser.getStreamObject(); - if (token instanceof StringObject) { - hexToken = (StringObject) token; - startRange = hexToken.getUnsignedInt(0, hexToken.getLength()); - } else { - // likely a malformed cmap - break; - } - // end range - token = parser.getStreamObject(); - if (token instanceof StringObject) { - hexToken = (StringObject) token; - endRange = hexToken.getUnsignedInt(0, hexToken.getLength()); - } else { - // likely a malformed cmap - break; - } - - // the next token will be vector or another Integer - token = parser.getStreamObject(); - if (token instanceof List) { - bfRange.add(new CMapRange(startRange, - endRange, - (List) token)); - } else { - hexToken = (StringObject) token; - Integer offset = hexToken.getUnsignedInt(0, hexToken.getLength()); - bfRange.add(new CMapRange(startRange, - endRange, - offset)); - } - } - } - - /** - * CID mappings still need to be implemented but I have - * no examples of yet to check. The CID mappings are little - * bit different then the bf ranges. - */ - - // find cIdChars - if (stringToken.equalsIgnoreCase("begincidchar")) { - - } - // find cIdRange - if (stringToken.equalsIgnoreCase("begincidrange")) { - - } - // find notDefChars - if (stringToken.equalsIgnoreCase("beginnotdefchar")) { - - } - // find notDefRange - if (stringToken.equalsIgnoreCase("beginnotdefrange")) { - - } - - } - previousToken = token; - } - } catch (UnsupportedEncodingException e) { - logger.log(Level.SEVERE, "CMap parsing error", e); - } catch (IOException e) { - // eat it, end of file stream - } finally { - if (cMapInputStream != null) { - try { - cMapInputStream.close(); - } catch (IOException e) { - logger.log(Level.FINE, "Error clossing cmap stream", e); - } - } - } - } - - public String toUnicode(char ch) { - // check bfChar - if (bfChars != null) { - char[] tmp = bfChars.get((int) ch); - if (tmp != null) { - return String.valueOf(tmp); - } - } - // check bfRange for matches, there may be many ranges to check - if (bfRange != null) { - for (CMapRange aBfRange : bfRange) { - if (aBfRange.inRange(ch)) { - return String.valueOf(aBfRange.getCMapValue(ch)); - } - } - } - return String.valueOf(ch); - } - - /** - * The method is called when ever a character code is incounter that has a - * FontDescriptor that defines a ToUnicode CMap. The charMap - * is mapped according to the CMap rules and a mapped character code is - * returned. - * - * @param charMap value to map against the ToUnicode CMap - * @return mapped character value. - */ - public char toSelector(char charMap) { - // print out a mapping for a particular character -// if (charMap == 42){ -// System.out.println("mapping " + (int)charMap + " " + bfChars); -// System.out.println(cIdSystemInfo); -// System.out.println(cMapType); -// } - - // for ToUnicode we only need to look at bfChar and bfRange. - // bfChar values have a higher precedent then bfRange. - - // check bfChar - if (bfChars != null) { - char[] tmp = bfChars.get((int) charMap); - if (tmp != null) { - return tmp[0]; - } - } - // check bfRange for matches, there may be many ranges to check - if (bfRange != null) { - for (CMapRange aBfRange : bfRange) { - if (aBfRange.inRange(charMap)) { - return aBfRange.getCMapValue(charMap)[0]; - } - } - } - return charMap; - } - - public char toSelector(char charMap, boolean isCFF) { - return toSelector(charMap); - } - - /** - * Help class to store data for a CMap bfrange value. CMap bfranges come - * in two flavours but there both share a start and end range value. - * Characters that fall in this range are mapped with wither the offset - * value or to an offset vector. - *

- * Basic offset Mapping - * <0000> <005E> <0020> - values that are between <0000> and <005E> are - * offset by <0020> ie <0001> maps to <0021>, <004f> maps to <006f> and - * <0006F> would not be mapped by this range. - *

- * Vector offset Mapping - * <005F> <0061>[<00660066> <0066069> <00660066006C>] - values that are - * between <005f> and <0067> are mapped directly to an offset index in the - * array. ie <005f> maps to <00660066> and <0060> maps to <0066069> and - * finally <0061> maps to <00660066006C>. - */ - class CMapRange { - - // start value for a bfrange - int startRange = 0; - // end value for a bfrange - int endRange = 0; - // offset mapping - int offsetValue = 0; - // offset vector - List offsetVecor = null; - - /** - * Create a new instance of a CMapRange, when it is a simple range - * mapping with an offset value. - * - * @param startRange start range of mapping - * @param endRange end range of mapping - * @param offsetValue value to offset a mapping by - */ - public CMapRange(int startRange, int endRange, int offsetValue) { - this.startRange = startRange; - this.endRange = endRange; - this.offsetValue = offsetValue; - } - - /** - * Creat new instance of a CMapRange, when it is a more vector range - * mapping. Each valid number in the range maps the a corresponding - * value in the vector based on the numbers offset from the start range. - * - * @param startRange start range of mapping - * @param endRange end range of the mapping - * @param offsetVecor offset mappped vector - */ - public CMapRange(int startRange, int endRange, List offsetVecor) { - this.startRange = startRange; - this.endRange = endRange; - this.offsetVecor = offsetVecor; - } - - /** - * Checks if a value is in the CMap bfrange. - * - * @param value value to check for containment - * @return true if the cmap falls inside one of the bfranges, false - * otherwise. - */ - public boolean inRange(int value) { - return (value >= startRange && value <= endRange); - } - - /** - * Get the mapped value of value. It is assumed that - * inRange is called before this method is called. If the - * value is not in the range then a value of -1 is returned - * - * @param value value to find corresponding CMap for - * @return the mapped CMap value for value, -1 if the - * value can not be mapped. - */ - public char[] getCMapValue(int value) { - - // case of float offset - if (offsetVecor == null) { - return new char[]{(char) (offsetValue + (value - startRange))};//value + offsetValue; - } else {// case of vector offset - // value - startRange will give the index in the vector of the desired - // mapping value - StringObject hexToken = (StringObject) offsetVecor.get(value - startRange); - char[] test = convertToString(hexToken.getLiteralStringBuffer()); - return test; - } - } - - } - - // convert to characters. - private char[] convertToString(CharSequence s) { - if (s == null || s.length() % 2 != 0) { - throw new IllegalArgumentException(); - } - int len = s.length(); - if (len == 1) { - return new char[]{s.charAt(0)}; - } - char[] dest = new char[len / 2]; - for (int i = 0, j = 0; i < len; i += 2, j++) { - dest[j] = (char) ((s.charAt(i) << 8) | s.charAt(i + 1)); - } - return dest; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/Encoding.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/Encoding.java deleted file mode 100644 index 97198e43e3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/Encoding.java +++ /dev/null @@ -1,2591 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts.ofont; - -import java.util.HashMap; - -/** - * put your documentation comment here - */ -public class Encoding implements org.icepdf.core.pobjects.fonts.Encoding { - private char enc[]; - - private Encoding(char e[]) { - enc = e; - } - - public char get(char i) { - if (i >= 0 && i < 256) { -// char c = enc[i]; - // if (c >= 0) - return enc[i]; - } - return i; - } - - static Encoding getStandard() { - return new Encoding(se); - } - - static Encoding getMacRoman() { - return new Encoding(mre); - } - - static Encoding getWinAnsi() { - return new Encoding(wae); - } - - public static Encoding getPDFDoc() { - return new Encoding(pde); - } - - static Encoding getSymbol() { - return new Encoding(sym); - } - - static Encoding getZapfDingBats() { - return new Encoding(zap); - } - - static int getUV(String glyphName) { - Integer UV = h.get(glyphName); - if (UV != null) - return UV; - if (glyphName.startsWith("G")) { - try { - String s = glyphName.substring(1); - return Integer.parseInt(s); - } catch (Exception ex) { - // - } - } - return -1; - } - - static private HashMap h; - static private char se[], mre[], wae[], pde[], sym[], zap[]; - - // common symbol alaises, displayable, followed by aliases - // More symbols should be added here as mappings are needed. - public static int[][] symbolAlaises = {{183, 61623, 8226}, // bullets - {169, 61667, 61651, 63721, 63193}, // copy rights - {174, 61650, 61666, 61614}, // registered - {80, 8364} // euro - }; - public static int[] registeredAlaises = {182}; - static { - h = new HashMap(1046); - h.put("A", 65); - h.put("AE", 198); - h.put("AEacute", 508); - h.put("AEsmall", 63462); - h.put("Aacute", 193); - h.put("Aacutesmall", 63457); - h.put("Abreve", 258); - h.put("Acircumflex", 194); - h.put("Acircumflexsmall", 63458); - h.put("Acute", 63177); - h.put("Acutesmall", 63412); - h.put("Adieresis", 196); - h.put("Adieresissmall", 63460); - h.put("Agrave", 192); - h.put("Agravesmall", 63456); - h.put("Alpha", 913); - h.put("Alphatonos", 902); - h.put("Amacron", 256); - h.put("Aogonek", 260); - h.put("Aring", 197); - h.put("Aringacute", 506); - h.put("Aringsmall", 63461); - h.put("Asmall", 63329); - h.put("Atilde", 195); - h.put("Atildesmall", 63459); - h.put("B", 66); - h.put("Beta", 914); - h.put("Brevesmall", 63220); - h.put("Bsmall", 63330); - h.put("C", 67); - h.put("Cacute", 262); - h.put("Caron", 63178); - h.put("Caronsmall", 63221); - h.put("Ccaron", 268); - h.put("Ccedilla", 199); - h.put("Ccedillasmall", 63463); - h.put("Ccircumflex", 264); - h.put("Cdotaccent", 266); - h.put("Cedillasmall", 63416); - h.put("Chi", 935); - h.put("Circumflexsmall", 63222); - h.put("Csmall", 63331); - h.put("D", 68); - h.put("Dcaron", 270); - h.put("Dcroat", 272); - h.put("Delta", 8710); - h.put("Delta", 916); - h.put("Dieresis", 63179); - h.put("DieresisAcute", 63180); - h.put("DieresisGrave", 63181); - h.put("Dieresissmall", 63400); - h.put("Dotaccentsmall", 63223); - h.put("Dsmall", 63332); - h.put("E", 69); - h.put("Eacute", 201); - h.put("Eacutesmall", 63465); - h.put("Ebreve", 276); - h.put("Ecaron", 282); - h.put("Ecircumflex", 202); - h.put("Ecircumflexsmall", 63466); - h.put("Edieresis", 203); - h.put("Edieresissmall", 63467); - h.put("Edotaccent", 278); - h.put("Egrave", 200); - h.put("Egravesmall", 63464); - h.put("Emacron", 274); - h.put("Eng", 330); - h.put("Eogonek", 280); - h.put("Epsilon", 917); - h.put("Epsilontonos", 904); - h.put("Esmall", 63333); - h.put("Eta", 919); - h.put("Etatonos", 905); - h.put("Eth", 208); - h.put("Ethsmall", 63472); - h.put("Euro", 8364); - h.put("F", 70); - h.put("Fsmall", 63334); - h.put("G", 71); - h.put("Gamma", 915); - h.put("Gbreve", 286); - h.put("Gcaron", 486); - h.put("Gcircumflex", 284); - h.put("Gcommaaccent", 290); - h.put("Gdotaccent", 288); - h.put("Grave", 63182); - h.put("Gravesmall", 63328); - h.put("Gsmall", 63335); - h.put("H", 72); - h.put("H18533", 9679); - h.put("H18543", 9642); - h.put("H18551", 9643); - h.put("H22073", 9633); - h.put("Hbar", 294); - h.put("Hcircumflex", 292); - h.put("Hsmall", 63336); - h.put("Hungarumlaut", 63183); - h.put("Hungarumlautsmall", 63224); - h.put("I", 73); - h.put("IJ", 306); - h.put("Iacute", 205); - h.put("Iacutesmall", 63469); - h.put("Ibreve", 300); - h.put("Icircumflex", 206); - h.put("Icircumflexsmall", 63470); - h.put("Idieresis", 207); - h.put("Idieresissmall", 63471); - h.put("Idotaccent", 304); - h.put("Ifraktur", 8465); - h.put("Igrave", 204); - h.put("Igravesmall", 63468); - h.put("Imacron", 298); - h.put("Iogonek", 302); - h.put("Iota", 921); - h.put("Iotadieresis", 938); - h.put("Iotatonos", 906); - h.put("Ismall", 63337); - h.put("Itilde", 296); - h.put("J", 74); - h.put("Jcircumflex", 308); - h.put("Jsmall", 63338); - h.put("K", 75); - h.put("Kappa", 922); - h.put("Kcommaaccent", 310); - h.put("Ksmall", 63339); - h.put("L", 76); - h.put("LL", 63167); - h.put("Lacute", 313); - h.put("Lambda", 923); - h.put("Lcaron", 317); - h.put("Lcommaaccent", 315); - h.put("Ldot", 319); - h.put("Lslash", 321); - h.put("Lslashsmall", 63225); - h.put("Lsmall", 63340); - h.put("M", 77); - h.put("Macron", 63184); - h.put("Macronsmall", 63407); - h.put("Msmall", 63341); - h.put("Mu", 924); - h.put("N", 78); - h.put("Nacute", 323); - h.put("Ncaron", 327); - h.put("Ncommaaccent", 325); - h.put("Nsmall", 63342); - h.put("Ntilde", 209); - h.put("Ntildesmall", 63473); - h.put("Nu", 925); - h.put("O", 79); - h.put("OE", 338); - h.put("OEsmall", 63226); - h.put("Oacute", 211); - h.put("Oacutesmall", 63475); - h.put("Obreve", 334); - h.put("Ocircumflex", 212); - h.put("Ocircumflexsmall", 63476); - h.put("Odieresis", 214); - h.put("Odieresissmall", 63478); - h.put("Ogoneksmall", 63227); - h.put("Ograve", 210); - h.put("Ogravesmall", 63474); - h.put("Ohorn", 416); - h.put("Ohungarumlaut", 336); - h.put("Omacron", 332); - h.put("Omega", 8486); - h.put("Omega", 937); - h.put("Omegatonos", 911); - h.put("Omicron", 927); - h.put("Omicrontonos", 908); - h.put("Oslash", 216); - h.put("Oslashacute", 510); - h.put("Oslashsmall", 63480); - h.put("Osmall", 63343); - h.put("Otilde", 213); - h.put("Otildesmall", 63477); - h.put("P", 80); - h.put("Phi", 934); - h.put("Pi", 928); - h.put("Psi", 936); - h.put("Psmall", 63344); - h.put("Q", 81); - h.put("Qsmall", 63345); - h.put("R", 82); - h.put("Racute", 340); - h.put("Rcaron", 344); - h.put("Rcommaaccent", 342); - h.put("Rfraktur", 8476); - h.put("Rho", 929); - h.put("Ringsmall", 63228); - h.put("Rsmall", 63346); - h.put("S", 83); - h.put("SF010000", 9484); - h.put("SF020000", 9492); - h.put("SF030000", 9488); - h.put("SF040000", 9496); - h.put("SF050000", 9532); - h.put("SF060000", 9516); - h.put("SF070000", 9524); - h.put("SF080000", 9500); - h.put("SF090000", 9508); - h.put("SF100000", 9472); - h.put("SF110000", 9474); - h.put("SF190000", 9569); - h.put("SF200000", 9570); - h.put("SF210000", 9558); - h.put("SF220000", 9557); - h.put("SF230000", 9571); - h.put("SF240000", 9553); - h.put("SF250000", 9559); - h.put("SF260000", 9565); - h.put("SF270000", 9564); - h.put("SF280000", 9563); - h.put("SF360000", 9566); - h.put("SF370000", 9567); - h.put("SF380000", 9562); - h.put("SF390000", 9556); - h.put("SF400000", 9577); - h.put("SF410000", 9574); - h.put("SF420000", 9568); - h.put("SF430000", 9552); - h.put("SF440000", 9580); - h.put("SF450000", 9575); - h.put("SF460000", 9576); - h.put("SF470000", 9572); - h.put("SF480000", 9573); - h.put("SF490000", 9561); - h.put("SF500000", 9560); - h.put("SF510000", 9554); - h.put("SF520000", 9555); - h.put("SF530000", 9579); - h.put("SF540000", 9578); - h.put("Sacute", 346); - h.put("Scaron", 352); - h.put("Scaronsmall", 63229); - h.put("Scedilla", 350); - h.put("Scedilla", 63169); - h.put("Scircumflex", 348); - h.put("Scommaaccent", 536); - h.put("Sigma", 931); - h.put("Ssmall", 63347); - h.put("T", 84); - h.put("Tau", 932); - h.put("Tbar", 358); - h.put("Tcaron", 356); - h.put("Tcommaaccent", 354); - h.put("Tcommaaccent", 538); - h.put("Theta", 920); - h.put("Thorn", 222); - h.put("Thornsmall", 63486); - h.put("Tildesmall", 63230); - h.put("Tsmall", 63348); - h.put("U", 85); - h.put("Uacute", 218); - h.put("Uacutesmall", 63482); - h.put("Ubreve", 364); - h.put("Ucircumflex", 219); - h.put("Ucircumflexsmall", 63483); - h.put("Udieresis", 220); - h.put("Udieresissmall", 63484); - h.put("Ugrave", 217); - h.put("Ugravesmall", 63481); - h.put("Uhorn", 431); - h.put("Uhungarumlaut", 368); - h.put("Umacron", 362); - h.put("Uogonek", 370); - h.put("Upsilon", 933); - h.put("Upsilon1", 978); - h.put("Upsilondieresis", 939); - h.put("Upsilontonos", 910); - h.put("Uring", 366); - h.put("Usmall", 63349); - h.put("Utilde", 360); - h.put("V", 86); - h.put("Vsmall", 63350); - h.put("W", 87); - h.put("Wacute", 7810); - h.put("Wcircumflex", 372); - h.put("Wdieresis", 7812); - h.put("Wgrave", 7808); - h.put("Wsmall", 63351); - h.put("X", 88); - h.put("Xi", 926); - h.put("Xsmall", 63352); - h.put("Y", 89); - h.put("Yacute", 221); - h.put("Yacutesmall", 63485); - h.put("Ycircumflex", 374); - h.put("Ydieresis", 376); - h.put("Ydieresissmall", 63487); - h.put("Ygrave", 7922); - h.put("Ysmall", 63353); - h.put("Z", 90); - h.put("Zacute", 377); - h.put("Zcaron", 381); - h.put("Zcaronsmall", 63231); - h.put("Zdotaccent", 379); - h.put("Zeta", 918); - h.put("Zsmall", 63354); - h.put("a", 97); - h.put("aacute", 225); - h.put("abreve", 259); - h.put("acircumflex", 226); - h.put("acute", 180); - h.put("acutecomb", 769); - h.put("adieresis", 228); - h.put("ae", 230); - h.put("aeacute", 509); - h.put("afii00208", 8213); - h.put("afii10017", 1040); - h.put("afii10018", 1041); - h.put("afii10019", 1042); - h.put("afii10020", 1043); - h.put("afii10021", 1044); - h.put("afii10022", 1045); - h.put("afii10023", 1025); - h.put("afii10024", 1046); - h.put("afii10025", 1047); - h.put("afii10026", 1048); - h.put("afii10027", 1049); - h.put("afii10028", 1050); - h.put("afii10029", 1051); - h.put("afii10030", 1052); - h.put("afii10031", 1053); - h.put("afii10032", 1054); - h.put("afii10033", 1055); - h.put("afii10034", 1056); - h.put("afii10035", 1057); - h.put("afii10036", 1058); - h.put("afii10037", 1059); - h.put("afii10038", 1060); - h.put("afii10039", 1061); - h.put("afii10040", 1062); - h.put("afii10041", 1063); - h.put("afii10042", 1064); - h.put("afii10043", 1065); - h.put("afii10044", 1066); - h.put("afii10045", 1067); - h.put("afii10046", 1068); - h.put("afii10047", 1069); - h.put("afii10048", 1070); - h.put("afii10049", 1071); - h.put("afii10050", 1168); - h.put("afii10051", 1026); - h.put("afii10052", 1027); - h.put("afii10053", 1028); - h.put("afii10054", 1029); - h.put("afii10055", 1030); - h.put("afii10056", 1031); - h.put("afii10057", 1032); - h.put("afii10058", 1033); - h.put("afii10059", 1034); - h.put("afii10060", 1035); - h.put("afii10061", 1036); - h.put("afii10062", 1038); - h.put("afii10063", 63172); - h.put("afii10064", 63173); - h.put("afii10065", 1072); - h.put("afii10066", 1073); - h.put("afii10067", 1074); - h.put("afii10068", 1075); - h.put("afii10069", 1076); - h.put("afii10070", 1077); - h.put("afii10071", 1105); - h.put("afii10072", 1078); - h.put("afii10073", 1079); - h.put("afii10074", 1080); - h.put("afii10075", 1081); - h.put("afii10076", 1082); - h.put("afii10077", 1083); - h.put("afii10078", 1084); - h.put("afii10079", 1085); - h.put("afii10080", 1086); - h.put("afii10081", 1087); - h.put("afii10082", 1088); - h.put("afii10083", 1089); - h.put("afii10084", 1090); - h.put("afii10085", 1091); - h.put("afii10086", 1092); - h.put("afii10087", 1093); - h.put("afii10088", 1094); - h.put("afii10089", 1095); - h.put("afii10090", 1096); - h.put("afii10091", 1097); - h.put("afii10092", 1098); - h.put("afii10093", 1099); - h.put("afii10094", 1100); - h.put("afii10095", 1101); - h.put("afii10096", 1102); - h.put("afii10097", 1103); - h.put("afii10098", 1169); - h.put("afii10099", 1106); - h.put("afii10100", 1107); - h.put("afii10101", 1108); - h.put("afii10102", 1109); - h.put("afii10103", 1110); - h.put("afii10104", 1111); - h.put("afii10105", 1112); - h.put("afii10106", 1113); - h.put("afii10107", 1114); - h.put("afii10108", 1115); - h.put("afii10109", 1116); - h.put("afii10110", 1118); - h.put("afii10145", 1039); - h.put("afii10146", 1122); - h.put("afii10147", 1138); - h.put("afii10148", 1140); - h.put("afii10192", 63174); - h.put("afii10193", 1119); - h.put("afii10194", 1123); - h.put("afii10195", 1139); - h.put("afii10196", 1141); - h.put("afii10831", 63175); - h.put("afii10832", 63176); - h.put("afii10846", 1241); - h.put("afii299", 8206); - h.put("afii300", 8207); - h.put("afii301", 8205); - h.put("afii57381", 1642); - h.put("afii57388", 1548); - h.put("afii57392", 1632); - h.put("afii57393", 1633); - h.put("afii57394", 1634); - h.put("afii57395", 1635); - h.put("afii57396", 1636); - h.put("afii57397", 1637); - h.put("afii57398", 1638); - h.put("afii57399", 1639); - h.put("afii57400", 1640); - h.put("afii57401", 1641); - h.put("afii57403", 1563); - h.put("afii57407", 1567); - h.put("afii57409", 1569); - h.put("afii57410", 1570); - h.put("afii57411", 1571); - h.put("afii57412", 1572); - h.put("afii57413", 1573); - h.put("afii57414", 1574); - h.put("afii57415", 1575); - h.put("afii57416", 1576); - h.put("afii57417", 1577); - h.put("afii57418", 1578); - h.put("afii57419", 1579); - h.put("afii57420", 1580); - h.put("afii57421", 1581); - h.put("afii57422", 1582); - h.put("afii57423", 1583); - h.put("afii57424", 1584); - h.put("afii57425", 1585); - h.put("afii57426", 1586); - h.put("afii57427", 1587); - h.put("afii57428", 1588); - h.put("afii57429", 1589); - h.put("afii57430", 1590); - h.put("afii57431", 1591); - h.put("afii57432", 1592); - h.put("afii57433", 1593); - h.put("afii57434", 1594); - h.put("afii57440", 1600); - h.put("afii57441", 1601); - h.put("afii57442", 1602); - h.put("afii57443", 1603); - h.put("afii57444", 1604); - h.put("afii57445", 1605); - h.put("afii57446", 1606); - h.put("afii57448", 1608); - h.put("afii57449", 1609); - h.put("afii57450", 1610); - h.put("afii57451", 1611); - h.put("afii57452", 1612); - h.put("afii57453", 1613); - h.put("afii57454", 1614); - h.put("afii57455", 1615); - h.put("afii57456", 1616); - h.put("afii57457", 1617); - h.put("afii57458", 1618); - h.put("afii57470", 1607); - h.put("afii57505", 1700); - h.put("afii57506", 1662); - h.put("afii57507", 1670); - h.put("afii57508", 1688); - h.put("afii57509", 1711); - h.put("afii57511", 1657); - h.put("afii57512", 1672); - h.put("afii57513", 1681); - h.put("afii57514", 1722); - h.put("afii57519", 1746); - h.put("afii57534", 1749); - h.put("afii57636", 8362); - h.put("afii57645", 1470); - h.put("afii57658", 1475); - h.put("afii57664", 1488); - h.put("afii57665", 1489); - h.put("afii57666", 1490); - h.put("afii57667", 1491); - h.put("afii57668", 1492); - h.put("afii57669", 1493); - h.put("afii57670", 1494); - h.put("afii57671", 1495); - h.put("afii57672", 1496); - h.put("afii57673", 1497); - h.put("afii57674", 1498); - h.put("afii57675", 1499); - h.put("afii57676", 1500); - h.put("afii57677", 1501); - h.put("afii57678", 1502); - h.put("afii57679", 1503); - h.put("afii57680", 1504); - h.put("afii57681", 1505); - h.put("afii57682", 1506); - h.put("afii57683", 1507); - h.put("afii57684", 1508); - h.put("afii57685", 1509); - h.put("afii57686", 1510); - h.put("afii57687", 1511); - h.put("afii57688", 1512); - h.put("afii57689", 1513); - h.put("afii57690", 1514); - h.put("afii57694", 64298); - h.put("afii57695", 64299); - h.put("afii57700", 64331); - h.put("afii57705", 64287); - h.put("afii57716", 1520); - h.put("afii57717", 1521); - h.put("afii57718", 1522); - h.put("afii57723", 64309); - h.put("afii57793", 1460); - h.put("afii57794", 1461); - h.put("afii57795", 1462); - h.put("afii57796", 1467); - h.put("afii57797", 1464); - h.put("afii57798", 1463); - h.put("afii57799", 1456); - h.put("afii57800", 1458); - h.put("afii57801", 1457); - h.put("afii57802", 1459); - h.put("afii57803", 1474); - h.put("afii57804", 1473); - h.put("afii57806", 1465); - h.put("afii57807", 1468); - h.put("afii57839", 1469); - h.put("afii57841", 1471); - h.put("afii57842", 1472); - h.put("afii57929", 700); - h.put("afii61248", 8453); - h.put("afii61289", 8467); - h.put("afii61352", 8470); - h.put("afii61573", 8236); - h.put("afii61574", 8237); - h.put("afii61575", 8238); - h.put("afii61664", 8204); - h.put("afii63167", 1645); - h.put("afii64937", 701); - h.put("agrave", 224); - h.put("aleph", 8501); - h.put("alpha", 945); - h.put("alphatonos", 940); - h.put("amacron", 257); - h.put("ampersand", 38); - h.put("ampersandsmall", 63270); - h.put("angle", 8736); - h.put("angleleft", 9001); - h.put("angleright", 9002); - h.put("anoteleia", 903); - h.put("aogonek", 261); - h.put("approxequal", 8776); - h.put("aring", 229); - h.put("aringacute", 507); - h.put("arrowboth", 8596); - h.put("arrowdblboth", 8660); - h.put("arrowdbldown", 8659); - h.put("arrowdblleft", 8656); - h.put("arrowdblright", 8658); - h.put("arrowdblup", 8657); - h.put("arrowdown", 8595); - h.put("arrowhorizex", 63719); - h.put("arrowleft", 8592); - h.put("arrowright", 8594); - h.put("arrowup", 8593); - h.put("arrowupdn", 8597); - h.put("arrowupdnbse", 8616); - h.put("arrowvertex", 63718); - h.put("asciicircum", 94); - h.put("asciitilde", 126); - h.put("asterisk", 42); - h.put("asteriskmath", 8727); - h.put("asuperior", 63209); - h.put("at", 64); - h.put("atilde", 227); - h.put("b", 98); - h.put("backslash", 92); - h.put("bar", 124); - h.put("beta", 946); - h.put("block", 9608); - h.put("braceex", 63732); - h.put("braceleft", 123); - h.put("braceleftbt", 63731); - h.put("braceleftmid", 63730); - h.put("bracelefttp", 63729); - h.put("braceright", 125); - h.put("bracerightbt", 63742); - h.put("bracerightmid", 63741); - h.put("bracerighttp", 63740); - h.put("bracketleft", 91); - h.put("bracketleftbt", 63728); - h.put("bracketleftex", 63727); - h.put("bracketlefttp", 63726); - h.put("bracketright", 93); - h.put("bracketrightbt", 63739); - h.put("bracketrightex", 63738); - h.put("bracketrighttp", 63737); - h.put("breve", 728); - h.put("brokenbar", 166); - h.put("bsuperior", 63210); - h.put("bullet", 8226); - h.put("c", 99); - h.put("cacute", 263); - h.put("caron", 711); - h.put("carriagereturn", 8629); - h.put("ccaron", 269); - h.put("ccedilla", 231); - h.put("ccircumflex", 265); - h.put("cdotaccent", 267); - h.put("cedilla", 184); - h.put("cent", 162); - h.put("centinferior", 63199); - h.put("centoldstyle", 63394); - h.put("centsuperior", 63200); - h.put("chi", 967); - h.put("circle", 9675); - h.put("circlemultiply", 8855); - h.put("circleplus", 8853); - h.put("circumflex", 710); - h.put("club", 9827); - h.put("colon", 58); - h.put("colonmonetary", 8353); - h.put("comma", 44); - h.put("commaaccent", 63171); - h.put("commainferior", 63201); - h.put("commasuperior", 63202); - h.put("congruent", 8773); - h.put("copyright", 169); - h.put("copyrightsans", 63721); - h.put("copyrightserif", 63193); - h.put("currency", 164); - h.put("cyrBreve", 63185); - h.put("cyrFlex", 63186); - h.put("cyrbreve", 63188); - h.put("cyrflex", 63189); - h.put("d", 100); - h.put("dagger", 8224); - h.put("daggerdbl", 8225); - h.put("dblGrave", 63187); - h.put("dblgrave", 63190); - h.put("dcaron", 271); - h.put("dcroat", 273); - h.put("degree", 176); - h.put("delta", 948); - h.put("diamond", 9830); - h.put("dieresis", 168); - h.put("dieresisacute", 63191); - h.put("dieresisgrave", 63192); - h.put("dieresistonos", 901); - h.put("divide", 247); - h.put("dkshade", 9619); - h.put("dnblock", 9604); - h.put("dollar", 36); - h.put("dollarinferior", 63203); - h.put("dollaroldstyle", 63268); - h.put("dollarsuperior", 63204); - h.put("dong", 8363); - h.put("dotaccent", 729); - h.put("dotbelowcomb", 803); - h.put("dotlessi", 305); - h.put("dotlessj", 63166); - h.put("dotmath", 8901); - h.put("dsuperior", 63211); - h.put("e", 101); - h.put("eacute", 233); - h.put("ebreve", 277); - h.put("ecaron", 283); - h.put("ecircumflex", 234); - h.put("edieresis", 235); - h.put("edotaccent", 279); - h.put("egrave", 232); - h.put("eight", 56); - h.put("eightinferior", 8328); - h.put("eightoldstyle", 63288); - h.put("eightsuperior", 8312); - h.put("element", 8712); - h.put("ellipsis", 8230); - h.put("emacron", 275); - h.put("emdash", 8212); - h.put("emptyset", 8709); - h.put("endash", 8211); - h.put("eng", 331); - h.put("eogonek", 281); - h.put("epsilon", 949); - h.put("epsilontonos", 941); - h.put("equal", 61); - h.put("equivalence", 8801); - h.put("estimated", 8494); - h.put("esuperior", 63212); - h.put("eta", 951); - h.put("etatonos", 942); - h.put("eth", 240); - h.put("exclam", 33); - h.put("exclamdbl", 8252); - h.put("exclamdown", 161); - h.put("exclamdownsmall", 63393); - h.put("exclamsmall", 63265); - h.put("existential", 8707); - h.put("f", 102); - h.put("female", 9792); - h.put("ff", 64256); - h.put("ffi", 64259); - h.put("ffl", 64260); - h.put("fi", 64257); - h.put("figuredash", 8210); - h.put("filledbox", 9632); - h.put("filledrect", 9644); - h.put("five", 53); - h.put("fiveeighths", 8541); - h.put("fiveinferior", 8325); - h.put("fiveoldstyle", 63285); - h.put("fivesuperior", 8309); - h.put("fl", 64258); - h.put("florin", 402); - h.put("four", 52); - h.put("fourinferior", 8324); - h.put("fouroldstyle", 63284); - h.put("foursuperior", 8308); - h.put("fraction", 8260); - h.put("fraction", 8725); - h.put("franc", 8355); - h.put("g", 103); - h.put("gamma", 947); - h.put("gbreve", 287); - h.put("gcaron", 487); - h.put("gcircumflex", 285); - h.put("gcommaaccent", 291); - h.put("gdotaccent", 289); - h.put("germandbls", 223); - h.put("gradient", 8711); - h.put("grave", 96); - h.put("gravecomb", 768); - h.put("greater", 62); - h.put("greaterequal", 8805); - h.put("guillemotleft", 171); - h.put("guillemotright", 187); - h.put("guilsinglleft", 8249); - h.put("guilsinglright", 8250); - h.put("h", 104); - h.put("hbar", 295); - h.put("hcircumflex", 293); - h.put("heart", 9829); - h.put("hookabovecomb", 777); - h.put("house", 8962); - h.put("hungarumlaut", 733); - h.put("hyphen", 45); - //h.put("hyphen",173); - h.put("hypheninferior", 63205); - h.put("hyphensuperior", 63206); - h.put("i", 105); - h.put("iacute", 237); - h.put("ibreve", 301); - h.put("icircumflex", 238); - h.put("idieresis", 239); - h.put("igrave", 236); - h.put("ij", 307); - h.put("imacron", 299); - h.put("infinity", 8734); - h.put("integral", 8747); - h.put("integralbt", 8993); - h.put("integralex", 63733); - h.put("integraltp", 8992); - h.put("intersection", 8745); - h.put("invbullet", 9688); - h.put("invcircle", 9689); - h.put("invsmileface", 9787); - h.put("iogonek", 303); - h.put("iota", 953); - h.put("iotadieresis", 970); - h.put("iotadieresistonos", 912); - h.put("iotatonos", 943); - h.put("isuperior", 63213); - h.put("itilde", 297); - h.put("j", 106); - h.put("jcircumflex", 309); - h.put("k", 107); - h.put("kappa", 954); - h.put("kcommaaccent", 311); - h.put("kgreenlandic", 312); - h.put("l", 108); - h.put("lacute", 314); - h.put("lambda", 955); - h.put("lcaron", 318); - h.put("lcommaaccent", 316); - h.put("ldot", 320); - h.put("less", 60); - h.put("lessequal", 8804); - h.put("lfblock", 9612); - h.put("lira", 8356); - h.put("ll", 63168); - h.put("logicaland", 8743); - h.put("logicalnot", 172); - h.put("logicalor", 8744); - h.put("longs", 383); - h.put("lozenge", 9674); - h.put("lslash", 322); - h.put("lsuperior", 63214); - h.put("ltshade", 9617); - h.put("m", 109); - h.put("macron", 175); - //h.put("macron",713); - h.put("male", 9794); - h.put("minus", 8722); - h.put("minute", 8242); - h.put("msuperior", 63215); - h.put("mu", 181); - //h.put("mu",956); - h.put("multiply", 215); - h.put("musicalnote", 9834); - h.put("musicalnotedbl", 9835); - h.put("n", 110); - h.put("nacute", 324); - h.put("napostrophe", 329); - h.put("ncaron", 328); - h.put("ncommaaccent", 326); - h.put("nine", 57); - h.put("nineinferior", 8329); - h.put("nineoldstyle", 63289); - h.put("ninesuperior", 8313); - h.put("notelement", 8713); - h.put("notequal", 8800); - h.put("notsubset", 8836); - h.put("nsuperior", 8319); - h.put("ntilde", 241); - h.put("nu", 957); - h.put("numbersign", 35); - h.put("o", 111); - h.put("oacute", 243); - h.put("obreve", 335); - h.put("ocircumflex", 244); - h.put("odieresis", 246); - h.put("oe", 339); - h.put("ogonek", 731); - h.put("ograve", 242); - h.put("ohorn", 417); - h.put("ohungarumlaut", 337); - h.put("omacron", 333); - h.put("omega", 969); - h.put("omega1", 982); - h.put("omegatonos", 974); - h.put("omicron", 959); - h.put("omicrontonos", 972); - h.put("one", 49); - h.put("onedotenleader", 8228); - h.put("oneeighth", 8539); - h.put("onefitted", 63196); - h.put("onehalf", 189); - h.put("oneinferior", 8321); - h.put("oneoldstyle", 63281); - h.put("onequarter", 188); - h.put("onesuperior", 185); - h.put("onethird", 8531); - h.put("openbullet", 9702); - h.put("ordfeminine", 170); - h.put("ordmasculine", 186); - h.put("orthogonal", 8735); - h.put("oslash", 248); - h.put("oslashacute", 511); - h.put("osuperior", 63216); - h.put("otilde", 245); - h.put("p", 112); - h.put("paragraph", 182); - h.put("parenleft", 40); - h.put("parenleftbt", 63725); - h.put("parenleftex", 63724); - h.put("parenleftinferior", 8333); - h.put("parenleftsuperior", 8317); - h.put("parenlefttp", 63723); - h.put("parenright", 41); - h.put("parenrightbt", 63736); - h.put("parenrightex", 63735); - h.put("parenrightinferior", 8334); - h.put("parenrightsuperior", 8318); - h.put("parenrighttp", 63734); - h.put("partialdiff", 8706); - h.put("percent", 37); - h.put("period", 46); - h.put("periodcentered", 183); - h.put("periodcentered", 8729); - h.put("periodinferior", 63207); - h.put("periodsuperior", 63208); - h.put("perpendicular", 8869); - h.put("perthousand", 8240); - h.put("peseta", 8359); - h.put("phi", 966); - h.put("phi1", 981); - h.put("pi", 960); - h.put("plus", 43); - h.put("plusminus", 177); - h.put("prescription", 8478); - h.put("product", 8719); - h.put("propersubset", 8834); - h.put("propersuperset", 8835); - h.put("proportional", 8733); - h.put("psi", 968); - h.put("q", 113); - h.put("question", 63); - h.put("questiondown", 191); - h.put("questiondownsmall", 63423); - h.put("questionsmall", 63295); - h.put("quotedbl", 34); - h.put("quotedblbase", 8222); - h.put("quotedblleft", 8220); - h.put("quotedblright", 8221); - h.put("quoteleft", 8216); - h.put("quotereversed", 8219); - h.put("quoteright", 8217); - h.put("quotesinglbase", 8218); - h.put("quotesingle", 39); - h.put("r", 114); - h.put("racute", 341); - h.put("radical", 8730); - h.put("radicalex", 63717); - h.put("rcaron", 345); - h.put("rcommaaccent", 343); - h.put("reflexsubset", 8838); - h.put("reflexsuperset", 8839); - h.put("registered", 174); - h.put("registersans", 63720); - h.put("registerserif", 63194); - h.put("revlogicalnot", 8976); - h.put("rho", 961); - h.put("ring", 730); - h.put("rsuperior", 63217); - h.put("rtblock", 9616); - h.put("rupiah", 63197); - h.put("s", 115); - h.put("sacute", 347); - h.put("scaron", 353); - h.put("scedilla", 351); - h.put("scedilla", 63170); - h.put("scircumflex", 349); - h.put("scommaaccent", 537); - h.put("second", 8243); - h.put("section", 167); - h.put("semicolon", 59); - h.put("seven", 55); - h.put("seveneighths", 8542); - h.put("seveninferior", 8327); - h.put("sevenoldstyle", 63287); - h.put("sevensuperior", 8311); - h.put("shade", 9618); - h.put("sigma", 963); - h.put("sigma1", 962); - h.put("similar", 8764); - h.put("six", 54); - h.put("sixinferior", 8326); - h.put("sixoldstyle", 63286); - h.put("sixsuperior", 8310); - h.put("slash", 47); - h.put("smileface", 9786); - h.put("space", 32); - //h.put("space",160); - h.put("spade", 9824); - h.put("ssuperior", 63218); - h.put("sterling", 163); - h.put("suchthat", 8715); - h.put("summation", 8721); - h.put("sun", 9788); - h.put("t", 116); - h.put("tau", 964); - h.put("tbar", 359); - h.put("tcaron", 357); - h.put("tcommaaccent", 355); - h.put("tcommaaccent", 539); - h.put("therefore", 8756); - h.put("theta", 952); - h.put("theta1", 977); - h.put("thorn", 254); - h.put("three", 51); - h.put("threeeighths", 8540); - h.put("threeinferior", 8323); - h.put("threeoldstyle", 63283); - h.put("threequarters", 190); - h.put("threequartersemdash", 63198); - h.put("threesuperior", 179); - h.put("tilde", 732); - h.put("tildecomb", 771); - h.put("tonos", 900); - h.put("trademark", 8482); - h.put("trademarksans", 63722); - h.put("trademarkserif", 63195); - h.put("triagdn", 9660); - h.put("triaglf", 9668); - h.put("triagrt", 9658); - h.put("triagup", 9650); - h.put("tsuperior", 63219); - h.put("two", 50); - h.put("twodotenleader", 8229); - h.put("twoinferior", 8322); - h.put("twooldstyle", 63282); - h.put("twosuperior", 178); - h.put("twothirds", 8532); - h.put("u", 117); - h.put("uacute", 250); - h.put("ubreve", 365); - h.put("ucircumflex", 251); - h.put("udieresis", 252); - h.put("ugrave", 249); - h.put("uhorn", 432); - h.put("uhungarumlaut", 369); - h.put("umacron", 363); - h.put("underscore", 95); - h.put("underscoredbl", 8215); - h.put("union", 8746); - h.put("universal", 8704); - h.put("uogonek", 371); - h.put("upblock", 9600); - h.put("upsilon", 965); - h.put("upsilondieresis", 971); - h.put("upsilondieresistonos", 944); - h.put("upsilontonos", 973); - h.put("uring", 367); - h.put("utilde", 361); - h.put("v", 118); - h.put("w", 119); - h.put("wacute", 7811); - h.put("wcircumflex", 373); - h.put("wdieresis", 7813); - h.put("weierstrass", 8472); - h.put("wgrave", 7809); - h.put("x", 120); - h.put("xi", 958); - h.put("y", 121); - h.put("yacute", 253); - h.put("ycircumflex", 375); - h.put("ydieresis", 255); - h.put("yen", 165); - h.put("ygrave", 7923); - h.put("z", 122); - h.put("zacute", 378); - h.put("zcaron", 382); - h.put("zdotaccent", 380); - h.put("zero", 48); - h.put("zeroinferior", 8320); - h.put("zerooldstyle", 63280); - h.put("zerosuperior", 8304); - h.put("zeta", 950); - h.put("a1", 9985); - h.put("a2", 9986); - h.put("a202", 9987); - h.put("a3", 9988); - h.put("a4", 9742); - h.put("a5", 9990); - h.put("a119", 9991); - h.put("a118", 9992); - h.put("a117", 9993); - h.put("a11", 9755); - h.put("a12", 9758); - h.put("a13", 9996); - h.put("a14", 9997); - h.put("a15", 9998); - h.put("a16", 9999); - h.put("a105", 10000); - h.put("a17", 10001); - h.put("a18", 10002); - h.put("a19", 10003); - h.put("a20", 10004); - h.put("a21", 10005); - h.put("a22", 10006); - h.put("a23", 10007); - h.put("a24", 10008); - h.put("a25", 10009); - h.put("a26", 10010); - h.put("a27", 10011); - h.put("a28", 10012); - h.put("a6", 10013); - h.put("a7", 10014); - h.put("a8", 10015); - h.put("a9", 10016); - h.put("a10", 10017); - h.put("a29", 10018); - h.put("a30", 10019); - h.put("a31", 10020); - h.put("a32", 10021); - h.put("a33", 10022); - h.put("a34", 10023); - h.put("a35", 9733); - h.put("a36", 10025); - h.put("a37", 10026); - h.put("a38", 10027); - h.put("a39", 10028); - h.put("a40", 10029); - h.put("a41", 10030); - h.put("a42", 10031); - h.put("a43", 10032); - h.put("a44", 10033); - h.put("a45", 10034); - h.put("a46", 10035); - h.put("a47", 10036); - h.put("a48", 10037); - h.put("a49", 10038); - h.put("a50", 10039); - h.put("a51", 10040); - h.put("a52", 10041); - h.put("a53", 10042); - h.put("a54", 10043); - h.put("a55", 10044); - h.put("a56", 10045); - h.put("a57", 10046); - h.put("a58", 10047); - h.put("a59", 10048); - h.put("a60", 10049); - h.put("a61", 10050); - h.put("a62", 10051); - h.put("a63", 10052); - h.put("a64", 10053); - h.put("a65", 10054); - h.put("a66", 10055); - h.put("a67", 10056); - h.put("a68", 10057); - h.put("a69", 10058); - h.put("a70", 10059); - h.put("a71", 9679); - h.put("a72", 10061); - h.put("a73", 9632); - h.put("a74", 10063); - h.put("a203", 10064); - h.put("a75", 10065); - h.put("a204", 10066); - h.put("a76", 9650); - h.put("a77", 9660); - h.put("a78", 9670); - h.put("a79", 10070); - h.put("a81", 9687); - h.put("a82", 10072); - h.put("a83", 10073); - h.put("a84", 10074); - h.put("a97", 10075); - h.put("a98", 10076); - h.put("a99", 10077); - h.put("a100", 10078); - h.put("a89", 63703); - h.put("a90", 63704); - h.put("a93", 63705); - h.put("a94", 63706); - h.put("a91", 63707); - h.put("a92", 63708); - h.put("a205", 63709); - h.put("a85", 63710); - h.put("a206", 63711); - h.put("a86", 63712); - h.put("a87", 63713); - h.put("a88", 63714); - h.put("a95", 63715); - h.put("a96", 63716); - h.put("a101", 10081); - h.put("a102", 10082); - h.put("a103", 10083); - h.put("a104", 10084); - h.put("a106", 10085); - h.put("a107", 10086); - h.put("a108", 10087); - h.put("a112", 9827); - h.put("a111", 9830); - h.put("a110", 9829); - h.put("a109", 9824); - h.put("a120", 9312); - h.put("a121", 9313); - h.put("a122", 9314); - h.put("a123", 9315); - h.put("a124", 9316); - h.put("a125", 9317); - h.put("a126", 9318); - h.put("a127", 9319); - h.put("a128", 9320); - h.put("a129", 9321); - h.put("a130", 10102); - h.put("a131", 10103); - h.put("a132", 10104); - h.put("a133", 10105); - h.put("a134", 10106); - h.put("a135", 10107); - h.put("a136", 10108); - h.put("a137", 10109); - h.put("a138", 10110); - h.put("a139", 10111); - h.put("a140", 10112); - h.put("a141", 10113); - h.put("a142", 10114); - h.put("a143", 10115); - h.put("a144", 10116); - h.put("a145", 10117); - h.put("a146", 10118); - h.put("a147", 10119); - h.put("a148", 10120); - h.put("a149", 10121); - h.put("a150", 10122); - h.put("a151", 10123); - h.put("a152", 10124); - h.put("a153", 10125); - h.put("a154", 10126); - h.put("a155", 10127); - h.put("a156", 10128); - h.put("a157", 10129); - h.put("a158", 10130); - h.put("a159", 10131); - h.put("a160", 10132); - h.put("a161", 8594); - h.put("a163", 8596); - h.put("a164", 8597); - h.put("a196", 10136); - h.put("a165", 10137); - h.put("a192", 10138); - h.put("a166", 10139); - h.put("a167", 10140); - h.put("a168", 10141); - h.put("a169", 10142); - h.put("a170", 10143); - h.put("a171", 10144); - h.put("a172", 10145); - h.put("a173", 10146); - h.put("a162", 10147); - h.put("a174", 10148); - h.put("a175", 10149); - h.put("a176", 10150); - h.put("a177", 10151); - h.put("a178", 10152); - h.put("a179", 10153); - h.put("a193", 10154); - h.put("a180", 10155); - h.put("a199", 10156); - h.put("a181", 10157); - h.put("a200", 10158); - h.put("a182", 10159); - h.put("a201", 10161); - h.put("a183", 10162); - h.put("a184", 10163); - h.put("a197", 10164); - h.put("a185", 10165); - h.put("a194", 10166); - h.put("a198", 10167); - h.put("a186", 10168); - h.put("a195", 10169); - h.put("a187", 10170); - h.put("a188", 10171); - h.put("a189", 10172); - h.put("a190", 10173); - h.put("a191", 10174); - // UNKNOWN - h.put("apple", 32); - // END - se = new char[256]; - mre = new char[256]; - wae = new char[256]; - pde = new char[256]; - sym = new char[256]; - zap = new char[256]; - for (int i = 0; i < 256; i++) { - se[i] = '?'; - mre[i] = '?'; - wae[i] = '?'; - if (i > 040) { - wae[i] = (char) h.get("bullet").intValue(); - } - pde[i] = '?'; - sym[i] = '?'; - zap[i] = '?'; - } - pde[24] = (char) h.get("breve").intValue(); - pde[25] = (char) h.get("caron").intValue(); - pde[26] = (char) h.get("circumflex").intValue(); - pde[27] = (char) h.get("dotaccent").intValue(); - pde[28] = (char) h.get("hungarumlaut").intValue(); - pde[29] = (char) h.get("ogonek").intValue(); - pde[30] = (char) h.get("ring").intValue(); - pde[31] = (char) h.get("tilde").intValue(); - se[32] = (char) h.get("space").intValue(); - mre[32] = (char) h.get("space").intValue(); - wae[32] = (char) h.get("space").intValue(); - pde[32] = (char) h.get("space").intValue(); - se[33] = (char) h.get("exclam").intValue(); - mre[33] = (char) h.get("exclam").intValue(); - wae[33] = (char) h.get("exclam").intValue(); - pde[33] = (char) h.get("exclam").intValue(); - se[34] = (char) h.get("quotedbl").intValue(); - mre[34] = (char) h.get("quotedbl").intValue(); - wae[34] = (char) h.get("quotedbl").intValue(); - pde[34] = (char) h.get("quotedbl").intValue(); - se[35] = (char) h.get("numbersign").intValue(); - mre[35] = (char) h.get("numbersign").intValue(); - wae[35] = (char) h.get("numbersign").intValue(); - pde[35] = (char) h.get("numbersign").intValue(); - se[36] = (char) h.get("dollar").intValue(); - mre[36] = (char) h.get("dollar").intValue(); - wae[36] = (char) h.get("dollar").intValue(); - pde[36] = (char) h.get("dollar").intValue(); - se[37] = (char) h.get("percent").intValue(); - mre[37] = (char) h.get("percent").intValue(); - wae[37] = (char) h.get("percent").intValue(); - pde[37] = (char) h.get("percent").intValue(); - se[38] = (char) h.get("ampersand").intValue(); - mre[38] = (char) h.get("ampersand").intValue(); - wae[38] = (char) h.get("ampersand").intValue(); - pde[38] = (char) h.get("ampersand").intValue(); - se[39] = (char) h.get("quoteright").intValue(); - mre[39] = (char) h.get("quotesingle").intValue(); - wae[39] = (char) h.get("quotesingle").intValue(); - pde[39] = (char) h.get("quotesingle").intValue(); - se[40] = (char) h.get("parenleft").intValue(); - mre[40] = (char) h.get("parenleft").intValue(); - wae[40] = (char) h.get("parenleft").intValue(); - pde[40] = (char) h.get("parenleft").intValue(); - se[41] = (char) h.get("parenright").intValue(); - mre[41] = (char) h.get("parenright").intValue(); - wae[41] = (char) h.get("parenright").intValue(); - pde[41] = (char) h.get("parenright").intValue(); - se[42] = (char) h.get("asterisk").intValue(); - mre[42] = (char) h.get("asterisk").intValue(); - wae[42] = (char) h.get("asterisk").intValue(); - pde[42] = (char) h.get("asterisk").intValue(); - se[43] = (char) h.get("plus").intValue(); - mre[43] = (char) h.get("plus").intValue(); - wae[43] = (char) h.get("plus").intValue(); - pde[43] = (char) h.get("plus").intValue(); - se[44] = (char) h.get("comma").intValue(); - mre[44] = (char) h.get("comma").intValue(); - wae[44] = (char) h.get("comma").intValue(); - pde[44] = (char) h.get("comma").intValue(); - se[45] = (char) h.get("hyphen").intValue(); - mre[45] = (char) h.get("hyphen").intValue(); - wae[45] = (char) h.get("hyphen").intValue(); - pde[45] = (char) h.get("hyphen").intValue(); - se[46] = (char) h.get("period").intValue(); - mre[46] = (char) h.get("period").intValue(); - wae[46] = (char) h.get("period").intValue(); - pde[46] = (char) h.get("period").intValue(); - se[47] = (char) h.get("slash").intValue(); - mre[47] = (char) h.get("slash").intValue(); - wae[47] = (char) h.get("slash").intValue(); - pde[47] = (char) h.get("slash").intValue(); - se[48] = (char) h.get("zero").intValue(); - mre[48] = (char) h.get("zero").intValue(); - wae[48] = (char) h.get("zero").intValue(); - pde[48] = (char) h.get("zero").intValue(); - se[49] = (char) h.get("one").intValue(); - mre[49] = (char) h.get("one").intValue(); - wae[49] = (char) h.get("one").intValue(); - pde[49] = (char) h.get("one").intValue(); - se[50] = (char) h.get("two").intValue(); - mre[50] = (char) h.get("two").intValue(); - wae[50] = (char) h.get("two").intValue(); - pde[50] = (char) h.get("two").intValue(); - se[51] = (char) h.get("three").intValue(); - mre[51] = (char) h.get("three").intValue(); - wae[51] = (char) h.get("three").intValue(); - pde[51] = (char) h.get("three").intValue(); - se[52] = (char) h.get("four").intValue(); - mre[52] = (char) h.get("four").intValue(); - wae[52] = (char) h.get("four").intValue(); - pde[52] = (char) h.get("four").intValue(); - se[53] = (char) h.get("five").intValue(); - mre[53] = (char) h.get("five").intValue(); - wae[53] = (char) h.get("five").intValue(); - pde[53] = (char) h.get("five").intValue(); - se[54] = (char) h.get("six").intValue(); - mre[54] = (char) h.get("six").intValue(); - wae[54] = (char) h.get("six").intValue(); - pde[54] = (char) h.get("six").intValue(); - se[55] = (char) h.get("seven").intValue(); - mre[55] = (char) h.get("seven").intValue(); - wae[55] = (char) h.get("seven").intValue(); - pde[55] = (char) h.get("seven").intValue(); - se[56] = (char) h.get("eight").intValue(); - mre[56] = (char) h.get("eight").intValue(); - wae[56] = (char) h.get("eight").intValue(); - pde[56] = (char) h.get("eight").intValue(); - se[57] = (char) h.get("nine").intValue(); - mre[57] = (char) h.get("nine").intValue(); - wae[57] = (char) h.get("nine").intValue(); - pde[57] = (char) h.get("nine").intValue(); - se[58] = (char) h.get("colon").intValue(); - mre[58] = (char) h.get("colon").intValue(); - wae[58] = (char) h.get("colon").intValue(); - pde[58] = (char) h.get("colon").intValue(); - se[59] = (char) h.get("semicolon").intValue(); - mre[59] = (char) h.get("semicolon").intValue(); - wae[59] = (char) h.get("semicolon").intValue(); - pde[59] = (char) h.get("semicolon").intValue(); - se[60] = (char) h.get("less").intValue(); - mre[60] = (char) h.get("less").intValue(); - wae[60] = (char) h.get("less").intValue(); - pde[60] = (char) h.get("less").intValue(); - se[61] = (char) h.get("equal").intValue(); - mre[61] = (char) h.get("equal").intValue(); - wae[61] = (char) h.get("equal").intValue(); - pde[61] = (char) h.get("equal").intValue(); - se[62] = (char) h.get("greater").intValue(); - mre[62] = (char) h.get("greater").intValue(); - wae[62] = (char) h.get("greater").intValue(); - pde[62] = (char) h.get("greater").intValue(); - se[63] = (char) h.get("question").intValue(); - mre[63] = (char) h.get("question").intValue(); - wae[63] = (char) h.get("question").intValue(); - pde[63] = (char) h.get("question").intValue(); - se[64] = (char) h.get("at").intValue(); - mre[64] = (char) h.get("at").intValue(); - wae[64] = (char) h.get("at").intValue(); - pde[64] = (char) h.get("at").intValue(); - se[65] = (char) h.get("A").intValue(); - mre[65] = (char) h.get("A").intValue(); - wae[65] = (char) h.get("A").intValue(); - pde[65] = (char) h.get("A").intValue(); - se[66] = (char) h.get("B").intValue(); - mre[66] = (char) h.get("B").intValue(); - wae[66] = (char) h.get("B").intValue(); - pde[66] = (char) h.get("B").intValue(); - se[67] = (char) h.get("C").intValue(); - mre[67] = (char) h.get("C").intValue(); - wae[67] = (char) h.get("C").intValue(); - pde[67] = (char) h.get("C").intValue(); - se[68] = (char) h.get("D").intValue(); - mre[68] = (char) h.get("D").intValue(); - wae[68] = (char) h.get("D").intValue(); - pde[68] = (char) h.get("D").intValue(); - se[69] = (char) h.get("E").intValue(); - mre[69] = (char) h.get("E").intValue(); - wae[69] = (char) h.get("E").intValue(); - pde[69] = (char) h.get("E").intValue(); - se[70] = (char) h.get("F").intValue(); - mre[70] = (char) h.get("F").intValue(); - wae[70] = (char) h.get("F").intValue(); - pde[70] = (char) h.get("F").intValue(); - se[71] = (char) h.get("G").intValue(); - mre[71] = (char) h.get("G").intValue(); - wae[71] = (char) h.get("G").intValue(); - pde[71] = (char) h.get("G").intValue(); - se[72] = (char) h.get("H").intValue(); - mre[72] = (char) h.get("H").intValue(); - wae[72] = (char) h.get("H").intValue(); - pde[72] = (char) h.get("H").intValue(); - se[73] = (char) h.get("I").intValue(); - mre[73] = (char) h.get("I").intValue(); - wae[73] = (char) h.get("I").intValue(); - pde[73] = (char) h.get("I").intValue(); - se[74] = (char) h.get("J").intValue(); - mre[74] = (char) h.get("J").intValue(); - wae[74] = (char) h.get("J").intValue(); - pde[74] = (char) h.get("J").intValue(); - se[75] = (char) h.get("K").intValue(); - mre[75] = (char) h.get("K").intValue(); - wae[75] = (char) h.get("K").intValue(); - pde[75] = (char) h.get("K").intValue(); - se[76] = (char) h.get("L").intValue(); - mre[76] = (char) h.get("L").intValue(); - wae[76] = (char) h.get("L").intValue(); - pde[76] = (char) h.get("L").intValue(); - se[77] = (char) h.get("M").intValue(); - mre[77] = (char) h.get("M").intValue(); - wae[77] = (char) h.get("M").intValue(); - pde[77] = (char) h.get("M").intValue(); - se[78] = (char) h.get("N").intValue(); - mre[78] = (char) h.get("N").intValue(); - wae[78] = (char) h.get("N").intValue(); - pde[78] = (char) h.get("N").intValue(); - se[79] = (char) h.get("O").intValue(); - mre[79] = (char) h.get("O").intValue(); - wae[79] = (char) h.get("O").intValue(); - pde[79] = (char) h.get("O").intValue(); - se[80] = (char) h.get("P").intValue(); - mre[80] = (char) h.get("P").intValue(); - wae[80] = (char) h.get("P").intValue(); - pde[80] = (char) h.get("P").intValue(); - se[81] = (char) h.get("Q").intValue(); - mre[81] = (char) h.get("Q").intValue(); - wae[81] = (char) h.get("Q").intValue(); - pde[81] = (char) h.get("Q").intValue(); - se[82] = (char) h.get("R").intValue(); - mre[82] = (char) h.get("R").intValue(); - wae[82] = (char) h.get("R").intValue(); - pde[82] = (char) h.get("R").intValue(); - se[83] = (char) h.get("S").intValue(); - mre[83] = (char) h.get("S").intValue(); - wae[83] = (char) h.get("S").intValue(); - pde[83] = (char) h.get("S").intValue(); - se[84] = (char) h.get("T").intValue(); - mre[84] = (char) h.get("T").intValue(); - wae[84] = (char) h.get("T").intValue(); - pde[84] = (char) h.get("T").intValue(); - se[85] = (char) h.get("U").intValue(); - mre[85] = (char) h.get("U").intValue(); - wae[85] = (char) h.get("U").intValue(); - pde[85] = (char) h.get("U").intValue(); - se[86] = (char) h.get("V").intValue(); - mre[86] = (char) h.get("V").intValue(); - wae[86] = (char) h.get("V").intValue(); - pde[86] = (char) h.get("V").intValue(); - se[87] = (char) h.get("W").intValue(); - mre[87] = (char) h.get("W").intValue(); - wae[87] = (char) h.get("W").intValue(); - pde[87] = (char) h.get("W").intValue(); - se[88] = (char) h.get("X").intValue(); - mre[88] = (char) h.get("X").intValue(); - wae[88] = (char) h.get("X").intValue(); - pde[88] = (char) h.get("X").intValue(); - se[89] = (char) h.get("Y").intValue(); - mre[89] = (char) h.get("Y").intValue(); - wae[89] = (char) h.get("Y").intValue(); - pde[89] = (char) h.get("Y").intValue(); - se[90] = (char) h.get("Z").intValue(); - mre[90] = (char) h.get("Z").intValue(); - wae[90] = (char) h.get("Z").intValue(); - pde[90] = (char) h.get("Z").intValue(); - se[91] = (char) h.get("bracketleft").intValue(); - mre[91] = (char) h.get("bracketleft").intValue(); - wae[91] = (char) h.get("bracketleft").intValue(); - pde[91] = (char) h.get("bracketleft").intValue(); - se[92] = (char) h.get("backslash").intValue(); - mre[92] = (char) h.get("backslash").intValue(); - wae[92] = (char) h.get("backslash").intValue(); - pde[92] = (char) h.get("backslash").intValue(); - se[93] = (char) h.get("bracketright").intValue(); - mre[93] = (char) h.get("bracketright").intValue(); - wae[93] = (char) h.get("bracketright").intValue(); - pde[93] = (char) h.get("bracketright").intValue(); - se[94] = (char) h.get("asciicircum").intValue(); - mre[94] = (char) h.get("asciicircum").intValue(); - wae[94] = (char) h.get("asciicircum").intValue(); - pde[94] = (char) h.get("asciicircum").intValue(); - se[95] = (char) h.get("underscore").intValue(); - mre[95] = (char) h.get("underscore").intValue(); - wae[95] = (char) h.get("underscore").intValue(); - pde[95] = (char) h.get("underscore").intValue(); - se[96] = (char) h.get("quoteleft").intValue(); - mre[96] = (char) h.get("grave").intValue(); - wae[96] = (char) h.get("grave").intValue(); - pde[96] = (char) h.get("grave").intValue(); - se[97] = (char) h.get("a").intValue(); - mre[97] = (char) h.get("a").intValue(); - wae[97] = (char) h.get("a").intValue(); - pde[97] = (char) h.get("a").intValue(); - se[98] = (char) h.get("b").intValue(); - mre[98] = (char) h.get("b").intValue(); - wae[98] = (char) h.get("b").intValue(); - pde[98] = (char) h.get("b").intValue(); - se[99] = (char) h.get("c").intValue(); - mre[99] = (char) h.get("c").intValue(); - wae[99] = (char) h.get("c").intValue(); - pde[99] = (char) h.get("c").intValue(); - se[100] = (char) h.get("d").intValue(); - mre[100] = (char) h.get("d").intValue(); - wae[100] = (char) h.get("d").intValue(); - pde[100] = (char) h.get("d").intValue(); - se[101] = (char) h.get("e").intValue(); - mre[101] = (char) h.get("e").intValue(); - wae[101] = (char) h.get("e").intValue(); - pde[101] = (char) h.get("e").intValue(); - se[102] = (char) h.get("f").intValue(); - mre[102] = (char) h.get("f").intValue(); - wae[102] = (char) h.get("f").intValue(); - pde[102] = (char) h.get("f").intValue(); - se[103] = (char) h.get("g").intValue(); - mre[103] = (char) h.get("g").intValue(); - wae[103] = (char) h.get("g").intValue(); - pde[103] = (char) h.get("g").intValue(); - se[104] = (char) h.get("h").intValue(); - mre[104] = (char) h.get("h").intValue(); - wae[104] = (char) h.get("h").intValue(); - pde[104] = (char) h.get("h").intValue(); - se[105] = (char) h.get("i").intValue(); - mre[105] = (char) h.get("i").intValue(); - wae[105] = (char) h.get("i").intValue(); - pde[105] = (char) h.get("i").intValue(); - se[106] = (char) h.get("j").intValue(); - mre[106] = (char) h.get("j").intValue(); - wae[106] = (char) h.get("j").intValue(); - pde[106] = (char) h.get("j").intValue(); - se[107] = (char) h.get("k").intValue(); - mre[107] = (char) h.get("k").intValue(); - wae[107] = (char) h.get("k").intValue(); - pde[107] = (char) h.get("k").intValue(); - se[108] = (char) h.get("l").intValue(); - mre[108] = (char) h.get("l").intValue(); - wae[108] = (char) h.get("l").intValue(); - pde[108] = (char) h.get("l").intValue(); - se[109] = (char) h.get("m").intValue(); - mre[109] = (char) h.get("m").intValue(); - wae[109] = (char) h.get("m").intValue(); - pde[109] = (char) h.get("m").intValue(); - se[110] = (char) h.get("n").intValue(); - mre[110] = (char) h.get("n").intValue(); - wae[110] = (char) h.get("n").intValue(); - pde[110] = (char) h.get("n").intValue(); - se[111] = (char) h.get("o").intValue(); - mre[111] = (char) h.get("o").intValue(); - wae[111] = (char) h.get("o").intValue(); - pde[111] = (char) h.get("o").intValue(); - se[112] = (char) h.get("p").intValue(); - mre[112] = (char) h.get("p").intValue(); - wae[112] = (char) h.get("p").intValue(); - pde[112] = (char) h.get("p").intValue(); - se[113] = (char) h.get("q").intValue(); - mre[113] = (char) h.get("q").intValue(); - wae[113] = (char) h.get("q").intValue(); - pde[113] = (char) h.get("q").intValue(); - se[114] = (char) h.get("r").intValue(); - mre[114] = (char) h.get("r").intValue(); - wae[114] = (char) h.get("r").intValue(); - pde[114] = (char) h.get("r").intValue(); - se[115] = (char) h.get("s").intValue(); - mre[115] = (char) h.get("s").intValue(); - wae[115] = (char) h.get("s").intValue(); - pde[115] = (char) h.get("s").intValue(); - se[116] = (char) h.get("t").intValue(); - mre[116] = (char) h.get("t").intValue(); - wae[116] = (char) h.get("t").intValue(); - pde[116] = (char) h.get("t").intValue(); - se[117] = (char) h.get("u").intValue(); - mre[117] = (char) h.get("u").intValue(); - wae[117] = (char) h.get("u").intValue(); - pde[117] = (char) h.get("u").intValue(); - se[118] = (char) h.get("v").intValue(); - mre[118] = (char) h.get("v").intValue(); - wae[118] = (char) h.get("v").intValue(); - pde[118] = (char) h.get("v").intValue(); - se[119] = (char) h.get("w").intValue(); - mre[119] = (char) h.get("w").intValue(); - wae[119] = (char) h.get("w").intValue(); - pde[119] = (char) h.get("w").intValue(); - se[120] = (char) h.get("x").intValue(); - mre[120] = (char) h.get("x").intValue(); - wae[120] = (char) h.get("x").intValue(); - pde[120] = (char) h.get("x").intValue(); - se[121] = (char) h.get("y").intValue(); - mre[121] = (char) h.get("y").intValue(); - wae[121] = (char) h.get("y").intValue(); - pde[121] = (char) h.get("y").intValue(); - se[122] = (char) h.get("z").intValue(); - mre[122] = (char) h.get("z").intValue(); - wae[122] = (char) h.get("z").intValue(); - pde[122] = (char) h.get("z").intValue(); - se[123] = (char) h.get("braceleft").intValue(); - mre[123] = (char) h.get("braceleft").intValue(); - wae[123] = (char) h.get("braceleft").intValue(); - pde[123] = (char) h.get("braceleft").intValue(); - se[124] = (char) h.get("bar").intValue(); - mre[124] = (char) h.get("bar").intValue(); - wae[124] = (char) h.get("bar").intValue(); - pde[124] = (char) h.get("bar").intValue(); - se[125] = (char) h.get("braceright").intValue(); - mre[125] = (char) h.get("braceright").intValue(); - wae[125] = (char) h.get("braceright").intValue(); - pde[125] = (char) h.get("braceright").intValue(); - se[126] = (char) h.get("asciitilde").intValue(); - mre[126] = (char) h.get("asciitilde").intValue(); - wae[126] = (char) h.get("asciitilde").intValue(); - pde[126] = (char) h.get("asciitilde").intValue(); - wae[127] = (char) h.get("bullet").intValue(); - mre[128] = (char) h.get("Adieresis").intValue(); - wae[128] = (char) h.get("Euro").intValue(); - pde[128] = (char) h.get("bullet").intValue(); - mre[129] = (char) h.get("Aring").intValue(); - wae[129] = (char) h.get("bullet").intValue(); - pde[129] = (char) h.get("dagger").intValue(); - mre[130] = (char) h.get("Ccedilla").intValue(); - wae[130] = (char) h.get("quotesinglbase").intValue(); - pde[130] = (char) h.get("daggerdbl").intValue(); - mre[131] = (char) h.get("Eacute").intValue(); - wae[131] = (char) h.get("florin").intValue(); - pde[131] = (char) h.get("ellipsis").intValue(); - mre[132] = (char) h.get("Ntilde").intValue(); - wae[132] = (char) h.get("quotedblbase").intValue(); - pde[132] = (char) h.get("emdash").intValue(); - mre[133] = (char) h.get("Odieresis").intValue(); - wae[133] = (char) h.get("ellipsis").intValue(); - pde[133] = (char) h.get("endash").intValue(); - mre[134] = (char) h.get("Udieresis").intValue(); - wae[134] = (char) h.get("dagger").intValue(); - pde[134] = (char) h.get("florin").intValue(); - mre[135] = (char) h.get("aacute").intValue(); - wae[135] = (char) h.get("daggerdbl").intValue(); - pde[135] = (char) h.get("fraction").intValue(); - mre[136] = (char) h.get("agrave").intValue(); - wae[136] = (char) h.get("circumflex").intValue(); - pde[136] = (char) h.get("guilsinglleft").intValue(); - mre[137] = (char) h.get("acircumflex").intValue(); - wae[137] = (char) h.get("perthousand").intValue(); - pde[137] = (char) h.get("guilsinglright").intValue(); - mre[138] = (char) h.get("adieresis").intValue(); - wae[138] = (char) h.get("Scaron").intValue(); - pde[138] = (char) h.get("minus").intValue(); - mre[139] = (char) h.get("atilde").intValue(); - wae[139] = (char) h.get("guilsinglleft").intValue(); - pde[139] = (char) h.get("perthousand").intValue(); - mre[140] = (char) h.get("aring").intValue(); - wae[140] = (char) h.get("OE").intValue(); - pde[140] = (char) h.get("quotedblbase").intValue(); - mre[141] = (char) h.get("ccedilla").intValue(); - wae[141] = (char) h.get("bullet").intValue(); - pde[141] = (char) h.get("quotedblleft").intValue(); - mre[142] = (char) h.get("eacute").intValue(); - wae[142] = (char) h.get("Zcaron").intValue(); - pde[142] = (char) h.get("quotedblright").intValue(); - mre[143] = (char) h.get("egrave").intValue(); - wae[143] = (char) h.get("bullet").intValue(); - pde[143] = (char) h.get("quoteleft").intValue(); - mre[144] = (char) h.get("ecircumflex").intValue(); - wae[144] = (char) h.get("bullet").intValue(); - pde[144] = (char) h.get("quoteright").intValue(); - mre[145] = (char) h.get("edieresis").intValue(); - wae[145] = (char) h.get("quoteleft").intValue(); - pde[145] = (char) h.get("quotesinglbase").intValue(); - mre[146] = (char) h.get("iacute").intValue(); - wae[146] = (char) h.get("quoteright").intValue(); - pde[146] = (char) h.get("trademark").intValue(); - mre[147] = (char) h.get("igrave").intValue(); - wae[147] = (char) h.get("quotedblleft").intValue(); - pde[147] = (char) h.get("fi").intValue(); - mre[148] = (char) h.get("icircumflex").intValue(); - wae[148] = (char) h.get("quotedblright").intValue(); - pde[148] = (char) h.get("fl").intValue(); - mre[149] = (char) h.get("idieresis").intValue(); - wae[149] = (char) h.get("bullet").intValue(); - pde[149] = (char) h.get("Lslash").intValue(); - mre[150] = (char) h.get("ntilde").intValue(); - wae[150] = (char) h.get("endash").intValue(); - pde[150] = (char) h.get("OE").intValue(); - mre[151] = (char) h.get("oacute").intValue(); - wae[151] = (char) h.get("emdash").intValue(); - pde[151] = (char) h.get("Scaron").intValue(); - mre[152] = (char) h.get("ograve").intValue(); - wae[152] = (char) h.get("tilde").intValue(); - pde[152] = (char) h.get("Ydieresis").intValue(); - mre[153] = (char) h.get("ocircumflex").intValue(); - wae[153] = (char) h.get("trademark").intValue(); - pde[153] = (char) h.get("Zcaron").intValue(); - mre[154] = (char) h.get("odieresis").intValue(); - wae[154] = (char) h.get("scaron").intValue(); - pde[154] = (char) h.get("dotlessi").intValue(); - mre[155] = (char) h.get("otilde").intValue(); - wae[155] = (char) h.get("guilsinglright").intValue(); - pde[155] = (char) h.get("lslash").intValue(); - mre[156] = (char) h.get("uacute").intValue(); - wae[156] = (char) h.get("oe").intValue(); - pde[156] = (char) h.get("oe").intValue(); - mre[157] = (char) h.get("ugrave").intValue(); - wae[157] = (char) h.get("bullet").intValue(); - pde[157] = (char) h.get("scaron").intValue(); - mre[158] = (char) h.get("ucircumflex").intValue(); - wae[158] = (char) h.get("zcaron").intValue(); - pde[158] = (char) h.get("zcaron").intValue(); - mre[159] = (char) h.get("udieresis").intValue(); - wae[159] = (char) h.get("Ydieresis").intValue(); - mre[160] = (char) h.get("dagger").intValue(); - wae[160] = (char) h.get("space").intValue(); - pde[160] = (char) h.get("Euro").intValue(); - se[161] = (char) h.get("exclamdown").intValue(); - mre[161] = (char) h.get("degree").intValue(); - wae[161] = (char) h.get("exclamdown").intValue(); - pde[161] = (char) h.get("exclamdown").intValue(); - se[162] = (char) h.get("cent").intValue(); - mre[162] = (char) h.get("cent").intValue(); - wae[162] = (char) h.get("cent").intValue(); - pde[162] = (char) h.get("cent").intValue(); - se[163] = (char) h.get("sterling").intValue(); - mre[163] = (char) h.get("sterling").intValue(); - wae[163] = (char) h.get("sterling").intValue(); - pde[163] = (char) h.get("sterling").intValue(); - se[164] = (char) h.get("fraction").intValue(); - mre[164] = (char) h.get("section").intValue(); - wae[164] = (char) h.get("currency").intValue(); - pde[164] = (char) h.get("currency").intValue(); - se[165] = (char) h.get("yen").intValue(); - mre[165] = (char) h.get("bullet").intValue(); - wae[165] = (char) h.get("yen").intValue(); - pde[165] = (char) h.get("yen").intValue(); - se[166] = (char) h.get("florin").intValue(); - mre[166] = (char) h.get("paragraph").intValue(); - wae[166] = (char) h.get("brokenbar").intValue(); - pde[166] = (char) h.get("brokenbar").intValue(); - se[167] = (char) h.get("section").intValue(); - mre[167] = (char) h.get("germandbls").intValue(); - wae[167] = (char) h.get("section").intValue(); - pde[167] = (char) h.get("section").intValue(); - se[168] = (char) h.get("currency").intValue(); - mre[168] = (char) h.get("registered").intValue(); - wae[168] = (char) h.get("dieresis").intValue(); - pde[168] = (char) h.get("dieresis").intValue(); - se[169] = (char) h.get("quotesingle").intValue(); - mre[169] = (char) h.get("copyright").intValue(); - wae[169] = (char) h.get("copyright").intValue(); - pde[169] = (char) h.get("copyright").intValue(); - se[170] = (char) h.get("quotedblleft").intValue(); - mre[170] = (char) h.get("trademark").intValue(); - wae[170] = (char) h.get("ordfeminine").intValue(); - pde[170] = (char) h.get("ordfeminine").intValue(); - se[171] = (char) h.get("guillemotleft").intValue(); - mre[171] = (char) h.get("acute").intValue(); - wae[171] = (char) h.get("guillemotleft").intValue(); - pde[171] = (char) h.get("guillemotleft").intValue(); - se[172] = (char) h.get("guilsinglleft").intValue(); - mre[172] = (char) h.get("dieresis").intValue(); - wae[172] = (char) h.get("logicalnot").intValue(); - pde[172] = (char) h.get("logicalnot").intValue(); - se[173] = (char) h.get("guilsinglright").intValue(); - wae[173] = (char) h.get("hyphen").intValue(); - se[174] = (char) h.get("fi").intValue(); - mre[174] = (char) h.get("AE").intValue(); - wae[174] = (char) h.get("registered").intValue(); - pde[174] = (char) h.get("registered").intValue(); - se[175] = (char) h.get("fl").intValue(); - mre[175] = (char) h.get("Oslash").intValue(); - wae[175] = (char) h.get("macron").intValue(); - pde[175] = (char) h.get("macron").intValue(); - wae[176] = (char) h.get("degree").intValue(); - pde[176] = (char) h.get("degree").intValue(); - se[177] = (char) h.get("endash").intValue(); - mre[177] = (char) h.get("plusminus").intValue(); - wae[177] = (char) h.get("plusminus").intValue(); - pde[177] = (char) h.get("plusminus").intValue(); - se[178] = (char) h.get("dagger").intValue(); - wae[178] = (char) h.get("twosuperior").intValue(); - pde[178] = (char) h.get("twosuperior").intValue(); - se[179] = (char) h.get("daggerdbl").intValue(); - wae[179] = (char) h.get("threesuperior").intValue(); - pde[179] = (char) h.get("threesuperior").intValue(); - se[180] = (char) h.get("periodcentered").intValue(); - mre[180] = (char) h.get("yen").intValue(); - wae[180] = (char) h.get("acute").intValue(); - pde[180] = (char) h.get("acute").intValue(); - mre[181] = (char) h.get("mu").intValue(); - wae[181] = (char) h.get("mu").intValue(); - pde[181] = (char) h.get("mu").intValue(); - se[182] = (char) h.get("paragraph").intValue(); - wae[182] = (char) h.get("paragraph").intValue(); - pde[182] = (char) h.get("paragraph").intValue(); - se[183] = (char) h.get("bullet").intValue(); - wae[183] = (char) h.get("periodcentered").intValue(); - pde[183] = (char) h.get("periodcentered").intValue(); - se[184] = (char) h.get("quotesinglbase").intValue(); - wae[184] = (char) h.get("cedilla").intValue(); - pde[184] = (char) h.get("cedilla").intValue(); - se[185] = (char) h.get("quotedblbase").intValue(); - wae[185] = (char) h.get("onesuperior").intValue(); - pde[185] = (char) h.get("onesuperior").intValue(); - se[186] = (char) h.get("quotedblright").intValue(); - wae[186] = (char) h.get("ordmasculine").intValue(); - pde[186] = (char) h.get("ordmasculine").intValue(); - se[187] = (char) h.get("guillemotright").intValue(); - mre[187] = (char) h.get("ordfeminine").intValue(); - wae[187] = (char) h.get("guillemotright").intValue(); - pde[187] = (char) h.get("guillemotright").intValue(); - se[188] = (char) h.get("ellipsis").intValue(); - mre[188] = (char) h.get("ordmasculine").intValue(); - wae[188] = (char) h.get("onequarter").intValue(); - pde[188] = (char) h.get("onequarter").intValue(); - se[189] = (char) h.get("perthousand").intValue(); - wae[189] = (char) h.get("onehalf").intValue(); - pde[189] = (char) h.get("onehalf").intValue(); - mre[190] = (char) h.get("ae").intValue(); - wae[190] = (char) h.get("threequarters").intValue(); - pde[190] = (char) h.get("threequarters").intValue(); - se[191] = (char) h.get("questiondown").intValue(); - mre[191] = (char) h.get("oslash").intValue(); - wae[191] = (char) h.get("questiondown").intValue(); - pde[191] = (char) h.get("questiondown").intValue(); - mre[192] = (char) h.get("questiondown").intValue(); - wae[192] = (char) h.get("Agrave").intValue(); - pde[192] = (char) h.get("Agrave").intValue(); - se[193] = (char) h.get("grave").intValue(); - mre[193] = (char) h.get("exclamdown").intValue(); - wae[193] = (char) h.get("Aacute").intValue(); - pde[193] = (char) h.get("Aacute").intValue(); - se[194] = (char) h.get("acute").intValue(); - mre[194] = (char) h.get("logicalnot").intValue(); - wae[194] = (char) h.get("Acircumflex").intValue(); - pde[194] = (char) h.get("Acircumflex").intValue(); - se[195] = (char) h.get("circumflex").intValue(); - wae[195] = (char) h.get("Atilde").intValue(); - pde[195] = (char) h.get("Atilde").intValue(); - se[196] = (char) h.get("tilde").intValue(); - mre[196] = (char) h.get("florin").intValue(); - wae[196] = (char) h.get("Adieresis").intValue(); - pde[196] = (char) h.get("Adieresis").intValue(); - se[197] = (char) h.get("macron").intValue(); - wae[197] = (char) h.get("Aring").intValue(); - pde[197] = (char) h.get("Aring").intValue(); - se[198] = (char) h.get("breve").intValue(); - wae[198] = (char) h.get("AE").intValue(); - pde[198] = (char) h.get("AE").intValue(); - se[199] = (char) h.get("dotaccent").intValue(); - mre[199] = (char) h.get("guillemotleft").intValue(); - wae[199] = (char) h.get("Ccedilla").intValue(); - pde[199] = (char) h.get("Ccedilla").intValue(); - se[200] = (char) h.get("dieresis").intValue(); - mre[200] = (char) h.get("guillemotright").intValue(); - wae[200] = (char) h.get("Egrave").intValue(); - pde[200] = (char) h.get("Egrave").intValue(); - mre[201] = (char) h.get("ellipsis").intValue(); - wae[201] = (char) h.get("Eacute").intValue(); - pde[201] = (char) h.get("Eacute").intValue(); - se[202] = (char) h.get("ring").intValue(); - mre[202] = (char) h.get("space").intValue(); - wae[202] = (char) h.get("Ecircumflex").intValue(); - pde[202] = (char) h.get("Ecircumflex").intValue(); - se[203] = (char) h.get("cedilla").intValue(); - mre[203] = (char) h.get("Agrave").intValue(); - wae[203] = (char) h.get("Edieresis").intValue(); - pde[203] = (char) h.get("Edieresis").intValue(); - mre[204] = (char) h.get("Atilde").intValue(); - wae[204] = (char) h.get("Igrave").intValue(); - pde[204] = (char) h.get("Igrave").intValue(); - se[205] = (char) h.get("hungarumlaut").intValue(); - mre[205] = (char) h.get("Otilde").intValue(); - wae[205] = (char) h.get("Iacute").intValue(); - pde[205] = (char) h.get("Iacute").intValue(); - se[206] = (char) h.get("ogonek").intValue(); - mre[206] = (char) h.get("OE").intValue(); - wae[206] = (char) h.get("Icircumflex").intValue(); - pde[206] = (char) h.get("Icircumflex").intValue(); - se[207] = (char) h.get("caron").intValue(); - mre[207] = (char) h.get("oe").intValue(); - wae[207] = (char) h.get("Idieresis").intValue(); - pde[207] = (char) h.get("Idieresis").intValue(); - se[208] = (char) h.get("emdash").intValue(); - mre[208] = (char) h.get("endash").intValue(); - wae[208] = (char) h.get("Eth").intValue(); - pde[208] = (char) h.get("Eth").intValue(); - mre[209] = (char) h.get("emdash").intValue(); - wae[209] = (char) h.get("Ntilde").intValue(); - pde[209] = (char) h.get("Ntilde").intValue(); - mre[210] = (char) h.get("quotedblleft").intValue(); - wae[210] = (char) h.get("Ograve").intValue(); - pde[210] = (char) h.get("Ograve").intValue(); - mre[211] = (char) h.get("quotedblright").intValue(); - wae[211] = (char) h.get("Oacute").intValue(); - pde[211] = (char) h.get("Oacute").intValue(); - mre[212] = (char) h.get("quoteleft").intValue(); - wae[212] = (char) h.get("Ocircumflex").intValue(); - pde[212] = (char) h.get("Ocircumflex").intValue(); - mre[213] = (char) h.get("quoteright").intValue(); - wae[213] = (char) h.get("Otilde").intValue(); - pde[213] = (char) h.get("Otilde").intValue(); - mre[214] = (char) h.get("divide").intValue(); - wae[214] = (char) h.get("Odieresis").intValue(); - pde[214] = (char) h.get("Odieresis").intValue(); - wae[215] = (char) h.get("multiply").intValue(); - pde[215] = (char) h.get("multiply").intValue(); - mre[216] = (char) h.get("ydieresis").intValue(); - wae[216] = (char) h.get("Oslash").intValue(); - pde[216] = (char) h.get("Oslash").intValue(); - mre[217] = (char) h.get("Ydieresis").intValue(); - wae[217] = (char) h.get("Ugrave").intValue(); - pde[217] = (char) h.get("Ugrave").intValue(); - mre[218] = (char) h.get("fraction").intValue(); - wae[218] = (char) h.get("Uacute").intValue(); - pde[218] = (char) h.get("Uacute").intValue(); - mre[219] = (char) h.get("currency").intValue(); - wae[219] = (char) h.get("Ucircumflex").intValue(); - pde[219] = (char) h.get("Ucircumflex").intValue(); - mre[220] = (char) h.get("guilsinglleft").intValue(); - wae[220] = (char) h.get("Udieresis").intValue(); - pde[220] = (char) h.get("Udieresis").intValue(); - mre[221] = (char) h.get("guilsinglright").intValue(); - wae[221] = (char) h.get("Yacute").intValue(); - pde[221] = (char) h.get("Yacute").intValue(); - mre[222] = (char) h.get("fi").intValue(); - wae[222] = (char) h.get("Thorn").intValue(); - pde[222] = (char) h.get("Thorn").intValue(); - mre[223] = (char) h.get("fl").intValue(); - wae[223] = (char) h.get("germandbls").intValue(); - pde[223] = (char) h.get("germandbls").intValue(); - mre[224] = (char) h.get("daggerdbl").intValue(); - wae[224] = (char) h.get("agrave").intValue(); - pde[224] = (char) h.get("agrave").intValue(); - se[225] = (char) h.get("AE").intValue(); - mre[225] = (char) h.get("periodcentered").intValue(); - wae[225] = (char) h.get("aacute").intValue(); - pde[225] = (char) h.get("aacute").intValue(); - mre[226] = (char) h.get("quotesinglbase").intValue(); - wae[226] = (char) h.get("acircumflex").intValue(); - pde[226] = (char) h.get("acircumflex").intValue(); - se[227] = (char) h.get("ordfeminine").intValue(); - mre[227] = (char) h.get("quotedblbase").intValue(); - wae[227] = (char) h.get("atilde").intValue(); - pde[227] = (char) h.get("atilde").intValue(); - mre[228] = (char) h.get("perthousand").intValue(); - wae[228] = (char) h.get("adieresis").intValue(); - pde[228] = (char) h.get("adieresis").intValue(); - mre[229] = (char) h.get("Acircumflex").intValue(); - wae[229] = (char) h.get("aring").intValue(); - pde[229] = (char) h.get("aring").intValue(); - mre[230] = (char) h.get("Ecircumflex").intValue(); - wae[230] = (char) h.get("ae").intValue(); - pde[230] = (char) h.get("ae").intValue(); - mre[231] = (char) h.get("Aacute").intValue(); - wae[231] = (char) h.get("ccedilla").intValue(); - pde[231] = (char) h.get("ccedilla").intValue(); - se[232] = (char) h.get("Lslash").intValue(); - mre[232] = (char) h.get("Edieresis").intValue(); - wae[232] = (char) h.get("egrave").intValue(); - pde[232] = (char) h.get("egrave").intValue(); - se[233] = (char) h.get("Oslash").intValue(); - mre[233] = (char) h.get("Egrave").intValue(); - wae[233] = (char) h.get("eacute").intValue(); - pde[233] = (char) h.get("eacute").intValue(); - se[234] = (char) h.get("OE").intValue(); - mre[234] = (char) h.get("Iacute").intValue(); - wae[234] = (char) h.get("ecircumflex").intValue(); - pde[234] = (char) h.get("ecircumflex").intValue(); - se[235] = (char) h.get("ordmasculine").intValue(); - mre[235] = (char) h.get("Icircumflex").intValue(); - wae[235] = (char) h.get("edieresis").intValue(); - pde[235] = (char) h.get("edieresis").intValue(); - mre[236] = (char) h.get("Idieresis").intValue(); - wae[236] = (char) h.get("igrave").intValue(); - pde[236] = (char) h.get("igrave").intValue(); - mre[237] = (char) h.get("Igrave").intValue(); - wae[237] = (char) h.get("iacute").intValue(); - pde[237] = (char) h.get("iacute").intValue(); - mre[238] = (char) h.get("Oacute").intValue(); - wae[238] = (char) h.get("icircumflex").intValue(); - pde[238] = (char) h.get("icircumflex").intValue(); - mre[239] = (char) h.get("Ocircumflex").intValue(); - wae[239] = (char) h.get("idieresis").intValue(); - pde[239] = (char) h.get("idieresis").intValue(); - wae[240] = (char) h.get("eth").intValue(); - pde[240] = (char) h.get("eth").intValue(); - se[241] = (char) h.get("ae").intValue(); - mre[241] = (char) h.get("Ograve").intValue(); - wae[241] = (char) h.get("ntilde").intValue(); - pde[241] = (char) h.get("ntilde").intValue(); - mre[242] = (char) h.get("Uacute").intValue(); - wae[242] = (char) h.get("ograve").intValue(); - pde[242] = (char) h.get("ograve").intValue(); - mre[243] = (char) h.get("Ucircumflex").intValue(); - wae[243] = (char) h.get("oacute").intValue(); - pde[243] = (char) h.get("oacute").intValue(); - mre[244] = (char) h.get("Ugrave").intValue(); - wae[244] = (char) h.get("ocircumflex").intValue(); - pde[244] = (char) h.get("ocircumflex").intValue(); - se[245] = (char) h.get("dotlessi").intValue(); - mre[245] = (char) h.get("dotlessi").intValue(); - wae[245] = (char) h.get("otilde").intValue(); - pde[245] = (char) h.get("otilde").intValue(); - mre[246] = (char) h.get("circumflex").intValue(); - wae[246] = (char) h.get("odieresis").intValue(); - pde[246] = (char) h.get("odieresis").intValue(); - mre[247] = (char) h.get("tilde").intValue(); - wae[247] = (char) h.get("divide").intValue(); - pde[247] = (char) h.get("divide").intValue(); - se[248] = (char) h.get("lslash").intValue(); - mre[248] = (char) h.get("macron").intValue(); - wae[248] = (char) h.get("oslash").intValue(); - pde[248] = (char) h.get("oslash").intValue(); - se[249] = (char) h.get("oslash").intValue(); - mre[249] = (char) h.get("breve").intValue(); - wae[249] = (char) h.get("ugrave").intValue(); - pde[249] = (char) h.get("ugrave").intValue(); - se[250] = (char) h.get("oe").intValue(); - mre[250] = (char) h.get("dotaccent").intValue(); - wae[250] = (char) h.get("uacute").intValue(); - pde[250] = (char) h.get("uacute").intValue(); - se[251] = (char) h.get("germandbls").intValue(); - mre[251] = (char) h.get("ring").intValue(); - wae[251] = (char) h.get("ucircumflex").intValue(); - pde[251] = (char) h.get("ucircumflex").intValue(); - mre[252] = (char) h.get("cedilla").intValue(); - wae[252] = (char) h.get("udieresis").intValue(); - pde[252] = (char) h.get("udieresis").intValue(); - mre[253] = (char) h.get("hungarumlaut").intValue(); - wae[253] = (char) h.get("yacute").intValue(); - pde[253] = (char) h.get("yacute").intValue(); - mre[254] = (char) h.get("ogonek").intValue(); - wae[254] = (char) h.get("thorn").intValue(); - pde[254] = (char) h.get("thorn").intValue(); - mre[255] = (char) h.get("caron").intValue(); - wae[255] = (char) h.get("ydieresis").intValue(); - pde[255] = (char) h.get("ydieresis").intValue(); - - // addition of white space mappings. - // Line feed - se[10] = (char) h.get("space").intValue(); - mre[10] = (char) h.get("space").intValue(); - wae[10] = (char) h.get("space").intValue(); - // carriage return - se[13] = (char) h.get("space").intValue(); - mre[13] = (char) h.get("space").intValue(); - wae[13] = (char) h.get("space").intValue(); - // tabs - se[9] = (char) h.get("space").intValue(); - mre[9] = (char) h.get("space").intValue(); - wae[9] = (char) h.get("space").intValue(); - - - sym[0x20] = (char) h.get("space").intValue(); - sym[041] = (char) h.get("exclam").intValue(); - sym[042] = (char) h.get("universal").intValue(); - sym[043] = (char) h.get("numbersign").intValue(); - sym[044] = (char) h.get("existential").intValue(); - sym[045] = (char) h.get("percent").intValue(); - sym[046] = (char) h.get("ampersand").intValue(); - sym[047] = (char) h.get("suchthat").intValue(); - sym[050] = (char) h.get("parenleft").intValue(); - sym[051] = (char) h.get("parenright").intValue(); - sym[052] = (char) h.get("asteriskmath").intValue(); - sym[053] = (char) h.get("plus").intValue(); - sym[054] = (char) h.get("comma").intValue(); - sym[055] = (char) h.get("minus").intValue(); - sym[056] = (char) h.get("period").intValue(); - sym[057] = (char) h.get("slash").intValue(); - sym[060] = (char) h.get("zero").intValue(); - sym[061] = (char) h.get("one").intValue(); - sym[062] = (char) h.get("two").intValue(); - sym[063] = (char) h.get("three").intValue(); - sym[064] = (char) h.get("four").intValue(); - sym[065] = (char) h.get("five").intValue(); - sym[066] = (char) h.get("six").intValue(); - sym[067] = (char) h.get("seven").intValue(); - sym[070] = (char) h.get("eight").intValue(); - sym[071] = (char) h.get("nine").intValue(); - sym[072] = (char) h.get("colon").intValue(); - sym[073] = (char) h.get("semicolon").intValue(); - sym[074] = (char) h.get("less").intValue(); - sym[075] = (char) h.get("equal").intValue(); - sym[076] = (char) h.get("greater").intValue(); - sym[077] = (char) h.get("question").intValue(); - sym[0100] = (char) h.get("congruent").intValue(); - sym[0101] = (char) h.get("Alpha").intValue(); - sym[0102] = (char) h.get("Beta").intValue(); - sym[0103] = (char) h.get("Chi").intValue(); - sym[0104] = (char) h.get("Delta").intValue(); - sym[0105] = (char) h.get("Epsilon").intValue(); - sym[0106] = (char) h.get("Phi").intValue(); - sym[0107] = (char) h.get("Gamma").intValue(); - sym[0110] = (char) h.get("Eta").intValue(); - sym[0111] = (char) h.get("Iota").intValue(); - sym[0112] = (char) h.get("theta1").intValue(); - sym[0113] = (char) h.get("Kappa").intValue(); - sym[0114] = (char) h.get("Lambda").intValue(); - sym[0115] = (char) h.get("Mu").intValue(); - sym[0116] = (char) h.get("Nu").intValue(); - sym[0117] = (char) h.get("Omicron").intValue(); - sym[0120] = (char) h.get("Pi").intValue(); - sym[0121] = (char) h.get("Theta").intValue(); - sym[0122] = (char) h.get("Rho").intValue(); - sym[0123] = (char) h.get("Sigma").intValue(); - sym[0124] = (char) h.get("Tau").intValue(); - sym[0125] = (char) h.get("Upsilon").intValue(); - sym[0126] = (char) h.get("sigma1").intValue(); - sym[0127] = (char) h.get("Omega").intValue(); - sym[0130] = (char) h.get("Xi").intValue(); - sym[0131] = (char) h.get("Psi").intValue(); - sym[0132] = (char) h.get("Zeta").intValue(); - sym[0133] = (char) h.get("bracketleft").intValue(); - sym[0134] = (char) h.get("therefore").intValue(); - sym[0135] = (char) h.get("bracketright").intValue(); - sym[0136] = (char) h.get("perpendicular").intValue(); - sym[0137] = (char) h.get("underscore").intValue(); - sym[0140] = (char) h.get("radicalex").intValue(); - sym[0141] = (char) h.get("alpha").intValue(); - sym[0142] = (char) h.get("beta").intValue(); - sym[0143] = (char) h.get("chi").intValue(); - sym[0144] = (char) h.get("delta").intValue(); - sym[0145] = (char) h.get("epsilon").intValue(); - sym[0146] = (char) h.get("phi").intValue(); - sym[0147] = (char) h.get("gamma").intValue(); - sym[0150] = (char) h.get("eta").intValue(); - sym[0151] = (char) h.get("iota").intValue(); - sym[0152] = (char) h.get("phi1").intValue(); - sym[0153] = (char) h.get("kappa").intValue(); - sym[0154] = (char) h.get("lambda").intValue(); - sym[0155] = (char) h.get("mu").intValue(); - sym[0156] = (char) h.get("nu").intValue(); - sym[0157] = (char) h.get("omicron").intValue(); - sym[0160] = (char) h.get("pi").intValue(); - sym[0161] = (char) h.get("theta").intValue(); - sym[0162] = (char) h.get("rho").intValue(); - sym[0163] = (char) h.get("sigma").intValue(); - sym[0164] = (char) h.get("tau").intValue(); - sym[0165] = (char) h.get("upsilon").intValue(); - sym[0166] = (char) h.get("omega1").intValue(); - sym[0167] = (char) h.get("omega").intValue(); - sym[0170] = (char) h.get("xi").intValue(); - sym[0171] = (char) h.get("psi").intValue(); - sym[0172] = (char) h.get("zeta").intValue(); - sym[0173] = (char) h.get("braceleft").intValue(); - sym[0174] = (char) h.get("bar").intValue(); - sym[0175] = (char) h.get("braceright").intValue(); - sym[0176] = (char) h.get("similar").intValue(); - sym[0240] = (char) h.get("Euro").intValue(); - sym[0241] = (char) h.get("Upsilon1").intValue(); - sym[0242] = (char) h.get("minute").intValue(); - sym[0243] = (char) h.get("lessequal").intValue(); - sym[0244] = (char) h.get("fraction").intValue(); - sym[0245] = (char) h.get("infinity").intValue(); - sym[0246] = (char) h.get("florin").intValue(); - sym[0247] = (char) h.get("club").intValue(); - sym[0250] = (char) h.get("diamond").intValue(); - sym[0251] = (char) h.get("heart").intValue(); - sym[0252] = (char) h.get("spade").intValue(); - sym[0253] = (char) h.get("arrowboth").intValue(); - sym[0254] = (char) h.get("arrowleft").intValue(); - sym[0255] = (char) h.get("arrowup").intValue(); - sym[0256] = (char) h.get("arrowright").intValue(); - sym[0257] = (char) h.get("arrowdown").intValue(); - sym[0260] = (char) h.get("degree").intValue(); - sym[0261] = (char) h.get("plusminus").intValue(); - sym[0262] = (char) h.get("second").intValue(); - sym[0263] = (char) h.get("greaterequal").intValue(); - sym[0264] = (char) h.get("multiply").intValue(); - sym[0265] = (char) h.get("proportional").intValue(); - sym[0266] = (char) h.get("partialdiff").intValue(); - sym[0267] = (char) h.get("bullet").intValue(); - sym[0270] = (char) h.get("divide").intValue(); - sym[0271] = (char) h.get("notequal").intValue(); - sym[0272] = (char) h.get("equivalence").intValue(); - sym[0273] = (char) h.get("approxequal").intValue(); - sym[0274] = (char) h.get("ellipsis").intValue(); - sym[0275] = (char) h.get("arrowvertex").intValue(); - sym[0276] = (char) h.get("arrowhorizex").intValue(); - sym[0277] = (char) h.get("carriagereturn").intValue(); - sym[0300] = (char) h.get("aleph").intValue(); - sym[0301] = (char) h.get("Ifraktur").intValue(); - sym[0302] = (char) h.get("Rfraktur").intValue(); - sym[0303] = (char) h.get("weierstrass").intValue(); - sym[0304] = (char) h.get("circlemultiply").intValue(); - sym[0305] = (char) h.get("circleplus").intValue(); - sym[0306] = (char) h.get("emptyset").intValue(); - sym[0307] = (char) h.get("intersection").intValue(); - sym[0310] = (char) h.get("union").intValue(); - sym[0311] = (char) h.get("propersuperset").intValue(); - sym[0312] = (char) h.get("reflexsuperset").intValue(); - sym[0313] = (char) h.get("notsubset").intValue(); - sym[0314] = (char) h.get("propersubset").intValue(); - sym[0315] = (char) h.get("reflexsubset").intValue(); - sym[0316] = (char) h.get("element").intValue(); - sym[0317] = (char) h.get("notelement").intValue(); - sym[0320] = (char) h.get("angle").intValue(); - sym[0321] = (char) h.get("gradient").intValue(); - sym[0322] = (char) h.get("registerserif").intValue(); - sym[0323] = (char) h.get("copyrightserif").intValue(); - sym[0324] = (char) h.get("trademarkserif").intValue(); - sym[0325] = (char) h.get("product").intValue(); - sym[0326] = (char) h.get("radical").intValue(); - sym[0327] = (char) h.get("dotmath").intValue(); - sym[0330] = (char) h.get("logicalnot").intValue(); - sym[0331] = (char) h.get("logicaland").intValue(); - sym[0332] = (char) h.get("logicalor").intValue(); - sym[0333] = (char) h.get("arrowdblboth").intValue(); - sym[0334] = (char) h.get("arrowdblleft").intValue(); - sym[0335] = (char) h.get("arrowdblup").intValue(); - sym[0336] = (char) h.get("arrowdblright").intValue(); - sym[0337] = (char) h.get("arrowdbldown").intValue(); - sym[0340] = (char) h.get("lozenge").intValue(); - sym[0341] = (char) h.get("angleleft").intValue(); - sym[0342] = (char) h.get("registersans").intValue(); - sym[0343] = (char) h.get("copyrightsans").intValue(); - sym[0344] = (char) h.get("trademarksans").intValue(); - sym[0345] = (char) h.get("summation").intValue(); - sym[0346] = (char) h.get("parenlefttp").intValue(); - sym[0347] = (char) h.get("parenleftex").intValue(); - sym[0350] = (char) h.get("parenleftbt").intValue(); - sym[0351] = (char) h.get("bracketlefttp").intValue(); - sym[0352] = (char) h.get("bracketleftex").intValue(); - sym[0353] = (char) h.get("bracketleftbt").intValue(); - sym[0354] = (char) h.get("bracelefttp").intValue(); - sym[0355] = (char) h.get("braceleftmid").intValue(); - sym[0356] = (char) h.get("braceleftbt").intValue(); - sym[0357] = (char) h.get("braceex").intValue(); - sym[0361] = (char) h.get("angleright").intValue(); - sym[0362] = (char) h.get("integral").intValue(); - sym[0363] = (char) h.get("integraltp").intValue(); - sym[0364] = (char) h.get("integralex").intValue(); - sym[0365] = (char) h.get("integralbt").intValue(); - sym[0366] = (char) h.get("parenrighttp").intValue(); - sym[0367] = (char) h.get("parenrightex").intValue(); - sym[0370] = (char) h.get("parenrightbt").intValue(); - sym[0371] = (char) h.get("bracketrighttp").intValue(); - sym[0372] = (char) h.get("bracketrightex").intValue(); - sym[0373] = (char) h.get("bracketrightbt").intValue(); - sym[0374] = (char) h.get("bracerighttp").intValue(); - sym[0375] = (char) h.get("bracerightmid").intValue(); - sym[0376] = (char) h.get("bracerightbt").intValue(); - zap[32] = (char) h.get("space").intValue(); - zap[33] = (char) h.get("a1").intValue(); - zap[34] = (char) h.get("a2").intValue(); - zap[35] = (char) h.get("a202").intValue(); - zap[36] = (char) h.get("a3").intValue(); - zap[37] = (char) h.get("a4").intValue(); - zap[38] = (char) h.get("a5").intValue(); - zap[39] = (char) h.get("a119").intValue(); - zap[40] = (char) h.get("a118").intValue(); - zap[41] = (char) h.get("a117").intValue(); - zap[42] = (char) h.get("a11").intValue(); - zap[43] = (char) h.get("a12").intValue(); - zap[44] = (char) h.get("a13").intValue(); - zap[45] = (char) h.get("a14").intValue(); - zap[46] = (char) h.get("a15").intValue(); - zap[47] = (char) h.get("a16").intValue(); - zap[48] = (char) h.get("a105").intValue(); - zap[49] = (char) h.get("a17").intValue(); - zap[50] = (char) h.get("a18").intValue(); - zap[51] = (char) h.get("a19").intValue(); - zap[52] = (char) h.get("a20").intValue(); - zap[53] = (char) h.get("a21").intValue(); - zap[54] = (char) h.get("a22").intValue(); - zap[55] = (char) h.get("a23").intValue(); - zap[56] = (char) h.get("a24").intValue(); - zap[57] = (char) h.get("a25").intValue(); - zap[58] = (char) h.get("a26").intValue(); - zap[59] = (char) h.get("a27").intValue(); - zap[60] = (char) h.get("a28").intValue(); - zap[61] = (char) h.get("a6").intValue(); - zap[62] = (char) h.get("a7").intValue(); - zap[63] = (char) h.get("a8").intValue(); - zap[64] = (char) h.get("a9").intValue(); - zap[65] = (char) h.get("a10").intValue(); - zap[66] = (char) h.get("a29").intValue(); - zap[67] = (char) h.get("a30").intValue(); - zap[68] = (char) h.get("a31").intValue(); - zap[69] = (char) h.get("a32").intValue(); - zap[70] = (char) h.get("a33").intValue(); - zap[71] = (char) h.get("a34").intValue(); - zap[72] = (char) h.get("a35").intValue(); - zap[73] = (char) h.get("a36").intValue(); - zap[74] = (char) h.get("a37").intValue(); - zap[75] = (char) h.get("a38").intValue(); - zap[76] = (char) h.get("a39").intValue(); - zap[77] = (char) h.get("a40").intValue(); - zap[78] = (char) h.get("a41").intValue(); - zap[79] = (char) h.get("a42").intValue(); - zap[80] = (char) h.get("a43").intValue(); - zap[81] = (char) h.get("a44").intValue(); - zap[82] = (char) h.get("a45").intValue(); - zap[83] = (char) h.get("a46").intValue(); - zap[84] = (char) h.get("a47").intValue(); - zap[85] = (char) h.get("a48").intValue(); - zap[86] = (char) h.get("a49").intValue(); - zap[87] = (char) h.get("a50").intValue(); - zap[88] = (char) h.get("a51").intValue(); - zap[89] = (char) h.get("a52").intValue(); - zap[90] = (char) h.get("a53").intValue(); - zap[91] = (char) h.get("a54").intValue(); - zap[92] = (char) h.get("a55").intValue(); - zap[93] = (char) h.get("a56").intValue(); - zap[94] = (char) h.get("a57").intValue(); - zap[95] = (char) h.get("a58").intValue(); - zap[96] = (char) h.get("a59").intValue(); - zap[97] = (char) h.get("a60").intValue(); - zap[98] = (char) h.get("a61").intValue(); - zap[99] = (char) h.get("a62").intValue(); - zap[100] = (char) h.get("a63").intValue(); - zap[101] = (char) h.get("a64").intValue(); - zap[102] = (char) h.get("a65").intValue(); - zap[103] = (char) h.get("a66").intValue(); - zap[104] = (char) h.get("a67").intValue(); - zap[105] = (char) h.get("a68").intValue(); - zap[106] = (char) h.get("a69").intValue(); - zap[107] = (char) h.get("a70").intValue(); - zap[108] = (char) h.get("a71").intValue(); - zap[109] = (char) h.get("a72").intValue(); - zap[110] = (char) h.get("a73").intValue(); - zap[111] = (char) h.get("a74").intValue(); - zap[112] = (char) h.get("a203").intValue(); - zap[113] = (char) h.get("a75").intValue(); - zap[114] = (char) h.get("a204").intValue(); - zap[115] = (char) h.get("a76").intValue(); - zap[116] = (char) h.get("a77").intValue(); - zap[117] = (char) h.get("a78").intValue(); - zap[118] = (char) h.get("a79").intValue(); - zap[119] = (char) h.get("a81").intValue(); - zap[120] = (char) h.get("a82").intValue(); - zap[121] = (char) h.get("a83").intValue(); - zap[122] = (char) h.get("a84").intValue(); - zap[123] = (char) h.get("a97").intValue(); - zap[124] = (char) h.get("a98").intValue(); - zap[125] = (char) h.get("a99").intValue(); - zap[126] = (char) h.get("a100").intValue(); - zap[128] = (char) h.get("a89").intValue(); - zap[129] = (char) h.get("a90").intValue(); - zap[130] = (char) h.get("a93").intValue(); - zap[131] = (char) h.get("a94").intValue(); - zap[132] = (char) h.get("a91").intValue(); - zap[133] = (char) h.get("a92").intValue(); - zap[134] = (char) h.get("a205").intValue(); - zap[135] = (char) h.get("a85").intValue(); - zap[136] = (char) h.get("a206").intValue(); - zap[137] = (char) h.get("a86").intValue(); - zap[138] = (char) h.get("a87").intValue(); - zap[139] = (char) h.get("a88").intValue(); - zap[140] = (char) h.get("a95").intValue(); - zap[141] = (char) h.get("a96").intValue(); - zap[161] = (char) h.get("a101").intValue(); - zap[162] = (char) h.get("a102").intValue(); - zap[163] = (char) h.get("a103").intValue(); - zap[164] = (char) h.get("a104").intValue(); - zap[165] = (char) h.get("a106").intValue(); - zap[166] = (char) h.get("a107").intValue(); - zap[167] = (char) h.get("a108").intValue(); - zap[168] = (char) h.get("a112").intValue(); - zap[169] = (char) h.get("a111").intValue(); - zap[170] = (char) h.get("a110").intValue(); - zap[171] = (char) h.get("a109").intValue(); - zap[172] = (char) h.get("a120").intValue(); - zap[173] = (char) h.get("a121").intValue(); - zap[174] = (char) h.get("a122").intValue(); - zap[175] = (char) h.get("a123").intValue(); - zap[176] = (char) h.get("a124").intValue(); - zap[177] = (char) h.get("a125").intValue(); - zap[178] = (char) h.get("a126").intValue(); - zap[179] = (char) h.get("a127").intValue(); - zap[180] = (char) h.get("a128").intValue(); - zap[181] = (char) h.get("a129").intValue(); - zap[182] = (char) h.get("a130").intValue(); - zap[183] = (char) h.get("a131").intValue(); - zap[184] = (char) h.get("a132").intValue(); - zap[185] = (char) h.get("a133").intValue(); - zap[186] = (char) h.get("a134").intValue(); - zap[187] = (char) h.get("a135").intValue(); - zap[188] = (char) h.get("a136").intValue(); - zap[189] = (char) h.get("a137").intValue(); - zap[190] = (char) h.get("a138").intValue(); - zap[191] = (char) h.get("a139").intValue(); - zap[192] = (char) h.get("a140").intValue(); - zap[193] = (char) h.get("a141").intValue(); - zap[194] = (char) h.get("a142").intValue(); - zap[195] = (char) h.get("a143").intValue(); - zap[196] = (char) h.get("a144").intValue(); - zap[197] = (char) h.get("a145").intValue(); - zap[198] = (char) h.get("a146").intValue(); - zap[199] = (char) h.get("a147").intValue(); - zap[200] = (char) h.get("a148").intValue(); - zap[201] = (char) h.get("a149").intValue(); - zap[202] = (char) h.get("a150").intValue(); - zap[203] = (char) h.get("a151").intValue(); - zap[204] = (char) h.get("a152").intValue(); - zap[205] = (char) h.get("a153").intValue(); - zap[206] = (char) h.get("a154").intValue(); - zap[207] = (char) h.get("a155").intValue(); - zap[208] = (char) h.get("a156").intValue(); - zap[209] = (char) h.get("a157").intValue(); - zap[210] = (char) h.get("a158").intValue(); - zap[211] = (char) h.get("a159").intValue(); - zap[212] = (char) h.get("a160").intValue(); - zap[213] = (char) h.get("a161").intValue(); - zap[214] = (char) h.get("a163").intValue(); - zap[215] = (char) h.get("a164").intValue(); - zap[216] = (char) h.get("a196").intValue(); - zap[217] = (char) h.get("a165").intValue(); - zap[218] = (char) h.get("a192").intValue(); - zap[219] = (char) h.get("a166").intValue(); - zap[220] = (char) h.get("a167").intValue(); - zap[221] = (char) h.get("a168").intValue(); - zap[222] = (char) h.get("a169").intValue(); - zap[223] = (char) h.get("a170").intValue(); - zap[224] = (char) h.get("a171").intValue(); - zap[225] = (char) h.get("a172").intValue(); - zap[226] = (char) h.get("a173").intValue(); - zap[227] = (char) h.get("a162").intValue(); - zap[228] = (char) h.get("a174").intValue(); - zap[229] = (char) h.get("a175").intValue(); - zap[230] = (char) h.get("a176").intValue(); - zap[231] = (char) h.get("a177").intValue(); - zap[232] = (char) h.get("a178").intValue(); - zap[233] = (char) h.get("a179").intValue(); - zap[234] = (char) h.get("a193").intValue(); - zap[235] = (char) h.get("a180").intValue(); - zap[236] = (char) h.get("a199").intValue(); - zap[237] = (char) h.get("a181").intValue(); - zap[238] = (char) h.get("a200").intValue(); - zap[239] = (char) h.get("a182").intValue(); - zap[241] = (char) h.get("a201").intValue(); - zap[242] = (char) h.get("a183").intValue(); - zap[243] = (char) h.get("a184").intValue(); - zap[244] = (char) h.get("a197").intValue(); - zap[245] = (char) h.get("a185").intValue(); - zap[246] = (char) h.get("a194").intValue(); - zap[247] = (char) h.get("a198").intValue(); - zap[248] = (char) h.get("a186").intValue(); - zap[249] = (char) h.get("a195").intValue(); - zap[250] = (char) h.get("a187").intValue(); - zap[251] = (char) h.get("a188").intValue(); - zap[252] = (char) h.get("a189").intValue(); - zap[253] = (char) h.get("a190").intValue(); - zap[254] = (char) h.get("a191").intValue(); - } - /** - * put your documentation comment here - * @param s[] - */ - /* public static void main (String s[]) { - System.out.println("zeta=" + getUV("zeta"); - System.out.println("yen=" + getUV("yen"); - System.out.println("A=" + getUV("A"); - System.out.println("Alpha=" + getUV("Alpha"); - }*/ -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/Font.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/Font.java deleted file mode 100644 index e4092ebb0e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/Font.java +++ /dev/null @@ -1,721 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts.ofont; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.fonts.AFM; -import org.icepdf.core.pobjects.fonts.FontDescriptor; -import org.icepdf.core.util.FontUtil; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; -import java.util.List; -import java.util.StringTokenizer; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * - */ -public class Font extends org.icepdf.core.pobjects.fonts.Font { - - private static final Logger logger = - Logger.getLogger(Font.class.toString()); - - public static final Name BASE_ENCODING_KEY = new Name("BaseEncoding"); - public static final Name ENCODING_KEY = new Name("Encoding"); - public static final Name TOUNICODE_KEY = new Name("ToUnicode"); - public static final Name DIFFERENCES_KEY = new Name("Differences"); - public static final Name WIDTHS_KEY = new Name("Widths"); - public static final Name FIRST_CHAR_KEY = new Name("FirstChar"); - public static final Name W_KEY = new Name("W"); - public static final Name FONT_DESCRIPTOR_KEY = new Name("FontDescriptor"); - public static final Name DESCENDANT_FONTS_KEY = new Name("DescendantFonts"); - public static final Name NONE_KEY = new Name("none"); - public static final Name STANDARD_ENCODING_KEY = new Name("StandardEncoding"); - public static final Name MACROMAN_ENCODING_KEY = new Name("MacRomanEncoding"); - public static final Name WINANSI_ENCODING_KEY = new Name("WinAnsiEncoding"); - public static final Name PDF_DOC_ENCODING_KEY = new Name("PDFDocEncoding"); - - // A specification of the font's character encoding, if different from its - // built-in encoding. The value of Encoding may be either the name of a predefined - // encoding (MacRomanEncoding, MacExpertEncoding, or WinAnsi- Encoding, as - // described in Appendix D) or an encoding dictionary that specifies - // differences from the font's built-in encoding or from a specified predefined - // encoding - private Encoding encoding; - // encoding name for debugging reasons; - private Name encodingName; - - // An array of (LastChar ? FirstChar + 1) widths, each element being the - // glyph width for the character code that equals FirstChar plus the array index. - // For character codes outside the range FirstChar to LastChar, the value - // of MissingWidth from the FontDescriptor entry for this font is used. - private List widths; - - // widths for cid fonts, substitution specific, font files actually have - // correct glyph widths. - private HashMap cidWidths; - - // Base character mapping of 256 chars - private char[] cMap; - - // ToUnicode CMap object stores any mapping information - private CMap toUnicodeCMap; - - // Base 14 AFM fonts - protected AFM afm; - - // awt font style reference, ITALIC or BOLD|ITALIC - protected int style; - - // get list of all available fonts. - private static final java.awt.Font[] fonts = - GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); - - // Array of type1 font differences based on family names. - static final String type1Diff[][] = - {{"Bookman-Demi", "URWBookmanL-DemiBold", "Arial"}, { - "Bookman-DemiItalic", "URWBookmanL-DemiBoldItal", "Arial"}, { - "Bookman-Light", "URWBookmanL-Ligh", "Arial"}, { - "Bookman-LightItalic", "URWBookmanL-LighItal", "Arial"}, { - "Courier", "Nimbus Mono L Regular", "Nimbus Mono L"}, { - "Courier-Oblique", - "Nimbus Mono L Regular Oblique", - "Nimbus Mono L"}, - { - "Courier-Bold", "Nimbus Mono L Bold", "Nimbus Mono L"}, { - "Courier-BoldOblique", - "Nimbus Mono L Bold Oblique", - "Nimbus Mono L"}, - { - "AvantGarde-Book", "URWGothicL-Book", "Arial"}, { - "AvantGarde-BookOblique", "URWGothicL-BookObli", "Arial"}, { - "AvantGarde-Demi", "URWGothicL-Demi", "Arial"}, { - "AvantGarde-DemiOblique", "URWGothicL-DemiObli", "Arial"}, { - "Helvetica", "Nimbus Sans L Regular", "Nimbus Sans L"}, { - "Helvetica-Oblique", - "Nimbus Sans L Regular Italic", - "Nimbus Sans L"}, - { - "Helvetica-Bold", "Nimbus Sans L Bold", "Nimbus Sans L"}, { - "Helvetica-BoldOblique", - "Nimbus Sans L Bold Italic", - "Nimbus Sans L"}, - { - "Helvetica-Narrow", - "Nimbus Sans L Regular Condensed", - "Nimbus Sans L"}, - { - "Helvetica-Narrow-Oblique", - "Nimbus Sans L Regular Condensed Italic", - "Nimbus Sans L"}, - { - "Helvetica-Narrow-Bold", - "Nimbus Sans L Bold Condensed", - "Nimbus Sans L"}, - { - "Helvetica-Narrow-BoldOblique", - "Nimbus Sans L Bold Condensed Italic", - "Nimbus Sans L"}, - { - "Helvetica-Condensed", - "Nimbus Sans L Regular Condensed", - "Nimbus Sans L"}, - { - "Helvetica-Condensed-Oblique", - "Nimbus Sans L Regular Condensed Italic", - "Nimbus Sans L"}, - { - "Helvetica-Condensed-Bold", - "Nimbus Sans L Bold Condensed", - "Nimbus Sans L"}, - { - "Helvetica-Condensed-BoldOblique", - "Nimbus Sans L Bold Condensed Italic", - "Nimbus Sans L"}, - { - "Palatino-Roman", "URWPalladioL-Roma", "Arial"}, { - "Palatino-Italic", "URWPalladioL-Ital", "Arial"}, { - "Palatino-Bold", "URWPalladioL-Bold", "Arial"}, { - "Palatino-BoldItalic", "URWPalladioL-BoldItal", "Arial"}, { - "NewCenturySchlbk-Roman", "CenturySchL-Roma", "Arial"}, { - "NewCenturySchlbk-Italic", "CenturySchL-Ital", "Arial"}, { - "NewCenturySchlbk-Bold", "CenturySchL-Bold", "Arial"}, { - "NewCenturySchlbk-BoldItalic", "CenturySchL-BoldItal", "Arial"}, { - "Times-Roman", - "Nimbus Roman No9 L Regular", - "Nimbus Roman No9 L"}, - { - "Times-Italic", - "Nimbus Roman No9 L Regular Italic", - "Nimbus Roman No9 L"}, - { - "Times-Bold", - "Nimbus Roman No9 L Medium", - "Nimbus Roman No9 L"}, - { - "Times-BoldItalic", - "Nimbus Roman No9 L Medium Italic", - "Nimbus Roman No9 L"}, - { - "Symbol", "Standard Symbols L", "Standard Symbols L"}, { - "ZapfChancery-MediumItalic", "URWChanceryL-MediItal", "Arial"}, { - "ZapfDingbats", "Dingbats", "Dingbats"} - }; - - public Font(Library library, HashMap entries) { - super(library, entries); - - // initialize cMap array with base characters - cMap = new char[256]; - for (char i = 0; i < 256; i++) { - cMap[i] = i; - } - - // get font style value. - style = FontUtil.guessAWTFontStyle(basefont); - - // strip font name clean ready for processing - basefont = cleanFontName(basefont); - - // on a null type default to Type1 - if (subtype == null) { - subtype = new Name("Type1"); - } - - // This should help with figuring out special symbols - if (subtype.equals("Type3")) { - basefont = "Symbol"; - encoding = Encoding.getSymbol(); - - } - // Setup encoding for type 1 fonts - if (subtype.equals("Type1")) { - // symbol - if (basefont.equals("Symbol")) { - encoding = Encoding.getSymbol(); - } - // ZapfDingbats - else if (basefont.equalsIgnoreCase("ZapfDingbats") && - subtype.equals("Type1")) { - encoding = Encoding.getZapfDingBats(); - } - // check type1Diff table against base font and assign encoding of found - else { - for (String[] aType1Diff : type1Diff) { - if (basefont.equals(aType1Diff[0])) { - encodingName = STANDARD_ENCODING_KEY; - encoding = Encoding.getStandard(); - break; - } - } - } - } - // TrueType fonts with a Symbol name get WinAnsi encoding - if (subtype.equals("TrueType")) { - if (basefont.equals("Symbol")) { - encodingName = WINANSI_ENCODING_KEY; - encoding = Encoding.getWinAnsi(); - } - } - - } - - /** - * Initiate the Font. Retrieve any needed attributes, basically setup the - * font so it can be used by the content parser. - */ - public synchronized void init() { - // flag for initiated fonts - if (inited) { - return; - } - - // re-initialize the char mapping array based on the encoding of the font - if (encoding != null) { - for (char i = 0; i < 256; i++) { - cMap[i] = encoding.get(i); - } - } - - // ToUnicode indicates that we now have CMap stream that need to be parsed - Object objectUnicode = library.getObject(entries, TOUNICODE_KEY); - if (objectUnicode != null && objectUnicode instanceof Stream) { - toUnicodeCMap = new CMap(library, new HashMap(), (Stream) objectUnicode); - toUnicodeCMap.init(); - } - - // Find any special encoding information, not used very often - Object o = library.getObject(entries, ENCODING_KEY); - if (o != null) { - if (o instanceof HashMap) { - HashMap encoding = (HashMap) o; - setBaseEncoding(library.getName(encoding, BASE_ENCODING_KEY)); - List differences = (List) library.getObject(encoding, DIFFERENCES_KEY); - if (differences != null) { - int c = 0; - for (Object oo : differences) { - if (oo instanceof Number) { - c = ((Number) oo).intValue(); - } else if (oo instanceof Name) { - String n = oo.toString(); - int c1 = Encoding.getUV(n); - if (c1 == -1) { - if (n.charAt(0) == 'a') { - n = n.substring(1); - try { - c1 = Integer.parseInt(n); - } catch (Exception ex) { - logger.log(Level.FINE, "Error parings font differences"); - } - } - } - cMap[c] = (char) c1; - c++; - } - } - } - } else if (o instanceof Name) { - setBaseEncoding((Name) o); - } - } - - // An array of (LastChar ? FirstChar + 1) widths, each element being the - // glyph width for the character code that equals FirstChar plus the array index. - widths = (List) (library.getObject(entries, WIDTHS_KEY)); - if (widths != null) { - - // Assigns the First character code defined in the font's Widths array - o = library.getObject(entries, FIRST_CHAR_KEY); - if (o != null) { - firstchar = ((Number) o).intValue(); - } - } - // check of a cid font - else if (library.getObject(entries, W_KEY) != null) { - // calculate CID widths - cidWidths = calculateCIDWidths(); - // first char is likely 1. - firstchar = 0; - // cid fonts are not afm... - isAFMFont = false; - } - // afm fonts don't have widths. - else { - isAFMFont = false; - } - - - // Assign the font descriptor - Object of = library.getObject(entries, FONT_DESCRIPTOR_KEY); - if (of instanceof FontDescriptor) { - fontDescriptor = (FontDescriptor) of; - fontDescriptor.init(); - } - - // If there is no FontDescriptor then we most likely have a core afm - // font and we should get the matrix so that we can derive the correct - // font. - if (fontDescriptor == null && basefont != null) { - // see if the baseFont name matches one of the AFM names - Object afm = AFM.AFMs.get(basefont.toLowerCase()); - if (afm != null && afm instanceof AFM) { - AFM fontMetrix = (AFM) afm; - // finally create a fontDescriptor based on AFM data. - fontDescriptor = FontDescriptor.createDescriptor(library, fontMetrix); - fontDescriptor.init(); - } - } - - // assign font name for descriptor - if (fontDescriptor != null) { - String name = fontDescriptor.getFontName(); - if (name != null && name.length() > 0) { - basefont = cleanFontName(name); - } - } - - // checking flags for set bits. - if (fontDescriptor != null && (fontDescriptor.getFlags() & 64) != 0 - && encoding == null) { - encodingName = STANDARD_ENCODING_KEY; - encoding = Encoding.getStandard(); - } - - // this is a test to basic CIDFont support. The current font class - // is not setup to deal with this type of font, however we can still - // located the descendant font described by the CIDFont's data and try - // and cMap the properties over to the type1 font - Object descendant = library.getObject(entries, DESCENDANT_FONTS_KEY); - if (descendant != null) { - List tmp = (List) descendant; - if (tmp.get(0) instanceof Reference) { - // locate the font reference - Object fontReference = library.getObject((Reference) tmp.get(0)); - if (fontReference instanceof Font) { - // create and initiate the font based on the stream data - Font desendant = (Font) fontReference; - desendant.toUnicodeCMap = this.toUnicodeCMap; - desendant.init(); - this.cidWidths = desendant.cidWidths; - // point the DescendantFont font Descriptor to this Font object - // this may help improve the display of some fonts. - if (fontDescriptor == null) { - fontDescriptor = desendant.fontDescriptor; - String name = fontDescriptor.getFontName(); - if (name != null) { - basefont = cleanFontName(name); - } - } - } - } - } - - // check to see if the the font subtype is Type 1 and see if it matches - // one of the base 14 types included with the document. - if (subtype.equals("Type1")) { - AFM a = AFM.AFMs.get(basefont.toLowerCase()); - if (a != null && a.getFontName() != null) { - afm = a; - } - } - // Create a new true type font based on the named basefont. - if (subtype.equals("Type1")) { - for (String[] aType1Diff : type1Diff) { - if (basefont.equals(aType1Diff[0])) { - java.awt.Font f = - new java.awt.Font( - aType1Diff[1], - style, - 12); - if (f.getFamily().equals(aType1Diff[2])) { - basefont = aType1Diff[1]; - break; - } - } - } - } - - // font substitution found flag - isFontSubstitution = true; -// isAFMFont = true; - - // get most types of embedded fonts from here - if (fontDescriptor != null && fontDescriptor.getEmbeddedFont() != null) { - font = fontDescriptor.getEmbeddedFont(); - isFontSubstitution = false; - isAFMFont = false; - } - - // look at all PS font names and try and find a match - if (font == null && basefont != null) { - // Check to see if any of the system fonts match the basefont name - for (java.awt.Font font1 : fonts) { - - // remove white space - StringTokenizer st = new StringTokenizer(font1.getPSName(), " ", false); - String fontName = ""; - while (st.hasMoreElements()) fontName += st.nextElement(); - - // if a match is found assign it as the real font - if (fontName.equalsIgnoreCase(basefont)) { - font = new OFont(new java.awt.Font(font1.getFamily(), style, 1)); - basefont = font1.getPSName(); - isFontSubstitution = true; - break; - } - } - } - - // look at font family name matches against system fonts - if (font == null && basefont != null) { - - // clean the base name so that is has just the font family - String fontFamily = FontUtil.guessFamily(basefont); - - for (java.awt.Font font1 : fonts) { - // find font family match - if (FontUtil.normalizeString( - font1.getFamily()).equalsIgnoreCase(fontFamily)) { - // create new font with font family name and style - font = new OFont(new java.awt.Font(font1.getFamily(), style, 1)); - basefont = font1.getFontName(); - isFontSubstitution = true; - break; - } - } - } - // if still null, shouldn't be, assigned the basefont name - if (font == null) { - try { - font = new OFont(java.awt.Font.getFont(basefont, - new java.awt.Font(basefont, - style, - 12))); - basefont = font.getName(); - } catch (Exception e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error creating awt.font for: " + entries); - } - } - } - // If the font substitutions failed then we want to try and pick the proper - // font family based on what the font name best matches up with none - // font family font names. if all else fails use serif as it is the most' - // common font. - if (!isFontSubstitution && font != null && - !font.getName().toLowerCase().contains(font.getFamily().toLowerCase())) { - // see if we working with a sans serif font - if ((font.getName().toLowerCase().contains("times new roman") || - font.getName().toLowerCase().contains("timesnewroman") || - font.getName().toLowerCase().contains("bodoni") || - font.getName().toLowerCase().contains("garamond") || - font.getName().toLowerCase().contains("minion web") || - font.getName().toLowerCase().contains("stone serif") || - font.getName().toLowerCase().contains("stoneserif") || - font.getName().toLowerCase().contains("georgia") || - font.getName().toLowerCase().contains("bitstream cyberbit"))) { - font = new OFont(new java.awt.Font("serif", - font.getStyle(), (int) font.getSize())); - basefont = "serif"; - } - // see if we working with a monospaced font - else if ((font.getName().toLowerCase().contains("helvetica") || - font.getName().toLowerCase().contains("arial") || - font.getName().toLowerCase().contains("trebuchet") || - font.getName().toLowerCase().contains("avant garde gothic") || - font.getName().toLowerCase().contains("avantgardegothic") || - font.getName().toLowerCase().contains("verdana") || - font.getName().toLowerCase().contains("univers") || - font.getName().toLowerCase().contains("futura") || - font.getName().toLowerCase().contains("stone sans") || - font.getName().toLowerCase().contains("stonesans") || - font.getName().toLowerCase().contains("gill sans") || - font.getName().toLowerCase().contains("gillsans") || - font.getName().toLowerCase().contains("akzidenz") || - font.getName().toLowerCase().contains("grotesk"))) { - font = new OFont(new java.awt.Font("sansserif", - font.getStyle(), (int) font.getSize())); - basefont = "sansserif"; - } - // see if we working with a mono spaced font - else if ((font.getName().toLowerCase().contains("courier") || - font.getName().toLowerCase().contains("courier new") || - font.getName().toLowerCase().contains("couriernew") || - font.getName().toLowerCase().contains("prestige") || - font.getName().toLowerCase().contains("eversonmono") || - font.getName().toLowerCase().contains("Everson Mono"))) { - font = new OFont(new java.awt.Font("monospaced", - font.getStyle(), (int) font.getSize())); - basefont = "monospaced"; - } - // if all else fails go with the serif as it is the most common font family - else { - font = new OFont(new java.awt.Font("serif", - font.getStyle(), (int) font.getSize())); - basefont = "serif"; - } - } - // finally if we have an empty font then we default to serif so that - // we can try and render the character codes. - if (font == null) { - font = new OFont(new java.awt.Font("serif", style, 12)); - basefont = "serif"; - } - - // setup encoding and widths. - setWidth(); - font = font.deriveFont(encoding, toUnicodeCMap); - - if (logger.isLoggable(Level.FINE)) { - logger.fine(name + " - " + encodingName + " " + basefont + " " + - font.toString() + " " + isFontSubstitution); - } - - inited = true; - } - - /** - * Sets the encoding of the font - * - * @param baseEncoding encoding name ususally MacRomanEncoding, - * MacExpertEncoding, or WinAnsi- Encoding - */ - private void setBaseEncoding(Name baseEncoding) { - if (baseEncoding == null) { - encodingName = NONE_KEY; - return; - } - encodingName = baseEncoding; - if (baseEncoding.equals(STANDARD_ENCODING_KEY)) { - encoding = Encoding.getStandard(); - } else if (baseEncoding.equals(MACROMAN_ENCODING_KEY)) { - encoding = Encoding.getMacRoman(); - } else if (baseEncoding.equals(WINANSI_ENCODING_KEY)) { - encoding = Encoding.getWinAnsi(); - } else if (baseEncoding.equals(PDF_DOC_ENCODING_KEY)) { - encoding = Encoding.getPDFDoc(); - } - // initiate encoding cMap. - if (encoding != null) { - for (char i = 0; i < 256; i++) { - cMap[i] = encoding.get(i); - } - } - } - - /** - * String representation of the Font object. - * - * @return string representing Font object attributes. - */ - public String toString() { - return "FONT= " + encodingName + " " + entries.toString(); - } - - - /** - * Gets the widths of the given character and appends it to the - * current advance - * - * @param character character to find width of - * @param advance current advance of the character - * @return width of specfied character. - - private float getWidth(int character, float advance) { - character -= firstchar; - if (widths != null) { - if (character >= 0 && character < widths.size()) { - return ((Number) widths.elementAt(character)).floatValue() / 1000f; - } - } - // get any necessary afm widths - else if (afm != null) { - Float i = afm.getWidths()[(character)]; - if (i != null) { - return i / 1000f; - } - } - // find any widths in the font descriptor - else if (fontDescriptor != null) { - if (fontDescriptor.getMissingWidth() > 0) - return fontDescriptor.getMissingWidth() / 1000f; - } - return advance; - }*/ - - /** - * Utility method for setting the widths for a particular font given the - * specified encoding. - */ - private void setWidth() { - float missingWidth = 0; - float ascent = 0.0f; - float descent = 0.0f; - if (fontDescriptor != null) { - if (fontDescriptor.getMissingWidth() > 0) { - missingWidth = fontDescriptor.getMissingWidth() / 1000f; - ascent = fontDescriptor.getAscent() / 1000f; - descent = fontDescriptor.getDescent() / 1000f; - } - } - if (widths != null) { - float[] newWidth = new float[256 - firstchar]; - for (int i = 0, max = widths.size(); i < max; i++) { - if (widths.get(i) != null) { - newWidth[i] = ((Number) widths.get(i)).floatValue() / 1000f; - } - } - font = font.deriveFont(newWidth, firstchar, missingWidth, ascent, descent, cMap); - } else if (cidWidths != null) { - // cidWidth are already scaled correct to .001 - font = font.deriveFont(cidWidths, firstchar, missingWidth, ascent, descent, null); - } else if (afm != null && isAFMFont) { - font = font.deriveFont(afm.getWidths(), firstchar, missingWidth, ascent, descent, cMap); - } - - } - - private String cleanFontName(String fontName) { - - // crystal report ecoding specific, this will have to made more - // robust when more examples are found. - fontName = FontUtil.removeBaseFontSubset(fontName); - - // strip commas from basefont name and replace with dashes - if (subtype != null && (subtype.equals("Type0") - || subtype.equals("Type1") - || subtype.equals("MMType1") - || subtype.equals("TrueType"))) { - if (fontName != null) { - // normalize so that java.awt.decode will work correctly - fontName = fontName.replace(',', '-'); - } - } - return fontName; - } - - private HashMap calculateCIDWidths() { - HashMap cidWidths = new HashMap(75); - // get width vector - Object o = library.getObject(entries, W_KEY); - if (o instanceof List) { - List cidWidth = (List) o; - Object current; - Object peek; - List subWidth; - int currentChar; - for (int i = 0, max = cidWidth.size() - 1; i < max; i++) { - current = cidWidth.get(i); - peek = cidWidth.get(i + 1); - // found format c[w1, w2 ... wn] - if (current instanceof Integer && - peek instanceof List) { - // apply Unicode mapping if any - currentChar = (Integer) current; - subWidth = (List) peek; - for (int j = 0, subMax = subWidth.size(); j < subMax; j++) { - if (subWidth.get(j) instanceof Integer) { - cidWidths.put(currentChar + j, (Integer) subWidth.get(j) / 1000f); - } else if (subWidth.get(j) instanceof Float) { - cidWidths.put(currentChar + j, (Float) subWidth.get(j) / 1000f); - } - } - i++; - } - if (current instanceof Integer && - peek instanceof Integer) { - for (int j = (Integer) current; j <= (Integer) peek; j++) { - // apply Unicode mapping if any - currentChar = j; - if (cidWidth.get(i + 2) instanceof Integer) { - cidWidths.put(currentChar, (Integer) cidWidth.get(i + 2) / 1000f); - } else if (cidWidth.get(i + 2) instanceof Float) { - cidWidths.put(currentChar, (Float) cidWidth.get(i + 2) / 1000f); - } - } - i += 2; - } - } - } - return cidWidths; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/OFont.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/OFont.java deleted file mode 100644 index b7f7f12b55..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/fonts/ofont/OFont.java +++ /dev/null @@ -1,427 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.fonts.ofont; - -import org.icepdf.core.pobjects.fonts.CMap; -import org.icepdf.core.pobjects.fonts.Encoding; -import org.icepdf.core.pobjects.fonts.FontFile; -import org.icepdf.core.pobjects.graphics.TextState; - -import java.awt.*; -import java.awt.Font; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphMetrics; -import java.awt.font.GlyphVector; -import java.awt.font.TextLayout; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * OFont is an awt Font wrapper used to aid in the paint of glyphs. - * - * @since 3.0 - */ -public class OFont implements FontFile { - - private static final Logger log = - Logger.getLogger(OFont.class.toString()); - - private Font awtFont; - private Rectangle2D maxCharBounds = - new Rectangle2D.Double(0.0, 0.0, 1.0, 1.0); - - // text layout map, very expensive to create, so we'll cache them. - private HashMap echarAdvanceCache; - - protected float[] widths; - protected Map cidWidths; - protected float missingWidth; - protected int firstCh; - protected float ascent; - protected float descent; - protected Encoding encoding; - protected CMap toUnicode; - protected char[] cMap; - - - public OFont(Font awtFont) { - this.awtFont = awtFont; - maxCharBounds = new Rectangle2D.Double(); - this.echarAdvanceCache = new HashMap(256); - } - - private OFont(OFont font) { - this.echarAdvanceCache = font.echarAdvanceCache; - this.awtFont = font.awtFont; - this.encoding = font.encoding; - this.toUnicode = font.toUnicode; - this.missingWidth = font.missingWidth; - this.firstCh = font.firstCh; - this.ascent = font.ascent; - this.descent = font.descent; - this.widths = font.widths; - this.cidWidths = font.cidWidths; - this.cMap = font.cMap; - this.maxCharBounds = font.maxCharBounds; - } - - public FontFile deriveFont(Encoding encoding, CMap toUnicode) { - OFont font = new OFont(this); - this.echarAdvanceCache.clear(); - font.encoding = encoding; - font.toUnicode = toUnicode; - return font; - } - - public FontFile deriveFont(float[] widths, int firstCh, float missingWidth, - float ascent, float descent, char[] diff) { - OFont font = new OFont(this); - this.echarAdvanceCache.clear(); - font.missingWidth = this.missingWidth; - font.firstCh = firstCh; - font.ascent = ascent; - font.descent = descent; - font.widths = widths; - font.cMap = diff; - return font; - } - - public FontFile deriveFont(Map widths, int firstCh, float missingWidth, - float ascent, float descent, char[] diff) { - OFont font = new OFont(this); - this.echarAdvanceCache.clear(); - font.missingWidth = this.missingWidth; - font.firstCh = firstCh; - font.ascent = ascent; - font.descent = descent; - font.cidWidths = widths; - font.cMap = diff; - return font; - } - - public FontFile deriveFont(AffineTransform at) { - OFont font = new OFont(this); - // clear font metric cache if we change the font's transform - if (!font.getTransform().equals(this.awtFont.getTransform())) { - this.echarAdvanceCache.clear(); - } - font.awtFont = this.awtFont.deriveFont(at); - - font.maxCharBounds = this.maxCharBounds; - return font; - } - - public boolean canDisplayEchar(char ech) { - return true; - } - - public FontFile deriveFont(float pointsize) { - OFont font = new OFont(this); - font.awtFont = this.awtFont.deriveFont(pointsize); - font.maxCharBounds = this.maxCharBounds; - return font; - } - - public Point2D echarAdvance(final char ech) { - - // create a glyph vector for the char - float advance; - float advanceY; - - // check cache for existing layout - String text = ech + "_" + awtFont.getSize(); - Point2D.Float echarAdvance = echarAdvanceCache.get(text); - - // generate metrics is needed - if (echarAdvance == null) { - - // the glyph vector should be created using any toUnicode value if present, as this is what we - // are drawing, the method also does a check to apply differences if toUnicode is null. - char echGlyph = getCMapping(ech); - - FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, true); - GlyphVector glyphVector = awtFont.createGlyphVector( - frc, - String.valueOf(echGlyph)); - TextLayout textLayout = new TextLayout(String.valueOf(echGlyph), awtFont, frc); - - // get bounds, only need to do this once. - maxCharBounds = awtFont.getMaxCharBounds(frc); - ascent = textLayout.getAscent(); - descent = textLayout.getDescent(); - - GlyphMetrics glyphMetrics = glyphVector.getGlyphMetrics(0); - advance = glyphMetrics.getAdvanceX(); - advanceY = glyphMetrics.getAdvanceY(); - - echarAdvanceCache.put(text, - new Point2D.Float(advance, advanceY)); - } - // returned cashed value - else { - advance = echarAdvance.x; - advanceY = echarAdvance.y; - } - - // widths uses original cid's, not the converted to unicode value. - if (widths != null && ech - firstCh >= 0 && ech - firstCh < widths.length) { - advance = widths[ech - firstCh] * awtFont.getSize2D(); - } else if (cidWidths != null) { - Float width = cidWidths.get((int) ech); - if (width != null) { - advance = cidWidths.get((int) ech) * awtFont.getSize2D(); - } - } - // find any widths in the font descriptor - else if (missingWidth > 0) { - advance = missingWidth / 1000f; - } - - return new Point2D.Float(advance, advanceY); - } - - /** - * Gets the ToUnicode character value for the given character. - * - * @param currentChar character to find a corresponding CMap for. - * @return a new Character based on the CMap tranformation. If the character - * can not be found in the CMap the orginal value is returned. - */ - private char getCMapping(char currentChar) { - if (toUnicode != null) { - return toUnicode.toSelector(currentChar); - } - return currentChar; - } - - /** - * Return the width of the given character - * - * @param character character to retreive width of - * @return width of the given character - */ - public char getCharDiff(char character) { - if (cMap != null && character < cMap.length) { - return cMap[character]; - } else { - return character; - } - } - - private char findAlternateSymbol(char character) { - // test for known symbol aliases - for (int i = 0; i < org.icepdf.core.pobjects.fonts.ofont.Encoding.symbolAlaises.length; i++) { - for (int j = 0; j < org.icepdf.core.pobjects.fonts.ofont.Encoding.symbolAlaises[i].length; j++) { - if (org.icepdf.core.pobjects.fonts.ofont.Encoding.symbolAlaises[i][j] == character) { - //System.out.println("found char " + Encoding.symbolAlaises[i][0]); - return (char) org.icepdf.core.pobjects.fonts.ofont.Encoding.symbolAlaises[i][0]; - } - } - } - return character; - } - - public CMap getToUnicode() { - return toUnicode; - } - - public int getStyle() { - return awtFont.getStyle(); - } - - public String getFamily() { - return awtFont.getFamily(); - } - - public float getSize() { - return awtFont.getSize(); - } - - public double getAscent() { - return ascent; - } - - public double getDescent() { - return descent; - } - - public Rectangle2D getMaxCharBounds() { - return maxCharBounds; - } - - public AffineTransform getTransform() { - return awtFont.getTransform(); - } - - public int getRights() { - return 0; - } - - public String getName() { - return awtFont.getName(); - } - - public boolean isHinted() { - return false; - } - - public void setIsCid() { - } - - public int getNumGlyphs() { - return awtFont.getNumGlyphs(); - } - - public char getSpaceEchar() { - return 32; - } - - public Rectangle2D getEstringBounds(String estr, int beginIndex, int limit) { - return null; - } - - public String getFormat() { - return null; - } - - public void drawEstring(Graphics2D g, String displayText, float x, float y, - long layout, int mode, Color strokecolor) { - - AffineTransform af = g.getTransform(); - Shape outline = getEstringOutline(displayText, x, y); - - if (TextState.MODE_FILL == mode || TextState.MODE_FILL_STROKE == mode || - TextState.MODE_FILL_ADD == mode || TextState.MODE_FILL_STROKE_ADD == mode) { - g.fill(outline); - } - if (TextState.MODE_STROKE == mode || TextState.MODE_FILL_STROKE == mode || - TextState.MODE_STROKE_ADD == mode || TextState.MODE_FILL_STROKE_ADD == mode) { - g.draw(outline); - } - g.setTransform(af); - - } - - public String toUnicode(String displayText) { - // Check string for displayable Glyphs, try and substitute any failed ones - StringBuilder sb = new StringBuilder(displayText.length()); - for (int i = 0; i < displayText.length(); i++) { - // Updated with displayable glyph when possible - sb.append(toUnicode(displayText.charAt(i))); - } - return sb.toString(); - } - - public String toUnicode(char c1) { - // the toUnicode map is used for font substitution and especially for CID fonts. If toUnicode is available - // we use it as is, if not then we can use the charDiff mapping, which takes care of font encoding - // differences. - char c = toUnicode == null ? getCharDiff(c1) : c1; - - // The problem here is that some CMapping only work properly if the - // embedded font is working properly, so that's how this logic works. - - //System.out.print((int)c + " (" + (char)c + ")"); - // check for CMap ToUnicode properties, if so we return it, no point - // jumping though the other hoops. - if (toUnicode != null) { - return toUnicode.toUnicode(c); - } - // otherwise work with a single char - c = getCMapping(c); - //System.out.print(" -> " + (int)c + " (" + (char)c + ")"); - //System.out.println(); - - // try alternate representation of character - if (!awtFont.canDisplay(c)) { - c |= 0xF000; - } - // correct the character c if possible -// if (!textState.font.font.canDisplay(c) && textState.font.font.canDisplay(c1)) { -// c = c1; -// } - - // due to different character encoding for invalid embedded fonts - // the proper font can not always be found - if (!awtFont.canDisplay(c)) { - - // try and find a similar symbol that can be displayed. - c = findAlternateSymbol(c); -// System.out.println(c + " + " + (int) c + " " + -// textState.currentfont.getName() + " " + -// textState.font.font ); - } - - // Debug code, show any undisplayable glyphs - if (log.isLoggable(Level.FINER)) { - if (!awtFont.canDisplay(c)) { - log.finer( - ((int) c1) + " " + Character.toString(c1) + " " + - (int) c + " " + c + " " + awtFont); - //+ " " + textState.font.font + " " + textState.font.font.getNumGlyphs()); - } - } - return String.valueOf(c); - } - - public ByteEncoding getByteEncoding() { - return ByteEncoding.ONE_BYTE; - } - - public Shape getEstringOutline(String displayText, float x, float y) { - - displayText = toUnicode(displayText); - FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, true); - GlyphVector glyphVector = awtFont.createGlyphVector(frc, displayText); - glyphVector.setGlyphPosition(0, new Point2D.Float(x, y)); - - // Iterate through displayText to calculate the the new advance value if - // the displayLength is greater then one character. This in sures that - // cid -> String will get displayed correctly. - int displayLength = displayText.length(); - float lastx; - if (displayLength > 1) { - Point2D p; - float advance = 0; - for (int i = 0; i < displayText.length(); i++) { - // Position of the specified glyph relative to the origin of glyphVector - p = glyphVector.getGlyphPosition(i); - lastx = (float) p.getX(); - // add fonts rise to the to glyph position (sup,sub scripts) - glyphVector.setGlyphPosition( - i, - new Point2D.Double(lastx + advance, p.getY())); - - // subtract the advance because we will be getting it from the fonts width - float adv1 = glyphVector.getGlyphMetrics(i).getAdvance(); - double adv2 = echarAdvance(displayText.charAt(i)).getX(); - advance += -adv1 + adv2 + lastx; - } - } - - return glyphVector.getOutline(); - } - - public URL getSource() { - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function.java deleted file mode 100644 index 07f1406bb8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.util.Library; - -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -/** - *

The class Function is factory responsible for creating the correct - * function type for the given "FunctionType" dictionary entry.

- *

- *

Functions in PDF represent static, self-contained numerical transformations. - * In general, a function can take any number (m) of input values and produce any - * number (n) of output values: - *

    - * f(x0,..., xm-1) = y0, ... , yn-1 - *
- *

In PDF functions, all the input values and all the output values are numbers. - * Each function definition includes a domain, the set of legal - * values for the input. Some functions also define a range, the - * set of legal values for the output. Input and output values are clipped to - * the respective domain and range. - *

- *

- *

This function factory currently support the following function types:

- *
    - *
  • type 0 - sampled function, uses a table of sample values to define the function. - * various techniques are used to interpolate values between the sampled values. - *
  • - *
  • type 2 - exponential interpolation, defines a set of - * coefficients for an exponential function. - *
  • - *
  • type 3 - stitching function, a combination of - * other functions, partitioned across a domain. - *
  • - *
  • type 4 - calculator function, uses operators from - * the PostScript language do describe an arithmetic expression. - *
  • - * - * - * @since 1.0 - */ -public abstract class Function { - - private static final Logger logger = - Logger.getLogger(Function.class.toString()); - - public static final Name FUNCTIONTYPE_NAME = new Name("FunctionType"); - public static final Name DOMAIN_NAME = new Name("Domain"); - public static final Name RANGE_NAME = new Name("Range"); - - /** - * An array of 2 x m numbers, where m is the number of input values. Input - * values outside the declared domain are clipped to the nearest boundary value. - */ - protected float[] domain; - - /** - * An array of 2 x n numbers, where n is the number of output values. Output - * values outside the declared range are clipped to the nearest boundary value. - * If this entry is absent, no clipping is done. - */ - protected float[] range; - - /** - * Function type associated with this function. - */ - protected int functionType; - - /** - *

    Creates a new instance of a Function object. Possible function types - * are:

    - *
      - *
    • 0 - sampled funciton.
    • - *
    • 2 - exponential interpolation funciton.
    • - *
    - * - * @param l document library. - * @param o dictionary or Hashmap containing Function type entries. - * @return Function object for the specified function type, null if the - * function type is not available or not defined. - */ - public static Function getFunction(Library l, Object o) { - Dictionary d = null; - - if (o instanceof Reference) { - o = l.getObject((Reference) o); - } - - // create a dictionary out of the object if possible - if (o instanceof Dictionary) { - d = (Dictionary) o; - } else if (o instanceof HashMap) { - d = new Dictionary(l, (HashMap) o); - } - - if (d != null) { - // find out what time of function type and create the appropriate - // function object. - int fType = d.getInt(FUNCTIONTYPE_NAME); - switch (fType) { - // sampled function - case 0: - return new Function_0(d); - // exponential interpolation - case 2: - return new Function_2(d); - // stitching function - case 3: - return new Function_3(d); - // PostScript calculator - case 4: - return new Function_4(d); - } - } - return null; - } - - /** - * Creates a new instance of Function object. - * - * @param d dictionary containing a vaild function dictionary. - */ - protected Function(Dictionary d) { - List dom = (List) d.getObject(DOMAIN_NAME); - domain = new float[dom.size()]; - for (int i = 0; i < dom.size(); i++) { - domain[i] = ((Number) dom.get(i)).floatValue(); - } - List r = (List) d.getObject(RANGE_NAME); - if (r != null) { - range = new float[r.size()]; - for (int i = 0; i < r.size(); i++) { - range[i] = ((Number) r.get(i)).floatValue(); - } - } - } - - /** - *

    Gets the function type number. - *

      - *
    • type 0 - sampled function, uses a table of sample values to define the function. - * various techniques are used to interpolate values between the sampled values. - *
    • - *
    • type 2 - exponential interpolation, defines a set of - * coeffiecients for an exponential function. - *
    • - *
    • type 3 - stitching function, a combination of - * other functions, partitioned across a domain. - *
    • - *
    • type 4 - calculator function, uses operators from - * the PostScript language do describe an arithmetic expression. - *
    • - * - */ - public int getFunctionType() { - return functionType; - } - - /** - *

      Interpolation function. For the given value of x, the interpolate - * calculates the y value on the line defined by the two points - * (xmin, ymin) and (xmax, ymax). - * - * @param x value we want to find a y value for. - * @param xmin point 1, x value. - * @param xmax point 2, x value. - * @param ymin point 1, y value. - * @param ymax oint 2, y value. - * @return y value for the given x value on the point define by - * (xmin, ymin) and (xmax, ymax). - */ - public static float interpolate(float x, float xmin, float xmax, float ymin, float ymax) { - return ((x - xmin) * (ymax - ymin) / (xmax - xmin)) + ymin; - } - - /** - *

      Evaluates the input values specified by m. In general, a - * function can take any number (m) of input values and produce any - * number (n) of output values: - *

        - * f(x0,..., xm-1) = y0, ... , yn-1 - *
      - * - * @param m input values to put through function. - * @return n output values. - */ - public abstract float[] calculate(float[] m); - - public float[] getDomain() { - return domain; - } - - public float[] getRange() { - return range; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_0.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_0.java deleted file mode 100644 index 183d65a236..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_0.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Stream; - -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      This class Function_0 represents a generic Type 0, sampled function - * type. Type 0 functions use a sequence of sampled values (contained in a stream) - * to produce an approximation for function whose domains and ranges are bounded. - * The samples are organized as an m-dimensional table in which each entry has n - * components.

      - *

      - *

      Sampled functions are highly general and offer reasonably accurate - * representations of arbitrary analytic functions at low expense. The - * dimensionality of a sampled function is restricted only by the implementation - * limits.

      - * - * @see Function - * @since 1.0 - */ -public class Function_0 extends Function { - - private static final Logger logger = - Logger.getLogger(Function_0.class.toString()); - - public static final Name SIZE_KEY = new Name("Size"); - public static final Name BITSPERSAMPLE_KEY = new Name("BitsPerSample"); - public static final Name ENCODE_KEY = new Name("Encode"); - public static final Name DECODE_KEY = new Name("Decode"); - - // An array of m positive integers specifying the number of samples in each - // input dimension of the sample table. - private int size[]; - - // The number of bits used to represent each sample. If the function has - // multiple output values, each one occupies BitsPerSample bits. Valid - // values are 1,2,4,8,12,16,24, and 32. - private int bitsPerSample; - - // The order of interpolation between samples. Valid values are 1 and 3, - // specifying linear and cubic spline interpolation, respectively. Default 1 - private int order; - - // An array of 2 x m numbers specifying the linear mapping of input values - // into the domain of the function's sample table. Default value: - // [0 (size0-1) 0 size1 ...]. - private float encode[]; - - // An array of 2 x n numbers specifying the linear mapping of sample values - // into the range the range appropriate for the function's output values. - // Default same as Range. - private float[] decode; - - private int[][] samples; - - /** - * Creates a new instance of a type 0 function. - * - * @param d function's dictionary. - */ - Function_0(Dictionary d) { - // initiate, domain and range - super(d); - - List s = (List) d.getObject(SIZE_KEY); - // setup size array, each entry represents the number of samples for - // each input dimension. - size = new int[s.size()]; - for (int i = 0; i < s.size(); i++) { - size[i] = (int) (((Number) s.get(i)).floatValue()); - } - // setup bitsPerSample array, each entry represents the number of bits used - // for each sample - bitsPerSample = d.getInt(BITSPERSAMPLE_KEY); - - // setup of encode table, specifies the linear mapping of input values - // into the domain of the function's sample table. - List enc = (List) d.getObject(ENCODE_KEY); - encode = new float[size.length * 2]; - if (enc != null) { - for (int i = 0; i < size.length * 2; i++) { - encode[i] = ((Number) enc.get(i)).floatValue(); - } - } else { - // encoding is optional, so fill up encode area with uniform - // mapping of 0,size[0]-1, 0,size[1]-1, 0,size[2]-1 which is - // the default value which is defined in the spec. - for (int i = 0; i < size.length; i++) { - encode[2 * i] = 0; - encode[2 * i + 1] = size[i] - 1; - } - } - - // setup decode, an array of 2 x n numbers specifying the linear mapping - // of sample values into the range appropriate for the function's output values. - List dec = (List) d.getObject(DECODE_KEY); - decode = new float[range.length]; - if (dec != null) { - for (int i = 0; i < range.length; i++) { - decode[i] = ((Number) dec.get(i)).floatValue(); - } - } else { - // decode is optional, so we should copy range as a default values - System.arraycopy(range, 0, decode, 0, range.length); - } - - // lastly get the stream byte data if any. - Stream stream = (Stream) d; - convertToSamples(stream.getDecodedStreamBytes(0), bitsPerSample); - } - - /** - * Calculates the y values for the given x values using a sampled function. - * - * @param x array of input values m. - * @return array of output value n. - */ - public float[] calculate(float[] x) { - // length of output array - int n = range.length / 2; - // ready output array - float y[] = new float[n]; - // work throw all input data and store in y[] - try { - // sampled each input value xi for 0 & i < m - for (int i = 0; i < size.length; i++) { - // clip input value appropriately for the given domain - // xi' = min (max(xi, Domain2i), Domain2i+1) - x[i] = Math.min(Math.max(x[i], domain[2 * i]), domain[2 * i + 1]); - // find the encoded value - // ei = interpolate (xi', Domain2i, Domain2i+1, Encode2i, Encode2i+1) - float e = interpolate(x[i], domain[2 * i], domain[2 * i + 1], - encode[2 * i], encode[2 * i + 1]); - // clip to the size of the sampled table in that dimension: - // ei' = min (max(ei, 0), Sizei-1) - e = Math.min(Math.max(e, 0), size[i] - 1); - // pretty sure that e1 and e2 are used to for a bilinear interpolation? - // Output values are are calculated from the nearest surrounding values - // in the sample table in the sample table. - int e1 = (int) Math.floor(e); - int e2 = (int) Math.ceil(e); - int index; - // Calculate the final output values - for (int j = 0; j < n; j++) { - // find nearest surrounding values in the sample table - int b1 = samples[e1][j]; - int b2 = samples[e2][j]; - // get the average - float r = ((float) b1 + (float) b2) / 2; - // interpolate to get output values - r = interpolate(r, 0f, (float) Math.pow(2, bitsPerSample) - - 1, decode[2 * j], decode[2 * j + 1]); - // finally, decoded values are clipped ot the range - // yj = min(max(rj', Range2j), Range2j+1) - r = Math.min(Math.max(r, range[2 * j]), range[2 * j + 1]); - index = i * n + j; - // make sure we y can contain the calculated r value - if (index < y.length) { - y[index] = r; - } - - } - } - } catch (Exception e) { - logger.log(Level.FINER, "Error calculating function 0 values", e); - } - return y; - } - - /** - * Utility for converting sample bytes to integers of the correct bits per sample. - * - * @param bytes byte array to convert. - * @param bitsPerSample bits per sample value - */ - private void convertToSamples(byte[] bytes, int bitsPerSample) { - int size = 1; - int inputMax = domain.length / 2; - int outputMax = range.length / 2; - for (int i = 0; i < inputMax; i++) { - size *= this.size[i]; - } - samples = new int[size][outputMax]; - - int sampleIndex = 0; - int byteLocation = 0; - int bitLocation = 0; - for (int i = 0; i < inputMax; i++) { - for (int j = 0; j < this.size[i]; j++) { - for (int k = 0; k < outputMax; k++) { - int value = 0; - int bitsToRead = bitsPerSample; - byte byteCount = bytes[byteLocation]; - while (bitsToRead > 0) { - int nextBit = ((byteCount >> (7 - bitLocation)) & 0x1); - value |= nextBit << (bitsToRead - 1); - bitLocation++; - // skip to the next bit. - if (bitLocation == 8) { - bitLocation = 0; - byteLocation++; - if (bitsToRead > 1) { - byteCount = bytes[byteLocation]; - } - } - bitsToRead--; - } - samples[sampleIndex][k] = value; - } - sampleIndex++; - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_2.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_2.java deleted file mode 100644 index 908fd595a1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_2.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; - -import java.util.Arrays; -import java.util.List; - -/** - *

      This class Function_2 represents a generic Type 2, exponentail - * interpolation function type. Type 2 functions include a set of parameters that - * define an exponential interpolation of one input value and n output values:

      - *

      - *

        - * f(x) = y0, ..., yn-1 - *
      - *

      - *

      Values of Domain must constrain x in such a way that if - * N is not an integer, all values of x must be non-negative, and if - * N is negative, no value of x may be zero. Typically, - * Domain is declared as [0.0 1.0], and N is a postive - * number. The Range attribute is optional and can be used to clip - * the output to a specified range. Note that when N is 1, the - * function performs a linear interpolation between C0 and - * C1; therefore, the function cna also be expressed as a sampled - * function (type 0).

      - * - * @see Function - * @since 1.0 - */ -public class Function_2 extends Function { - - public static final Name N_KEY = new Name("N"); - public static final Name C0_KEY = new Name("C0"); - public static final Name C1_KEY = new Name("C1"); - - // The interpolation exponent. Each input value x will return n values, - // given by: - // yj = COj + xN x (C1j - C0j) - // for 0 <= j < n - private float N; - - // An array of n numbers defining the function result when x = 0.0. Default - // value is [0.0] - private float C0[] = {0.0f}; - - // An array of n number defining the function result when x = 1.0. Default - // value is [1.0] - private float C1[] = {1.0f}; - - /** - * Creates a new instance of a type 2 function. - * - * @param d function's dictionary. - */ - Function_2(Dictionary d) { - super(d); - // Setup and assign N, interpolation exponent - N = d.getFloat(N_KEY); - - // Convert C0 dictionary values. - List c0 = (List) d.getObject(C0_KEY); - if (c0 != null) { - C0 = new float[c0.size()]; - for (int i = 0; i < c0.size(); i++) { - C0[i] = ((Number) c0.get(i)).floatValue(); - } - } - // legacy PDFGo code, guessing that setting default value should just - // be [0.0] and not assigned for each possible entry. - /*else { - for (int i = 0; i < range.length/2; i++) { - C0[i] = 0f; - } - }*/ - - // Convert C1 dictionary values - List c1 = (List) d.getObject(C1_KEY); - if (c1 != null) { - C1 = new float[c1.size()]; - for (int i = 0; i < c1.size(); i++) { - C1[i] = ((Number) c1.get(i)).floatValue(); - } - } - // legacy PDFGo code, guessing that setting default value should just - // be [1.0] and not assigned for each possible entry. - /*else { - for (int i = 0; i < range.length/2; i++) { - C1[i] = 1f; - } - }*/ - - } - - /** - *

      Exponential Interpolation calculation. Each input value x will return - * n values, given by:

      - *
        - * yj = - * COj + xN x (C1j - C0j), for 0 <= j < n - *
      - * - * @param x input values m - * @return output values n - */ - public float[] calculate(float[] x) { - // create output array - float y[] = new float[x.length * C0.length]; - float yValue; - // for each y value, apply exponential interpolation function - for (int i = 0; i < x.length; i++) { - // C0 and C1 should have the same length work through C0 length - for (int j = 0; j < C0.length; j++) { - // apply the function as defined above. - yValue = (float) (C0[j] + Math.pow(Math.abs(x[i]), N) * (C1[j] - C0[j])); - - // Range is optional but if present should be used to clip the output - if (range != null) - yValue = Math.min(Math.max(yValue, range[2 * j]), range[2 * j + 1]); - - // finally assign the interpolation value. - y[i * C0.length + j] = yValue; - } - } - return y; - } - - public String toString() { - return "FunctionType: " + functionType + - "\n domain: " + Arrays.toString(domain) + - "\n range: " + Arrays.toString(range) + - "\n N: " + N + - "\n C0: " + Arrays.toString(C0) + - "\n C1: " + Arrays.toString(C1); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_3.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_3.java deleted file mode 100644 index d98c7a4e4a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_3.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; - -import java.util.List; - -/** - *

      Type 3 Function (PDF 1.3) defines a stitching of the sub-domains of - * several 1-input functions to produce a single new 1-input function.

      - * - * @author ICEsoft Technologies Inc. - * @since 3.0 - */ -public class Function_3 extends Function { - - public static final Name BOUNDS_KEY = new Name("Bounds"); - public static final Name ENCODE_KEY = new Name("Encode"); - public static final Name FUNCTIONS_KEY = new Name("Functions"); - - // An array of k-1 numbers that, in combination with Domain, define the - // intervals to which each function from the Functions array applies. Bounds - // must be in order of increasing value and each value must be with in the - // domain defined by Domain - private float bounds[]; - - // An array of 2xk numbers that, taken in pairs, cMap each subset of the - // domain defined by Domain and the bounds array to the domain of the - // corresponding function. - private float encode[]; - - // An array of k 1--input functions making up the stitching function. The - // output dimensionality of all functions must be the same, and compatible - // with the values of the Range if Range is represent. - private Function functions[]; - - /** - * Creates a new instance of a type 2 function. - * - * @param d function's dictionary. - */ - Function_3(Dictionary d) { - super(d); - - // Convert bounds dictionary values. - List boundTemp = (List) d.getObject(BOUNDS_KEY); - if (boundTemp != null) { - bounds = new float[boundTemp.size()]; - for (int i = 0; i < boundTemp.size(); i++) { - bounds[i] = ((Number) boundTemp.get(i)).floatValue(); - } - } - - // convert encode dictionary. - List encodeTemp = (List) d.getObject(ENCODE_KEY); - if (encodeTemp != null) { - encode = new float[encodeTemp.size()]; - for (int i = 0; i < encodeTemp.size(); i++) { - encode[i] = ((Number) encodeTemp.get(i)).floatValue(); - } - } - - List functionTemp = (List) d.getObject(FUNCTIONS_KEY); - if (encodeTemp != null) { - functions = new Function[functionTemp.size()]; - for (int i = 0; i < functionTemp.size(); i++) { - functions[i] = Function.getFunction(d.getLibrary(), functionTemp.get(i)); -// System.out.println("Function " + functions[i].toString()); - } - } - - } - - /** - *

      Puts the value x thought the function type 3 algorithm. - * - * @param x input values m - * @return output values n - */ - public float[] calculate(float[] x) { - - int k = functions.length; - - if (k == 1 && bounds.length == 0) { - if (domain[0] <= x[0] && x[0] <= domain[1]) { - return encode(x, functions[0], 0); - } - } - - // Find where x finds into the following range: - // Domain0 < Bounds0 < Bounds1 < ... < Boundsk-2 < Domain1 - // where k = functions length. The found bound is the equivalent function - // to use to encode the x value. - for (int b = 0; b < bounds.length; b++) { - // first sub domain - if (b == 0) { - // check if domain0 <= x < bounds0, return function if true - if (domain[0] <= x[0] && x[0] < bounds[b]) { - return encode(x, functions[b], b); - } - } - // last sub domain - if (b == k - 2) { - // check if bounds k-2 <= x <= domain 0, return function if true - if (bounds[b] <= x[0] && x[0] <= domain[1]) { - return encode(x, functions[k - 1], k - 1); - } - } - // bounds <= x < bounds b + 1, return function if true - if (bounds[b] <= x[0] && x[0] < bounds[b + 1]) { - return encode(x, functions[b], b); - } - } - - return null; - } - - /** - * Utility method to apply the interpolation rules and finally calculate - * the return value using the selected function. The method also checks - * to see if the values fall in the specified range and makes the - * appropriate adjustments, if range is present. - * - * @param x one element array, - * @param function function to be applied can be of any type. - * @param i i th subdomain, selected subdomain. - * @return n length array of calculated values. n length is defined by the - * colour space component count. - */ - private float[] encode(float[] x, Function function, int i) { - int k = functions.length; - - if (i <= 0 && i < k && bounds.length > 0) { - - float b1; - float b2; - if (i - 1 == -1) { - // domain 0 - b1 = domain[0]; - } else { - b1 = bounds[i - 1]; - } - if (i == k - 1) { - // domain 1 - b2 = domain[1]; - } else { - b2 = bounds[i]; - } - - if (k - 2 < bounds.length && bounds[k - 2] == domain[1]) { - x[0] = encode[2 * i]; - } - - x[0] = interpolate(x[0], b1, b2, encode[2 * i], encode[2 * i + 1]); - - x = function.calculate(x); - } else { - x[0] = interpolate(x[0], domain[0], domain[1], encode[2 * i], encode[2 * i + 1]); - x = function.calculate(x); - } - - // Have seen a few corner cases where the bounds are not defined or are null. There is nothing - // in the spec about how to handle this, so the work around below is experimental. - if (x != null) { - return validateAgainstRange(x); - } else { - return new float[]{1, 1, 1, 1}; - } - - } - - /** - * Utility method to check if the values fall within the functions range. - * - * @param values values to test against range. - * @return correct values that fall within the functions range. - */ - private float[] validateAgainstRange(float[] values) { - - // Range is an array of 2xn numbers, where n is the number of output - // values. - - for (int j = 0, max = values.length; j < max; j++) { - if (range != null && values[j] < range[2 * j]) { - values[j] = range[2 * j]; - } else if (range != null && values[j] > range[(2 * j) + 1]) { - values[j] = range[(2 * j) + 1]; - } else if (values[j] < 0) { - values[j] = 0.0f; - } - } - return values; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_4.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_4.java deleted file mode 100644 index 24ce9f27d2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/Function_4.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.functions.postscript.Lexer; -import org.icepdf.core.util.Utils; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.Stack; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      Type 4 Function (PDF 1.3), also called a PostScript calculator function, - * shall be represented as a stream containing code written n a small subset of - * the PostScript language.

      - *

      Type 4 functions offer greater flexibility and potentially greater - * accuracy then exponential functions (type 2 functions). Type 4 functions - * also make it possible to include a wide variety of halftone spots functions - * without the loss of accuracy that comes from sampling, and without adding to - * the list a predefined spot function (10.5.3 spot functions). All of the - * predefined spot functions can be written as type 4 functions.

      - * - * @author ICEsoft Technologies Inc. - * @since 4.2 - */ -public class Function_4 extends Function { - - private static final Logger logger = - Logger.getLogger(Function_4.class.toString()); - - // decoded content that makes up the type 4 functions. - private byte[] functionContent; - - // cache for calculated colour values - private ConcurrentHashMap resultCache; - - public Function_4(Dictionary d) { - super(d); - // decode the stream for parsing. - if (d instanceof Stream) { - Stream functionStream = (Stream) d; - functionContent = functionStream.getDecodedStreamBytes(0); - if (logger.isLoggable(Level.FINER)) { - logger.finer("Function 4: " + Utils.convertByteArrayToByteString(functionContent)); - } - - } else { - logger.warning("Type 4 function operands could not be found."); - } - // cache for type 4 function results. - resultCache = new ConcurrentHashMap(); - } - - /** - *

      Puts the value x thought the function type 4 algorithm. - * - * @param x input values m - * @return output values n - */ - public float[] calculate(float[] x) { - - // check the cache in case we've already made the calculation. - Integer colourKey = calculateColourKey(x); - float[] result = resultCache.get(colourKey); - if (result != null) { - return result; - } - - // setup the lexer stream - InputStream content = new ByteArrayInputStream(functionContent); - Lexer lex = new Lexer(); - lex.setInputStream(content); - - // parse/evaluate the type 4 functions with the input value(s) x. - try { - lex.parse(x); - } catch (Throwable e) { - logger.log(Level.WARNING, "Error Processing Type 4 definition", e); - } - - // get the remaining number on the stack which are the return values. - Stack stack = lex.getStack(); - - // length of output array - int n = range.length / 2; - // ready output array - float y[] = new float[n]; - - // pop remaining items off the stack and apply the range bounds. - for (int i = 0; i < n; i++) { - y[i] = Math.min(Math.max((Float) stack.elementAt(i), - range[2 * i]), range[2 * i + 1]); - } - // add the new value to the cache. - resultCache.put(colourKey, y); - return y; - } - - /** - * Utility for creating a comparable colour key for colour components. - * - * @param colours one or more colour values, usually maxes out at four. - * @return concatenation of colour values. - */ - private Integer calculateColourKey(float[] colours) { - int length = colours.length; - // only works for colour vlues 0-255 - if (!(colours[0] <= 1.0)) { - if (length == 1) { - return (int) colours[0]; - } else if (length == 2) { - return ((int) colours[1] << 8) | (int) colours[0]; - } else if (length == 3) { - return ((int) colours[2] << 16) | - ((int) colours[1] << 8) | (int) colours[0]; - } - } - // otherwise expensive hash generation. - StringBuilder builder = new StringBuilder(); - for (float colour : colours) { - builder.append(colour); - } - return builder.toString().hashCode(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Expression.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Expression.java deleted file mode 100644 index d5876cb5cc..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Expression.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions.postscript; - -import java.util.Stack; - -/** - * Representing a generic Expression which follows the Command pattern for delayed - * or differed execution. Expression is just another type of Operator but we - * can use an instanceof check to find occurrences of the object. - * - * @author ICEsoft Technologies Inc. - * @since 4.2 - */ -public class Expression extends Operator { - - - protected Expression(int type) { - super(type); - } - - @Override - public void eval(Stack stack) { - // nothing to do for an expression - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Lexer.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Lexer.java deleted file mode 100644 index 69c4844c5f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Lexer.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions.postscript; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.Stack; - -/** - * A state machine used to parse valid type 4 functions tokens in a input - * stream. As the tokens are parsed found operands are executed to mananipulate - * the stack. - * - * @author ICEsoft Technologies Inc. - * @since 4.2 - */ -public class Lexer { - - // stream reader pointers. - private Reader reader; - private char[] buf = new char[2056]; - private int pos = 0, numRead = 0, startTokenPos = 0; - private int tokenType = 0; - // expression depth count used to properly differ if and elseif operands. - private int expressionDepth; - - // lexer states - private static final int - TOKEN_NUMBER = 1, - TOKEN_OPERAND = 2, - TOKEN_EXPRESSION = 3, - TOKEN_BOOLEAN = 5; - - // procedure isa any {expression...} - private Procedure procedures; - private Procedure currentProcedure; - - public Lexer() { - procedures = new Procedure(null); - } - - /** - * Type 4 function input stream to pars.e - * - * @param in type 4 function input stream. - */ - public void setInputStream(InputStream in) { - setReader(new InputStreamReader(in)); - } - - protected void setReader(Reader reader) { - this.reader = reader; - } - - /** - * Parse the input stream associated with this instance. - * - * @param input array of 1 or more numbers to be pushed onto the stack before - * the type 4 function is executed. - * @throws IOException if the input stream is null or incomplete. - */ - public void parse(float[] input) throws IOException { - - if (reader == null) { - throw new IOException("Type 4 function, null input stream reader."); - } - - // set current procedure which is the root {}. - currentProcedure = procedures; - - // push input values on the stack - for (Number num : input) { - currentProcedure.getProc().push(num); - } - - tokenType = TOKEN_EXPRESSION; - - boolean done = false; - while (!done) { - - // Did we reach the end of the buffer, if so copy the next block - // of data into the buffer. - if (pos == buf.length) { - // Copy the start of the token to the beginning - System.arraycopy(buf, startTokenPos, buf, 0, pos - startTokenPos); - pos = buf.length - startTokenPos; - startTokenPos = 0; - numRead = pos; - } - // Read at pos position - int n = reader.read(buf, pos, buf.length - pos); - if (n <= 0) break; - numRead += n; - - // Scan to the numRead - while (pos < numRead) { - if (tokenType == TOKEN_NUMBER) { - numberStart(); - } else if (tokenType == TOKEN_OPERAND) { - operandStart(); - } else if (tokenType == TOKEN_BOOLEAN) { - booleanStart(); - } else if (tokenType == TOKEN_EXPRESSION) { - expressionStart(); - } - } - } - } - - /** - * Gets the stack associated with this lexer. Once parse has successfully - * executed the stack will contain n numbers which represent the type 4 - * function output. - * - * @return stack containing the output of the type 4 function. If #parse() - * was not called the stack will be empty - */ - public Stack getStack() { - return procedures.getProc(); - } - - /** - * Utility to find the next token state. - */ - private void parseNextState() { - while (pos < numRead) { - if (!(buf[pos] == ' ' || buf[pos] == '\t' || - buf[pos] == '\n' || buf[pos] == '\r')) { - break; - } - pos++; - } - - // We found the end - if (pos < numRead) { - startTokenPos = pos; - // look for number tokens. - if (buf[pos] < 'A') { - tokenType = TOKEN_NUMBER; - } - // else we have a boolean or operand. - else { - // look for a boolean - if ((buf[pos] == 'f' && buf[pos + 1] == 'a') || - (buf[pos] == 't' && buf[pos + 3] == 'e')) { - tokenType = TOKEN_BOOLEAN; - } - // otherwise we have an operand. - else if (buf[pos] < '{') { - tokenType = TOKEN_OPERAND; - } - // special expression or procedure definition - else if (buf[pos] == '{' || buf[pos] == '}') { - tokenType = TOKEN_EXPRESSION; - } else { - parseNextState(); - } - } - } - } - - /** - * Utility to find an expression {some opps}. We always ignore the first - * as it is the start of the function but all other will be assoicated with - * a if or elseif operand and as a result we don't eval the containing - * operands until the if or elseif operand is encountered. - */ - private void expressionStart() { - while (pos < numRead) { - // need to revisit the logic here, seems overly complicated. - if (!(buf[pos] == '{' || buf[pos] == '}')) { - break; - } - // corner case, no space between '}{' in {exp}{exp} - if (pos + 1 < numRead && buf[pos] == '}' && buf[pos + 1] == '{') { - pos++; - break; - } - pos++; - } - if (pos < numRead) { - Operator operand = OperatorFactory.getOperator(buf, - startTokenPos, pos - startTokenPos); - // found a start - if (operand.getType() == OperatorNames.OP_EXP_START) { - expressionDepth++; - if (expressionDepth > 1) { - currentProcedure = new Procedure(currentProcedure); - } - } - // found '}' so we decrement our depth count. - if (operand.getType() == OperatorNames.OP_EXP_END) { - currentProcedure = currentProcedure.getPrevious(); - expressionDepth--; - } - } - // go baby go! - parseNextState(); - } - - /** - * Utility for processing the operand state. - */ - private void operandStart() { - startTokenPos = pos; - while (pos < numRead) { - if (isDelimiter(buf[pos])) { - break; - } - pos++; - } - if (pos < numRead && pos > startTokenPos) { - Operator operand = OperatorFactory.getOperator(buf, startTokenPos, pos - startTokenPos); - // execute differed execution by looking at expression depth. - if (expressionDepth > 1) { - currentProcedure.getProc().push(operand); - } else { - // execute the operand - operand.eval(currentProcedure.getProc()); - } - } - parseNextState(); - } - - /** - * Utility of processing a number state. - */ - private void numberStart() { - startTokenPos = pos; - while (pos < numRead) { - if (isDelimiter(buf[pos])) { - break; - } - pos++; - } - if (pos < numRead) { - // push the number - currentProcedure.getProc().push(Float.parseFloat(new String(buf, startTokenPos, pos - startTokenPos))); - } - parseNextState(); - } - - /** - * Utility for processing boolean - */ - private void booleanStart() { - while (pos < numRead) { - if (isDelimiter(buf[pos])) { - break; - } - pos++; - } - if (pos < numRead) { - currentProcedure.getProc().push(Boolean.valueOf(new String(buf, startTokenPos, pos - startTokenPos))); - } - parseNextState(); - } - - /** - * Utility for finding token delimiter in a type 4 function stream. - * - * @param c character to compare against known delimiters. - * @return true if c is a delimiter otherwise, false. - */ - private static boolean isDelimiter(char c) { - return c == ' ' || c == '\t' || - c == '\n' || c == '\r' || - c == '{' || c == '}'; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/LexerText.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/LexerText.java deleted file mode 100644 index 98032a7e7e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/LexerText.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions.postscript; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * Simple type 4 function tests. - * - * @author ICEsoft Technologies Inc. - * @since 4.2 - */ -public class LexerText { - - public static final String TEST_1 = - "{1.000000 3 1 roll 1.000000 3 1 roll 1.000000 3 1 roll 5 -1 roll \n" + - "2 index -0.874500 mul 1.000000 add mul 1 index -0.098000 mul 1.000000 add mul 5 \n" + - "1 roll 4 -1 roll 2 index -0.796100 mul 1.000000 add mul 1 index -0.247100 \n" + - "mul 1.000000 add mul 4 1 roll 3 -1 roll 2 index -0.647100 mul 1.000000 \n" + - "add mul 1 index -0.878400 mul 1.000000 add mul 3 1 roll pop pop }"; - - public static final String TEST_2 = - "{1.000000 2 1 roll 1.000000 2 1 roll 1.000000 2 1 roll 0 index 1.000000 \n" + - "cvr exch sub 2 1 roll 5 -1 roll 1.000000 cvr exch sub 5 1 \n" + - "roll 4 -1 roll 1.000000 cvr exch sub 4 1 roll 3 -1 roll 1.000000 \n" + - "cvr exch sub 3 1 roll 2 -1 roll 1.000000 cvr exch sub 2 1 \n" + - "roll pop }"; - - public static final String TEST_3 = - "{0 0 0 0 5 4 roll 0 index 3 -1 roll add 2 1 roll pop dup 1 gt {pop 1} if " + - "4 1 roll dup 1 gt {pop 1} if 4 1 roll dup 1 gt {pop 1} if 4 1 roll dup 1 gt {pop 1} if 4 1 roll}"; - - public static final String TEST_4 = - "{dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 0 index 1 exp 1 mul 0 add dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 1 index 1 exp 0 mul 0 add dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 2 index 1 exp 0 mul 0 add dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 3 index 1 exp 0 mul 0 add dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 5 4 roll pop }"; - - public static void main(String[] args) { - - try { -// new LexerText().test5(); - new LexerText().test8(); - - } catch (IOException e) { - e.printStackTrace(); - } - } - - public void test1() throws IOException { - String test = - "{1.000000 3 1 roll 1.000000 3 1 roll 1.000000 3 1 roll 5 -1 roll \n" + - "2 index -0.874500 mul 1.000000 add mul 1 index -0.098000 mul 1.000000 add mul 5 \n" + - "1 roll 4 -1 roll 2 index -0.796100 mul 1.000000 add mul 1 index -0.247100 \n" + - "mul 1.000000 add mul 4 1 roll 3 -1 roll 2 index -0.647100 mul 1.000000 \n" + - "add mul 1 index -0.878400 mul 1.000000 add mul 3 1 roll pop pop }"; - ; - - InputStream function_4 = new ByteArrayInputStream(test.getBytes()); - Lexer lex = new Lexer(); - lex.setInputStream(function_4); - lex.parse(new float[]{1.0f, 1.0f}); - - System.out.println("result: " + lex.getStack().toString()); - } - - public void test2() throws IOException { - String test = - "{2 index 1.000000 cvr exch sub 4 1 roll 1 index 1.000000 cvr exch sub \n" + - "4 1 roll 0 index 1.000000 cvr exch sub 4 1 roll 1.000000 4 1 \n" + - "roll 7 -1 roll 1.000000 cvr exch sub 7 1 roll 6 -1 roll 1.000000 \n" + - "cvr exch sub 6 1 roll 5 -1 roll 1.000000 cvr exch sub 5 1 \n" + - "roll 4 -1 roll 1.000000 cvr exch sub 4 1 roll pop pop pop }"; - - InputStream function_4 = new ByteArrayInputStream(test.getBytes()); - Lexer lex = new Lexer(); - lex.setInputStream(function_4); - lex.parse(new float[]{0.360779f, 0.094238274f, 0.00392151f}); - - System.out.println("result: " + lex.getStack().toString()); - } - - // ficha--3--para+impresion.pdf page 1 - function CORRECT - public void test5() throws IOException { - String test = - "{2 index 1.000000 cvr exch sub 4 1 roll 1 index 1.000000 cvr exch sub \n" + - "4 1 roll 0 index 1.000000 cvr exch sub 4 1 roll 1.000000 4 1 \n" + - "roll 7 -1 roll 1.000000 cvr exch sub 7 1 roll 6 -1 roll 1.000000 \n" + - "cvr exch sub 6 1 roll 5 -1 roll 1.000000 cvr exch sub 5 1 \n" + - "roll 4 -1 roll 1.000000 cvr exch sub 4 1 roll pop pop pop }"; - - InputStream function_4 = new ByteArrayInputStream(test.getBytes()); - Lexer lex = new Lexer(); - lex.setInputStream(function_4); - lex.parse(new float[]{0.360779f, 0.094238274f, 0.00392151f}); - - System.out.println("result: " + lex.getStack().toString()); - } - - // ficha--3--para+impresion.pdf page 2 - function 1 NOT CORRECT? - public void test6() throws IOException { - String test = - "{1.000000 2 1 roll 1.000000 2 1 roll 1.000000 2 1 roll 0 index 1.000000 \n" + - "cvr exch sub 2 1 roll 5 -1 roll 1.000000 cvr exch sub 5 1 \n" + - "roll 4 -1 roll 1.000000 cvr exch sub 4 1 roll 3 -1 roll 1.000000 \n" + - "cvr exch sub 3 1 roll 2 -1 roll 1.000000 cvr exch sub 2 1 \n" + - "roll pop }"; - - InputStream function_4 = new ByteArrayInputStream(test.getBytes()); - Lexer lex = new Lexer(); - lex.setInputStream(function_4); - lex.parse(new float[]{0.300003f}); - - System.out.println("result: " + lex.getStack().toString()); - - // length of output array - int n = 4; - float[] range = new float[]{0, 1, 0, 1, 0, 1, 0, 1}; - // ready output array - float y[] = new float[n]; - - System.out.println(); - float value; - for (int i = 0; i < n; i++) { - value = (Float) lex.getStack().elementAt(i); - y[i] = Math.min(Math.max(value, range[2 * i]), range[2 * i + 1]); - System.out.print(y[i] + ", "); - } - System.out.println(); - } - - // 9560_test.pdf page 2 - function 1 NOT CORRECT? - public void test7() throws IOException { - String test = - "{0 0 0 0 5 4 roll 0 index 3 -1 roll add 2 1 roll pop dup 1 gt " + - "{pop 1} if 4 1 roll dup 1 gt {pop 1} if 4 1 roll dup 1 gt " + - "{pop 1} if 4 1 roll dup 1 gt {pop 1} if 4 1 roll}"; - - InputStream function_4 = new ByteArrayInputStream(test.getBytes()); - Lexer lex = new Lexer(); - lex.setInputStream(function_4); - lex.parse(new float[]{1f}); - - System.out.println("result: " + lex.getStack().toString()); - - // length of output array - int n = 4; - float[] range = new float[]{0, 1, 0, 1, 0, 1, 0, 1}; - // ready output array - float y[] = new float[n]; - - System.out.println(); - float value; - for (int i = 0; i < n; i++) { - value = (Float) lex.getStack().elementAt(i); - y[i] = Math.min(Math.max(value, range[2 * i]), range[2 * i + 1]); - System.out.print(y[i] + ", "); - } - System.out.println(); - } - - public void test8() throws IOException { - String test = - "{dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 0 index 1 exp 1 mul 0 add dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 1 index 1 exp 0 mul 0 add dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 2 index 1 exp 0 mul 0 add dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 3 index 1 exp 0 mul 0 add dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse 5 4 roll pop }"; - - InputStream function_4 = new ByteArrayInputStream(test.getBytes()); - Lexer lex = new Lexer(); - lex.setInputStream(function_4); - lex.parse(new float[]{1.0f}); - - System.out.println("result: " + lex.getStack().toString()); - - // length of output array - int n = 4; - float[] range = new float[]{0, 1, 0, 1, 0, 1, 0, 1}; - // ready output array - float y[] = new float[n]; - - // domain = 0, 1, 0, 1, 0, 1 - System.out.println(); - float value; - for (int i = 0; i < n; i++) { - value = (Float) lex.getStack().elementAt(i); - y[i] = Math.min(Math.max(value, range[2 * i]), range[2 * i + 1]); - System.out.print(y[i] + ", "); - } - System.out.println(); - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Operator.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Operator.java deleted file mode 100644 index 3a94e58154..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Operator.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions.postscript; - -import java.util.Stack; - -/** - * Representing a generic operand which follows the Command pattern for delayed - * or differed execution. - * - * @author ICEsoft Technologies Inc. - * @since 4.2 - */ -public abstract class Operator { - - protected int type; - - protected Operator(int type) { - this.type = type; - } - - public abstract void eval(Stack stack); - - public boolean equals(Object op) { - return (op instanceof Operator) && ((Operator) op).type == type; - } - - public int getType() { - return type; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/OperatorFactory.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/OperatorFactory.java deleted file mode 100644 index 6c947b1793..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/OperatorFactory.java +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions.postscript; - -import java.util.Stack; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Operator factory takes a operand char offset and quickly returns a Operator - * object which contains the respective operator evaluation logic. The calling - * method can defer the execution of operator as needed. - * - * @author ICEsoft Technologies Inc. - * @since 4.2 - */ -public class OperatorFactory { - - private static ConcurrentHashMap operatorCache = - new ConcurrentHashMap(); - - @SuppressWarnings(value = "unchecked") - public static Operator getOperator(char ch[], int offset, int length) { - - // get the operator int value. - final int operatorType = OperatorNames.getType(ch, offset, length); - - // check operator cache - Operator operator = operatorCache.get(operatorType); - if (operator != null) { - return operator; - } - // build the operation, consider added a few if range checks to limit - // the number of compares. - switch (operatorType) { - /** - * num1 abs = num2 - * 4.5 abs -> 4.5 - * 3 abs -> 3 - * 0 abs -> 0 - */ - case OperatorNames.OP_ABS: - operator = new Operator(OperatorNames.OP_ABS) { - public void eval(Stack stack) { - Float num = (Float) stack.pop(); - stack.push(Math.abs(num)); - } - }; - break; - /** - * num1 num2 add = sum - * 3 4 add -> 7 - * 9.9 1.1 add -> 11.0 - */ - case OperatorNames.OP_ADD: - operator = new Operator(OperatorNames.OP_ADD) { - public void eval(Stack stack) { - Float num2 = (Float) stack.pop(); - Float num1 = (Float) stack.pop(); - stack.push(num1 + num2); - } - }; - break; - /** - * bool1 bool2 and = bool3 - * int1 int2 and = int3 - * true true and -> true % A complete truth table - * true false and -> false - * false true and -> false - * false false and -> false - * 99 1 and -> 1 - * 52 7 and -> 4 - */ - case OperatorNames.OP_AND: - operator = new Operator(OperatorNames.OP_AND) { - public void eval(Stack stack) { - Object value = stack.pop(); - if (value instanceof Boolean) { - boolean bool2 = (Boolean) value; - boolean bool1 = (Boolean) stack.pop(); - stack.push(bool1 && bool2); - } else { - int val1 = ((Float) value).intValue(); - int val2 = ((Float) stack.pop()).intValue(); - stack.push(val1 & val2); - } - } - }; - break; - /*** - * num den atan = angle - * 0 1 atan -> 0.0 - * 1 0 atan -> 90.0 - * -100 0 atan -> 270.0 - * 4 4 atan -> 45.0 - */ - case OperatorNames.OP_ATAN: - operator = new Operator(OperatorNames.OP_ATAN) { - public void eval(Stack stack) { - float den = (Float) stack.pop(); - float num = (Float) stack.pop(); - stack.push(((Number) Math.toDegrees(Math.atan(num / den))).floatValue()); - } - }; - break; - /*** - * int1 shift bitshift int2 - * 07 3 bitshift -> 56 - * 142 3 bitshift -> 17 - */ - case OperatorNames.OP_BITSHIFT: - operator = new Operator(OperatorNames.OP_BITSHIFT) { - public void eval(Stack stack) { - long shift = (Long) stack.pop(); - long int1 = (Long) stack.pop(); - stack.push(int1 << shift); - } - }; - break; - /** - * num1 ceiling = num2 - * 3.2 ceiling -> 4.0 - * 4.8 ceiling -> 4.0 - * 99 ceiling -> 99 - */ - case OperatorNames.OP_CEILING: - operator = new Operator(OperatorNames.OP_CEILING) { - public void eval(Stack stack) { - float num1 = (Float) stack.pop(); - stack.push(((Number) Math.ceil(num1)).floatValue()); - } - }; - break; - /** - * aAngle cos = real - * 0 cos -> 1.0 - * 90 cos -> 0.0 - */ - case OperatorNames.OP_COS: - operator = new Operator(OperatorNames.OP_COS) { - public void eval(Stack stack) { - float aAngle = (Float) stack.pop(); - stack.push(((Number) Math.cos(aAngle)).floatValue()); - } - }; - break; - /** - * any1 ... anyn n copy any1 ... anyn any1 ... anyn - * - * array1 array2 copy subarray2 - * dict1 dict2 copy dict2 - * string1 string2 copy substring2 - * packedarray1 array2 copy subarray2 - * gstate1 gstate2 copy gstate2 - * - * (a) (b) (c) 2 copy -> (a) (b) (c) (b) (c) - * (a) (b) (c) 0 copy -> (a) (b) (c) - */ - case OperatorNames.OP_COPY: - operator = new Operator(OperatorNames.OP_COPY) { - public void eval(Stack stack) { - int n = ((Float) stack.pop()).intValue(); - int top = stack.size(); - for (int i = top - n; i < top; i++) { - stack.push(stack.get(i)); - } - } - }; - break; - /** - * num cvi = int - * string cvi = int - * - * (3.3E1) cvi -> 33 - * 47.8 cvi -> 47 - * 520.9 cvi -> 520 - */ - case OperatorNames.OP_CVI: - operator = new Operator(OperatorNames.OP_CVI) { - public void eval(Stack stack) { - // doesn't really convert to int but not a bit deal for - // java in general. - int number = ((Float) stack.pop()).intValue(); - stack.push(number); - } - }; - break; - /** - * num cvr real - * string cvr real - */ - case OperatorNames.OP_CVR: - operator = new Operator(OperatorNames.OP_CVR) { - public void eval(Stack stack) { - // doesn't really convert to int but not a bit deal for - // java in general. - float number = (Float) stack.pop(); - stack.push(number); - } - }; - break; - /** - * num1 num2 div quotient - * 3 2 div -> 1.5 - * 4 2 div -> 2.0 - */ - case OperatorNames.OP_DIV: - operator = new Operator(OperatorNames.OP_DIV) { - public void eval(Stack stack) { - // doesn't really convert to int but not a bit deal for - // java in general. - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push(num1 / num2); - } - }; - break; - /** - * any dup = any any - * duplicates the top element on the operand stack - */ - case OperatorNames.OP_DUP: - operator = new Operator(OperatorNames.OP_DUP) { - public void eval(Stack stack) { - // peek and push should give us the duplication. - stack.push(stack.peek()); - } - }; - break; - /** - * any1 any2 eq bool - * pops two objects from the operand stack and pushes true if they - * are equal, or false if not. - */ - case OperatorNames.OP_EQ: - operator = new Operator(OperatorNames.OP_EQ) { - public void eval(Stack stack) { - Object any2 = stack.pop(); - Object any1 = stack.pop(); - stack.push(any1.equals(any2)); - } - }; - break; - /** - * any1 any2 exch any2 any1 - * exchanges the top two elements on the operand stack. - * 1 2 exch -> 2 1 - */ - case OperatorNames.OP_EXCH: - operator = new Operator(OperatorNames.OP_EXCH) { - public void eval(Stack stack) { - Object any2 = stack.pop(); - Object any1 = stack.pop(); - stack.push(any2); - stack.push(any1); - } - }; - break; - /** - * base exponent exp = real - * 9 0.5 exp -> 3.0 - * -9 -1 exp -> -0.111111 - */ - case OperatorNames.OP_EXP: - operator = new Operator(OperatorNames.OP_EXP) { - public void eval(Stack stack) { - float exponent = (Float) stack.pop(); - float base = (Float) stack.pop(); - stack.push(((Number) Math.pow(base, exponent)).floatValue()); - } - }; - break; - /** - * num1 floor num2 - * 3.2 floor -> 3.0 - * -4.8 floor -> -5.0 - * 99 floor -> 99 - */ - case OperatorNames.OP_FLOOR: - operator = new Operator(OperatorNames.OP_FLOOR) { - public void eval(Stack stack) { - float num1 = (Float) stack.pop(); - stack.push(((Number) Math.floor(num1)).floatValue()); - } - }; - break; - /** - * num1 num2 ge bool - * string1 string2 ge bool - * - * pops two objects from the operand stack and pushes true if the - * first operand iS greater than or equal to the second, or false - * otherwise. - * 4.2 4 ge -> true - * (abc) (d) ge -> false - * (aba) (ab) ge -> true - * (aba) (aba) ge -> true - */ - case OperatorNames.OP_GE: - operator = new Operator(OperatorNames.OP_GE) { - public void eval(Stack stack) { - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push(num1 >= num2); - } - }; - break; - /** - * num1 num2 gt bool - * string1 string2 gt bool (not implemented) - */ - case OperatorNames.OP_GT: - operator = new Operator(OperatorNames.OP_GT) { - public void eval(Stack stack) { - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push(num1 > num2); - } - }; - break; - /** - * int1 int2 idiv quotient - * - * divides int1 by int2 and returns the integer part of the quotient, - * with any fractional part discarded. Both operands of idiv must - * be integers and the result is an integer. - * Examples - * 3 2 idiv -> 1 - * 4 2 idiv -> 2 - * -5 2 idiv -> -2 - */ - case OperatorNames.OP_IDIV: - operator = new Operator(OperatorNames.OP_IDIV) { - public void eval(Stack stack) { - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push((int) (num1 / num2)); - } - }; - break; - /** - * bool expression if - * removes both operands from the stack, then executes proc if bool is true. - * - * 3 4 lt {(3 is less than 4)} if -> (3 is less than 4) - */ - case OperatorNames.OP_IF: - operator = new Operator(OperatorNames.OP_IF) { - public void eval(Stack stack) { - // pop off the express so we can get at the bool - // if we don't have an Expression we can't continue. - Procedure proc1 = null; - if (stack.peek() instanceof Procedure) { - proc1 = (Procedure) stack.pop(); - } - boolean bool = (Boolean) stack.pop(); - // process expression 'if' expression is true - if (bool) { - proc1.eval(stack); - } - } - }; - break; - /** - * bool proc1 proc2 ifelse - - * removes all three operands from the stack, then executes proc1 - * if bool is true or proc2 if bool is false. - * - * 3 4 lt {(3 is less than 4)} if -> (3 is less than 4) - */ - case OperatorNames.OP_IFELSE: - operator = new Operator(OperatorNames.OP_IFELSE) { - public void eval(Stack stack) { - // if we don't have an Expression we can't continue. - Procedure proc2 = null, proc1 = null; - if (stack.peek() instanceof Procedure) { - proc2 = (Procedure) stack.pop(); - } - if (stack.peek() instanceof Procedure) { - proc1 = (Procedure) stack.pop(); - } - boolean bool = (Boolean) stack.pop(); - // process ifelse clause - if (bool) { - proc1.eval(stack); - } else { - proc2.eval(stack); - } - } - }; - break; - /** - * anyn ... any0 n index anyn ... any0 anyn - * - * removes the nonnegative integer n from the operand stack, counts - * down to the nth element from the top of the stack, and pushes a - * copy of that element on the stack. - * (a) (b) (c) (d) 0 index -> (a) (b) (c) (d) (d) - * (a) (b) (c) (d) 3 index -> (a) (b) (c) (d) (a) - */ - case OperatorNames.OP_INDEX: - operator = new Operator(OperatorNames.OP_INDEX) { - public void eval(Stack stack) { - float n = (Float) stack.pop(); - stack.push(stack.get((int) ((stack.size() - 1) - n))); - } - }; - break; - /** - * num1 num2 le bool - * string1 string2 le bool - * - * pops two objects from the operand stack and pushes true if the - * first operand is less than or equal to the second, or false - * otherwise. - */ - case OperatorNames.OP_LE: - operator = new Operator(OperatorNames.OP_LE) { - public void eval(Stack stack) { - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push(num1 <= num2); - } - }; - break; - /** - * num ln real - * returns the natural logarithm (base e) of num. - */ - case OperatorNames.OP_LN: - operator = new Operator(OperatorNames.OP_LN) { - public void eval(Stack stack) { - float num = (Float) stack.pop(); - stack.push(((Number) Math.log(num)).floatValue()); - } - }; - break; - /** - * num log real - * returns the common logarithm (base 10) of num. - */ - case OperatorNames.OP_LOG: - operator = new Operator(OperatorNames.OP_LOG) { - public void eval(Stack stack) { - float num = (Float) stack.pop(); - stack.push(((Number) Math.log10(num)).floatValue()); - } - }; - break; - /** - * num1 num2 lt bool - */ - case OperatorNames.OP_LT: - operator = new Operator(OperatorNames.OP_LT) { - public void eval(Stack stack) { - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push(num1 < num2); - } - }; - break; - /** - * int1 int2 mod remainder - * returns the remainder that results from dividing int1 by int2. - */ - case OperatorNames.OP_MOD: - operator = new Operator(OperatorNames.OP_MOD) { - public void eval(Stack stack) { - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push(num1 % num2); - } - }; - break; - /** - * num1 num2 mul product - * returns the product of num1 and num2. - */ - case OperatorNames.OP_MUL: - operator = new Operator(OperatorNames.OP_MUL) { - public void eval(Stack stack) { - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push(num1 * num2); - } - }; - break; - /** - * any1 any2 ne bool - * pops two objects from the operand stack and pushes false if they - * are equal, or true if not. - */ - case OperatorNames.OP_NE: - operator = new Operator(OperatorNames.OP_NE) { - public void eval(Stack stack) { - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push(num1 != num2); - } - }; - break; - /** - * num1 neg num2 - * returns the negative of num1. - */ - case OperatorNames.OP_NEG: - operator = new Operator(OperatorNames.OP_NEG) { - public void eval(Stack stack) { - float num1 = (Float) stack.pop(); - stack.push(-num1); - } - }; - break; - /** - * bool1 not bool2 - * returns the logical negation of the operand if it is boolean - */ - case OperatorNames.OP_NOT: - operator = new Operator(OperatorNames.OP_NOT) { - public void eval(Stack stack) { - boolean num1 = (Boolean) stack.pop(); - stack.push(!num1); - } - }; - break; - /** - * bool1 bool2 or bool3 - * returns the logical disjunction of the operands if they are boolean. - */ - case OperatorNames.OP_OR: - operator = new Operator(OperatorNames.OP_OR) { - public void eval(Stack stack) { - boolean bool2 = (Boolean) stack.pop(); - boolean bool1 = (Boolean) stack.pop(); - stack.push(bool1 || bool2); - } - }; - break; - /** - * any pop - * removes the top element from the operand stack and discards it. - */ - case OperatorNames.OP_POP: - operator = new Operator(OperatorNames.OP_POP) { - public void eval(Stack stack) { - stack.pop(); - } - }; - break; - /** - * anyn-1 ... any0 n j roll any (j-1) mod n ... any0 anyn-1 ... anyj mod n - * - * performs a circular shift of the objects anyn-1 through any0 on - * the operand stack by the amount j. Positive j indicates upward - * motion on the stack, whereas negative j indicates downward motion. - * n must be a nonnegative integer and j must be an integer. roll - * first removes these operands from the stack; there must be at - * least n additional elements. It then performs a circular shift - * of these n elements by j positions. If j is positive, each shift - * consists of removing an element from the top of the stack and - * inserting it between element n - 1 and element n of the stack, - * moving all in tervening elements one level higher on the stack. - * If j is negative, each shift consists of removing element n - 1 - * of the stack and pushing it on the top of the stack, moving all - * intervening elements one level lower on the stack. - * - * (a) (b) (c) 3 -1 roll -> (b) (c) (a) - * (a) (b) (c) 3 1 roll -> (c) (a) (b) - * (a) (b) (c) 3 0 roll -> (a) (b) (c) - */ - case OperatorNames.OP_ROLL: - operator = new Operator(OperatorNames.OP_ROLL) { - public void eval(Stack stack) { - float j = (Float) stack.pop(); - float n = (Float) stack.pop(); - // each sift consists of removing an element from the top of the - // stack and inserting it between element n-1 and element n of the stack - if (j > 0) { - for (int i = 0; i < j; i++) { - stack.insertElementAt(stack.lastElement(), - (int) (stack.size() - (n))); - // finish the move by poping the top; - stack.pop(); - } - } - // each shift consists of removing an element n-1 off the stack - // and pushing it on top of the stack - else if (j < 0) { - for (int i = 0, max = (int) -j; i < max; i++) { - stack.push(stack.remove((int) (stack.size() - (n)))); - } - } - } - }; - break; - /** - * num1 round num2 - * returns the integer value nearest to num1 - */ - case OperatorNames.OP_ROUND: - operator = new Operator(OperatorNames.OP_ROUND) { - public void eval(Stack stack) { - float num1 = (Float) stack.pop(); - stack.push(((Number) Math.round(num1)).floatValue()); - } - }; - break; - /** - * angle sin real - * returns the sine of angle, which is interpreted as an angle in degrees. - */ - case OperatorNames.OP_SIN: - operator = new Operator(OperatorNames.OP_SIN) { - public void eval(Stack stack) { - float aAngle = (Float) stack.pop(); - stack.push(((Number) Math.sin(aAngle)).floatValue()); - } - }; - break; - /** - * num sqrt real - * returns the sine of angle, which is interpreted as an angle in degrees. - */ - case OperatorNames.OP_SQRT: - operator = new Operator(OperatorNames.OP_SQRT) { - public void eval(Stack stack) { - float num = (Float) stack.pop(); - stack.push(((Number) Math.sqrt(num)).floatValue()); - } - }; - break; - /** - * num1 num2 sub difference - * returns the result of subtracting num2 from num1. - */ - case OperatorNames.OP_SUB: - operator = new Operator(OperatorNames.OP_SUB) { - public void eval(Stack stack) { - float num2 = (Float) stack.pop(); - float num1 = (Float) stack.pop(); - stack.push(num1 - num2); - } - }; - break; - /** - * num1 truncate num2 - * truncates num1 toward 0 by removing its fractional part. - */ - case OperatorNames.OP_TRUNCATE: - operator = new Operator(OperatorNames.OP_TRUNCATE) { - public void eval(Stack stack) { - float num1 = (Float) stack.pop(); - stack.push(((Number) Math.floor(num1)).floatValue()); - } - }; - break; - /** - * bool1 bool2 xor bool3 - * int1 int2 xor int3 - * returns the logical "exclusive or" of the operands if they are - * boolean. If the operands are integers, xor returns the bitwise - * "exclusive or" of their binary representations. - */ - case OperatorNames.OP_XOR: - operator = new Operator(OperatorNames.OP_XOR) { - public void eval(Stack stack) { - Object obj2 = stack.pop(); - if (obj2 instanceof Number) { - float num2 = (Float) obj2; - float num1 = (Float) stack.pop(); - stack.push((int) num1 ^ (int) num2); - } else if (obj2 instanceof Boolean) { - boolean bool2 = (Boolean) obj2; - boolean bool1 = (Boolean) stack.pop(); - stack.push(bool1 ^ bool2); - } - } - }; - break; - case OperatorNames.OP_EXP_START: - operator = new Expression(OperatorNames.OP_EXP_START); - break; - case OperatorNames.OP_EXP_END: - operator = new Expression(OperatorNames.OP_EXP_END); - break; - default: - operator = new Operator(OperatorNames.NO_OP) { - public void eval(Stack stack) { - // throw something? - System.out.println(operatorType + " not implemented "); - } - }; - break; - } - - // add the new operator to the cache - if (operator != null) { - operatorCache.put(operator.getType(), operator); - } - return operator; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/OperatorNames.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/OperatorNames.java deleted file mode 100644 index 958b3d0629..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/OperatorNames.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions.postscript; - -/** - * OperatorsNames purpose is to define all operators in the PostScript type 4 - * function definitions. The function also provides an accelerated operand - * lookup method #getType() which returns an integer representation of the - * operand so that it can be quickly compared/processed at a later time. - * - * @author ICEsoft Technologies Inc. - * @since 4.2 - */ -public class OperatorNames { - - /** - * Gets the operator type specified by the input substring. PostScript - * operands should all be lower case but this function will handle upper - * and mixed case if encountered. - * - * @param ch character array containing postscript calculator function. - * @param offset starting offset of input substring. - * @param length length of input substring. - * @return integer representing the operand found as described in class - * constants. - */ - public static int getType(char ch[], int offset, int length) { - char c1, c2; - char c = ch[offset]; - // quickly switch though possible operands to find matching operands - // as quickly as possible. - switch (c) { - case 'a': // abs | add | atan - case 'A': - if (length == 4) return OP_ATAN; - c1 = ch[offset + 1]; - if (c1 == 'b' || c1 == 'B') { - return OP_ABS; - } else if (c1 == 'd' || c1 == 'D') { - return OP_ADD; - } - break; - case 'b': // bitshift - case 'B': - return OP_BITSHIFT; - case 'c': // ceiling | cos | copy | cvi | cvr - case 'C': - if (length == 8) return OP_CEILING; - if (length == 4) return OP_COPY; - c1 = ch[offset + 1]; - if (c1 == 'o' || c1 == 'O') { - return OP_COS; - } else if (c1 == 'v' || c1 == 'V') { - c2 = ch[offset + 2]; - if (c2 == 'i' || c2 == 'I') { - return OP_CVI; - } else if (c2 == 'r' || c2 == 'R') { - return OP_CVR; - } - } - break; - case 'd': // div | dup - case 'D': - c1 = ch[offset + 1]; - if (c1 == 'i' || c1 == 'I') { - return OP_DIV; - } else if (c1 == 'u' || c1 == 'U') { - return OP_DUP; - } - break; - case 'e': // eq | exch | exp - case 'E': - if (length == 2) return OP_EQ; - if (length == 3) return OP_EXP; - if (length == 4) return OP_EXCH; - break; - case 'f': // floor - case 'F': - return OP_FLOOR; - case 'g': // div | dup - case 'G': - c1 = ch[offset + 1]; - if (c1 == 'e' || c1 == 'E') { - return OP_GE; - } else if (c1 == 't' || c1 == 'T') { - return OP_GT; - } - break; - case 'i': // idif | if | ifelse | in | index - case 'I': - if (length == 6) return OP_IFELSE; - c1 = ch[offset + 1]; - if (c1 == 'd' || c1 == 'D') { - return OP_IDIV; - } else if (c1 == 'f' || c1 == 'F') { - return OP_IF; - } else if (c1 == 'n' || c1 == 'N') { - if (length == 5) return OP_INDEX; - if (length == 2) return OP_LN; - } - break; - case 'l': // le | log | lt - case 'L': - if (length == 3) return OP_LOG; - c1 = ch[offset + 1]; - if (c1 == 'e' || c1 == 'E') { - return OP_LE; - } else if (c1 == 't' || c1 == 'T') { - return OP_LT; - } - break; - case 'm': // mod | mul - case 'M': - c1 = ch[offset + 1]; - if (c1 == 'o' || c1 == 'O') { - return OP_MOD; - } else if (c1 == 'u' || c1 == 'U') { - return OP_MUL; - } - break; - case 'n': // ne | neg | not - case 'N': - if (length == 2) return OP_NE; - c1 = ch[offset + 1]; - if (c1 == 'e' || c1 == 'e') { - return OP_NEG; - } else if (c1 == 'o' || c1 == 'O') { - return OP_NOT; - } - break; - case 'o': // or - case 'O': - return OP_OR; - case 'p': // pop - case 'P': - return OP_POP; - case 'r': // roll | round - case 'R': - if (length == 4) return OP_ROLL; - if (length == 5) return OP_ROUND; - break; - case 's': // sin | sqrt | sub - case 'S': - if (length == 4) return OP_SQRT; - c1 = ch[offset + 1]; - if (c1 == 'u' || c1 == 'U') { - return OP_SUB; - } else if (c1 == 'i' || c1 == 'I') { - return OP_SIN; - } - break; - case 't': // truncate - case 'T': - return OP_TRUNCATE; - case 'x': // xor - case 'X': - return OP_XOR; - case '{': - return OP_EXP_START; - case '}': - return OP_EXP_END; - } - return NO_OP; - } - - /** - * Postscript subset of operations used in a type 4 function PostScript - * calculator. - */ - public final static int - NO_OP = 0, - OP_ABS = 1, - OP_ADD = 2, - OP_AND = 3, - OP_ATAN = 4, - OP_BITSHIFT = 5, - OP_CEILING = 6, - OP_COS = 7, - OP_COPY = 8, - OP_CVI = 9, - OP_CVR = 10, - OP_DIV = 11, - OP_DUP = 12, - OP_EQ = 13, - OP_EXCH = 14, - OP_EXP = 15, - OP_FALSE = 16, - OP_FLOOR = 17, - OP_GE = 18, - OP_GT = 19, - OP_IDIV = 20, - OP_IF = 21, - OP_IFELSE = 22, - OP_LN = 23, - OP_INDEX = 24, - OP_LE = 25, - OP_LOG = 26, - OP_LT = 27, - OP_MOD = 28, - OP_MUL = 29, - OP_NE = 30, - OP_NEG = 31, - OP_NOT = 32, - OP_OR = 33, - OP_POP = 34, - OP_ROLL = 35, - OP_ROUND = 36, - OP_SIN = 37, - OP_SQRT = 38, - OP_SUB = 39, - OP_TRUE = 40, - OP_TRUNCATE = 41, - OP_XOR = 42, - OP_EXP_START = 43, - OP_EXP_END = 44, - OP_PROC = 45; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Procedure.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Procedure.java deleted file mode 100644 index 5373ee2019..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/functions/postscript/Procedure.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.functions.postscript; - -import java.util.Stack; - -/** - * Procedure represents a groups of operands enclosed by braces. For example - * {dup 0 lt {pop 0 }{dup 1 gt {pop 1 } if } ifelse is defined as: - * {operand... {proc} {proc {proc}}operand} operand} - *

      - * This structures aids in the handling of ifelse and if statements. - * - * @since 5.1.0 - */ -public class Procedure extends Operator { - - private Stack stack; - private Procedure previousProcedure; - - @SuppressWarnings("unchecked") - public Procedure(Procedure previousProcedure) { - super(OperatorNames.OP_PROC); - stack = new Stack(); - if (previousProcedure != null) { - previousProcedure.getProc().push(this); - } - this.previousProcedure = previousProcedure; - } - - public Procedure getPrevious() { - return previousProcedure; - } - - public Stack getProc() { - return stack; - } - - @Override - @SuppressWarnings("unchecked") - public void eval(Stack stack) { - // iterate over the stack objects and update the eval stack - // we need to to this in revers... - for (Object tmp : this.stack) { - if (tmp instanceof Operator && !(tmp instanceof Procedure)) { - ((Operator) tmp).eval(stack); - } else { - stack.push(tmp); - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/BlendComposite.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/BlendComposite.java deleted file mode 100644 index 12ea91b022..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/BlendComposite.java +++ /dev/null @@ -1,845 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -/* - * Copyright (c) 2006 Romain Guy - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -import org.icepdf.core.pobjects.Name; - -import java.awt.*; -import java.awt.image.ColorModel; -import java.awt.image.DataBuffer; -import java.awt.image.Raster; -import java.awt.image.WritableRaster; - -public final class BlendComposite implements Composite { - public enum BlendingMode { - NORMAL, - AVERAGE, - MULTIPLY, - SCREEN, - DARKEN, - LIGHTEN, - OVERLAY, - HARD_LIGHT, - SOFT_LIGHT, - DIFFERENCE, - NEGATION, - EXCLUSION, - COLOR_DODGE, - INVERSE_COLOR_DODGE, - SOFT_DODGE, - COLOR_BURN, - INVERSE_COLOR_BURN, - SOFT_BURN, - REFLECT, - GLOW, - FREEZE, - HEAT, - ADD, - SUBTRACT, - STAMP, - RED, - GREEN, - BLUE, - HUE, - SATURATION, - COLOR, - LUMINOSITY - } - - public static final Name NORMAL_VALUE = new Name("Normal"); - public static final Name COMPATIBLE_VALUE = new Name("Compatible"); - public static final Name MULTIPLY_VALUE = new Name("Multiply"); - public static final Name SCREEN_VALUE = new Name("Screen"); - public static final Name OVERLAY_VALUE = new Name("Overlay"); - public static final Name DARKEN_VALUE = new Name("Darken"); - public static final Name LIGHTEN_VALUE = new Name("Lighten"); - public static final Name COLOR_DODGE_VALUE = new Name("ColorDodge"); - public static final Name COLOR_BURN_VALUE = new Name("ColorBurn"); - public static final Name HARD_LIGHT_VALUE = new Name("HardLight"); - public static final Name SOFT_LIGHT_VALUE = new Name("SoftLight"); - public static final Name DIFFERENCE_VALUE = new Name("Difference"); - public static final Name EXCLUSION_VALUE = new Name("Exclusion"); - - private float alpha; - private BlendingMode mode; - - private BlendComposite(BlendingMode mode) { - this(mode, 1.0f); - } - - private BlendComposite(BlendingMode mode, float alpha) { - this.mode = mode; - setAlpha(alpha); - } - - public static BlendComposite getInstance(BlendingMode mode) { - return new BlendComposite(mode); - } - - public static BlendComposite getInstance(BlendingMode mode, float alpha) { - return new BlendComposite(mode, alpha); - } - - // todo consider composite cache. - public static Composite getInstance(Name modeName, float alpha) { - // check for -1, value not set and default should be used. - if (alpha == -1) { - alpha = 1; - } - if (modeName.equals(NORMAL_VALUE) || modeName.equals(COMPATIBLE_VALUE)) { - return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha); -// return new BlendComposite(BlendingMode.NORMAL, alpha); - } else if (modeName.equals(MULTIPLY_VALUE)) { - return new BlendComposite(BlendingMode.MULTIPLY, alpha); - } else if (modeName.equals(SCREEN_VALUE)) { - return new BlendComposite(BlendingMode.SCREEN, alpha); - } else if (modeName.equals(OVERLAY_VALUE)) { - return new BlendComposite(BlendingMode.OVERLAY, alpha); - } else if (modeName.equals(DARKEN_VALUE)) { - return new BlendComposite(BlendingMode.DARKEN, alpha); - } else if (modeName.equals(LIGHTEN_VALUE)) { - return new BlendComposite(BlendingMode.LIGHTEN, alpha); - } else if (modeName.equals(COLOR_DODGE_VALUE)) { - return new BlendComposite(BlendingMode.SOFT_DODGE, alpha); - } else if (modeName.equals(COLOR_BURN_VALUE)) { - return new BlendComposite(BlendingMode.SOFT_BURN, alpha); - } else if (modeName.equals(HARD_LIGHT_VALUE)) { - return new BlendComposite(BlendingMode.HARD_LIGHT, alpha); - } else if (modeName.equals(SOFT_LIGHT_VALUE)) { - return new BlendComposite(BlendingMode.SOFT_LIGHT, alpha); - } else if (modeName.equals(DIFFERENCE_VALUE)) { - return new BlendComposite(BlendingMode.DIFFERENCE, alpha); - } else if (modeName.equals(EXCLUSION_VALUE)) { - return new BlendComposite(BlendingMode.EXCLUSION, alpha); - } -// return new BlendComposite(BlendingMode.NORMAL, alpha); - return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha); - } - - - public BlendComposite derive(BlendingMode mode) { - return this.mode == mode ? this : new BlendComposite(mode, getAlpha()); - } - - public BlendComposite derive(float alpha) { - return this.alpha == alpha ? this : new BlendComposite(getMode(), alpha); - } - - public float getAlpha() { - return alpha; - } - - public BlendingMode getMode() { - return mode; - } - - private void setAlpha(float alpha) { - if (alpha < 0.0f || alpha > 1.0f) { - throw new IllegalArgumentException( - "alpha must be comprised between 0.0f and 1.0f"); - } - - this.alpha = alpha; - } - - @Override - public int hashCode() { - return Float.floatToIntBits(alpha) * 31 + mode.ordinal(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof BlendComposite)) { - return false; - } - - BlendComposite bc = (BlendComposite) obj; - - if (mode != bc.mode) { - return false; - } - - return alpha == bc.alpha; - } - - @Override - public String toString() { - return mode + " " + alpha; - } - - public CompositeContext createContext(ColorModel srcColorModel, - ColorModel dstColorModel, - RenderingHints hints) { - return new BlendingContext(this); - } - - private static final class BlendingContext implements CompositeContext { - private final Blender blender; - private final BlendComposite composite; - - private BlendingContext(BlendComposite composite) { - this.composite = composite; - this.blender = Blender.getBlenderFor(composite); - } - - public void dispose() { - } - - public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { - if (src.getSampleModel().getDataType() != DataBuffer.TYPE_INT || - dstIn.getSampleModel().getDataType() != DataBuffer.TYPE_INT || - dstOut.getSampleModel().getDataType() != DataBuffer.TYPE_INT) { - throw new IllegalStateException( - "Source and destination must store pixels as INT."); - } - - int width = Math.min(src.getWidth(), dstIn.getWidth()); - int height = Math.min(src.getHeight(), dstIn.getHeight()); - - float alpha = composite.getAlpha(); - - int[] srcPixel = new int[4]; - int[] dstPixel = new int[4]; - int[] srcPixels = new int[width]; - int[] dstPixels = new int[width]; - - for (int y = 0; y < height; y++) { - src.getDataElements(0, y, width, 1, srcPixels); - dstIn.getDataElements(0, y, width, 1, dstPixels); - for (int x = 0; x < width; x++) { - // pixels are stored as INT_ARGB - // our arrays are [R, G, B, A] - int pixel = srcPixels[x]; - srcPixel[0] = (pixel >> 16) & 0xFF; - srcPixel[1] = (pixel >> 8) & 0xFF; - srcPixel[2] = (pixel) & 0xFF; - srcPixel[3] = (pixel >> 24) & 0xFF; - - pixel = dstPixels[x]; - dstPixel[0] = (pixel >> 16) & 0xFF; - dstPixel[1] = (pixel >> 8) & 0xFF; - dstPixel[2] = (pixel) & 0xFF; - dstPixel[3] = (pixel >> 24) & 0xFF; - - int[] result = blender.blend(srcPixel, dstPixel); - - // mixes the result with the opacity - dstPixels[x] = - ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 | - ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16 | - ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) << 8 | - (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF; - } - dstOut.setDataElements(0, y, width, 1, dstPixels); - } - } - } - - private static abstract class Blender { - public abstract int[] blend(int[] src, int[] dst); - - private static void RGBtoHSL(int r, int g, int b, float[] hsl) { - float var_R = (r / 255f); - float var_G = (g / 255f); - float var_B = (b / 255f); - - float var_Min; - float var_Max; - float del_Max; - - if (var_R > var_G) { - var_Min = var_G; - var_Max = var_R; - } else { - var_Min = var_R; - var_Max = var_G; - } - if (var_B > var_Max) { - var_Max = var_B; - } - if (var_B < var_Min) { - var_Min = var_B; - } - - del_Max = var_Max - var_Min; - - float H, S, L; - L = (var_Max + var_Min) / 2f; - - if (del_Max - 0.01f <= 0.0f) { - H = 0; - S = 0; - } else { - if (L < 0.5f) { - S = del_Max / (var_Max + var_Min); - } else { - S = del_Max / (2 - var_Max - var_Min); - } - - float del_R = (((var_Max - var_R) / 6f) + (del_Max / 2f)) / del_Max; - float del_G = (((var_Max - var_G) / 6f) + (del_Max / 2f)) / del_Max; - float del_B = (((var_Max - var_B) / 6f) + (del_Max / 2f)) / del_Max; - - if (var_R == var_Max) { - H = del_B - del_G; - } else if (var_G == var_Max) { - H = (1 / 3f) + del_R - del_B; - } else { - H = (2 / 3f) + del_G - del_R; - } - if (H < 0) { - H += 1; - } - if (H > 1) { - H -= 1; - } - } - - hsl[0] = H; - hsl[1] = S; - hsl[2] = L; - } - - private static void HSLtoRGB(float h, float s, float l, int[] rgb) { - int R, G, B; - - if (s - 0.01f <= 0.0f) { - R = (int) (l * 255.0f); - G = (int) (l * 255.0f); - B = (int) (l * 255.0f); - } else { - float var_1, var_2; - if (l < 0.5f) { - var_2 = l * (1 + s); - } else { - var_2 = (l + s) - (s * l); - } - var_1 = 2 * l - var_2; - - R = (int) (255.0f * hue2RGB(var_1, var_2, h + (1.0f / 3.0f))); - G = (int) (255.0f * hue2RGB(var_1, var_2, h)); - B = (int) (255.0f * hue2RGB(var_1, var_2, h - (1.0f / 3.0f))); - } - - rgb[0] = R; - rgb[1] = G; - rgb[2] = B; - } - - private static float hue2RGB(float v1, float v2, float vH) { - if (vH < 0.0f) { - vH += 1.0f; - } - if (vH > 1.0f) { - vH -= 1.0f; - } - if ((6.0f * vH) < 1.0f) { - return (v1 + (v2 - v1) * 6.0f * vH); - } - if ((2.0f * vH) < 1.0f) { - return (v2); - } - if ((3.0f * vH) < 2.0f) { - return (v1 + (v2 - v1) * ((2.0f / 3.0f) - vH) * 6.0f); - } - return (v1); - } - - public static Blender getBlenderFor(BlendComposite composite) { - switch (composite.getMode()) { - case NORMAL: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - if (src[3] == 0) { - return dst; - } - return src; - } - }; - case MULTIPLY: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - // white stays white. - if (src[3] == 0) { - return dst; - } - return new int[]{ - (src[0] * dst[0]) >> 8, - (src[1] * dst[1]) >> 8, - (src[2] * dst[2]) >> 8, - Math.min(255, src[3] + dst[3]) - }; - } - }; - case ADD: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - Math.min(255, src[0] + dst[0]), - Math.min(255, src[1] + dst[1]), - Math.min(255, src[2] + dst[2]), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case AVERAGE: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - (src[0] + dst[0]) >> 1, - (src[1] + dst[1]) >> 1, - (src[2] + dst[2]) >> 1, - Math.min(255, src[3] + dst[3]) - }; - } - }; - case BLUE: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - dst[0], - src[1], - dst[2], - Math.min(255, src[3] + dst[3]) - }; - } - }; - case COLOR: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - float[] srcHSL = new float[3]; - RGBtoHSL(src[0], src[1], src[2], srcHSL); - float[] dstHSL = new float[3]; - RGBtoHSL(dst[0], dst[1], dst[2], dstHSL); - - int[] result = new int[4]; - HSLtoRGB(srcHSL[0], srcHSL[1], dstHSL[2], result); - result[3] = Math.min(255, src[3] + dst[3]); - - return result; - } - }; - case COLOR_BURN: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - src[0] == 0 ? 0 : - Math.max(0, 255 - (((255 - dst[0]) << 8) / src[0])), - src[1] == 0 ? 0 : - Math.max(0, 255 - (((255 - dst[1]) << 8) / src[1])), - src[2] == 0 ? 0 : - Math.max(0, 255 - (((255 - dst[2]) << 8) / src[2])), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case COLOR_DODGE: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - src[0] == 255 ? 255 : - Math.min((dst[0] << 8) / (255 - src[0]), 255), - src[1] == 255 ? 255 : - Math.min((dst[1] << 8) / (255 - src[1]), 255), - src[2] == 255 ? 255 : - Math.min((dst[2] << 8) / (255 - src[2]), 255), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case DARKEN: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - Math.min(src[0], dst[0]), - Math.min(src[1], dst[1]), - Math.min(src[2], dst[2]), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case DIFFERENCE: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - Math.abs(dst[0] - src[0]), - Math.abs(dst[1] - src[1]), - Math.abs(dst[2] - src[2]), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case EXCLUSION: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - dst[0] + src[0] - (dst[0] * src[0] >> 7), - dst[1] + src[1] - (dst[1] * src[1] >> 7), - dst[2] + src[2] - (dst[2] * src[2] >> 7), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case FREEZE: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - src[0] == 0 ? 0 : Math.max(0, 255 - (255 - dst[0]) * (255 - dst[0]) / src[0]), - src[1] == 0 ? 0 : Math.max(0, 255 - (255 - dst[1]) * (255 - dst[1]) / src[1]), - src[2] == 0 ? 0 : Math.max(0, 255 - (255 - dst[2]) * (255 - dst[2]) / src[2]), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case GLOW: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - dst[0] == 255 ? 255 : Math.min(255, src[0] * src[0] / (255 - dst[0])), - dst[1] == 255 ? 255 : Math.min(255, src[1] * src[1] / (255 - dst[1])), - dst[2] == 255 ? 255 : Math.min(255, src[2] * src[2] / (255 - dst[2])), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case GREEN: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - dst[0], - dst[1], - src[2], - Math.min(255, src[3] + dst[3]) - }; - } - }; - case HARD_LIGHT: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - if (src[3] == 0) { - return dst; - } - return new int[]{ - src[0] < 128 ? dst[0] * src[0] >> 7 : - 255 - ((255 - src[0]) * (255 - dst[0]) >> 7), - src[1] < 128 ? dst[1] * src[1] >> 7 : - 255 - ((255 - src[1]) * (255 - dst[1]) >> 7), - src[2] < 128 ? dst[2] * src[2] >> 7 : - 255 - ((255 - src[2]) * (255 - dst[2]) >> 7), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case HEAT: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - dst[0] == 0 ? 0 : Math.max(0, 255 - (255 - src[0]) * (255 - src[0]) / dst[0]), - dst[1] == 0 ? 0 : Math.max(0, 255 - (255 - src[1]) * (255 - src[1]) / dst[1]), - dst[2] == 0 ? 0 : Math.max(0, 255 - (255 - src[2]) * (255 - src[2]) / dst[2]), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case HUE: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - float[] srcHSL = new float[3]; - RGBtoHSL(src[0], src[1], src[2], srcHSL); - float[] dstHSL = new float[3]; - RGBtoHSL(dst[0], dst[1], dst[2], dstHSL); - - int[] result = new int[4]; - HSLtoRGB(srcHSL[0], dstHSL[1], dstHSL[2], result); - result[3] = Math.min(255, src[3] + dst[3]); - - return result; - } - }; - case INVERSE_COLOR_BURN: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - dst[0] == 0 ? 0 : - Math.max(0, 255 - (((255 - src[0]) << 8) / dst[0])), - dst[1] == 0 ? 0 : - Math.max(0, 255 - (((255 - src[1]) << 8) / dst[1])), - dst[2] == 0 ? 0 : - Math.max(0, 255 - (((255 - src[2]) << 8) / dst[2])), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case INVERSE_COLOR_DODGE: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - dst[0] == 255 ? 255 : - Math.min((src[0] << 8) / (255 - dst[0]), 255), - dst[1] == 255 ? 255 : - Math.min((src[1] << 8) / (255 - dst[1]), 255), - dst[2] == 255 ? 255 : - Math.min((src[2] << 8) / (255 - dst[2]), 255), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case LIGHTEN: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - Math.max(src[0], dst[0]), - Math.max(src[1], dst[1]), - Math.max(src[2], dst[2]), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case LUMINOSITY: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - - float[] srcHSL = new float[3]; - RGBtoHSL(src[0], src[1], src[2], srcHSL); - float[] dstHSL = new float[3]; - RGBtoHSL(dst[0], dst[1], dst[2], dstHSL); - - int[] result = new int[4]; - HSLtoRGB(dstHSL[0], dstHSL[1], srcHSL[2], result); - result[3] = Math.min(255, src[3] + dst[3]); - - return result; - } - }; - case NEGATION: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - 255 - Math.abs(255 - dst[0] - src[0]), - 255 - Math.abs(255 - dst[1] - src[1]), - 255 - Math.abs(255 - dst[2] - src[2]), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case OVERLAY: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - // screening with black leaves the underlying colour unchanged. - if (src[3] == 0) { - return dst; - } - return new int[]{ - dst[0] < 128 ? (dst[0] * src[0]) >> 7 : - 255 - ((255 - dst[0]) * (255 - src[0]) >> 7), - dst[1] < 128 ? dst[1] * src[1] >> 7 : - 255 - ((255 - dst[1]) * (255 - src[1]) >> 7), - dst[2] < 128 ? (dst[2] * src[2]) >> 7 : - 255 - ((255 - dst[2]) * (255 - src[2]) >> 7), - Math.min(255, dst[3]) - }; -// return dst; - } - }; - case RED: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - src[0], - dst[1], - dst[2], - Math.min(255, src[3] + dst[3]) - }; - } - }; - case REFLECT: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - src[0] == 255 ? 255 : Math.min(255, dst[0] * dst[0] / (255 - src[0])), - src[1] == 255 ? 255 : Math.min(255, dst[1] * dst[1] / (255 - src[1])), - src[2] == 255 ? 255 : Math.min(255, dst[2] * dst[2] / (255 - src[2])), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case SATURATION: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - float[] srcHSL = new float[3]; - RGBtoHSL(src[0], src[1], src[2], srcHSL); - float[] dstHSL = new float[3]; - RGBtoHSL(dst[0], dst[1], dst[2], dstHSL); - - int[] result = new int[4]; - HSLtoRGB(dstHSL[0], srcHSL[1], dstHSL[2], result); - result[3] = Math.min(255, src[3] + dst[3]); - - return result; - } - }; - case SCREEN: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - // screening with black leaves the underlying colour unchanged. - if ((src[0] == 0 && src[1] == 0 && src[2] == 0)) { - return dst; - } - // screening any colour with white, produces white. - if ((dst[0] != 255 && dst[1] != 255 && dst[2] != 255)) { - int[] value = new int[]{ - 255 - ((255 - src[0]) * (255 - dst[0]) >> 8), - 255 - ((255 - src[1]) * (255 - dst[1]) >> 8), - 255 - ((255 - src[2]) * (255 - dst[2]) >> 8), - Math.min(255, src[3] + (dst[3])) - }; - return value; - } - return src; - } - }; - case SOFT_BURN: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - dst[0] + src[0] < 256 ? - (dst[0] == 255 ? 255 : - Math.min(255, (src[0] << 7) / (255 - dst[0]))) : - Math.max(0, 255 - (((255 - dst[0]) << 7) / src[0])), - dst[1] + src[1] < 256 ? - (dst[1] == 255 ? 255 : - Math.min(255, (src[1] << 7) / (255 - dst[1]))) : - Math.max(0, 255 - (((255 - dst[1]) << 7) / src[1])), - dst[2] + src[2] < 256 ? - (dst[2] == 255 ? 255 : - Math.min(255, (src[2] << 7) / (255 - dst[2]))) : - Math.max(0, 255 - (((255 - dst[2]) << 7) / src[2])), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case SOFT_DODGE: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - if (src[3] == 0) { - return dst; - } - return new int[]{ - - dst[0] + src[0] < 256 ? - (src[0] == 255 ? 255 : - Math.min(255, (dst[0] << 7) / (255 - src[0]))) : - Math.max(0, 255 - (((255 - src[0]) << 7) / dst[0])), - dst[1] + src[1] < 256 ? - (src[1] == 255 ? 255 : - Math.min(255, (dst[1] << 7) / (255 - src[1]))) : - Math.max(0, 255 - (((255 - src[1]) << 7) / dst[1])), - dst[2] + src[2] < 256 ? - (src[2] == 255 ? 255 : - Math.min(255, (dst[2] << 7) / (255 - src[2]))) : - Math.max(0, 255 - (((255 - src[2]) << 7) / dst[2])), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case SOFT_LIGHT: - break; - case STAMP: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - Math.max(0, Math.min(255, dst[0] + 2 * src[0] - 256)), - Math.max(0, Math.min(255, dst[1] + 2 * src[1] - 256)), - Math.max(0, Math.min(255, dst[2] + 2 * src[2] - 256)), - Math.min(255, src[3] + dst[3]) - }; - } - }; - case SUBTRACT: - return new Blender() { - @Override - public int[] blend(int[] src, int[] dst) { - return new int[]{ - Math.max(0, src[0] + dst[0] - 256), - Math.max(0, src[1] + dst[1] - 256), - Math.max(0, src[2] + dst[2] - 256), - Math.min(255, src[3] + dst[3]) - }; - } - }; - } - throw new IllegalArgumentException("Blender not implement for " + - composite.getMode().name()); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/CachedImageReference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/CachedImageReference.java deleted file mode 100644 index 2d4b8bda35..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/CachedImageReference.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.Resources; - -import java.awt.image.BufferedImage; - -/** - * the Abstract CachedImageReference stores the decoded BufferedImage data in - * an ImagePool referenced by the images PDF object number to insure that if - * a page is garbage collected the image can re fetched from the pool if - * necessary. - * - * @since 5.0 - */ -public abstract class CachedImageReference extends ImageReference { - - private ImagePool imagePool; - private boolean isNull; - - protected CachedImageReference(ImageStream imageStream, GraphicsState graphicsState, - Resources resources, int imageIndex, - Page page) { - super(imageStream, graphicsState, resources, imageIndex, page); - imagePool = imageStream.getLibrary().getImagePool(); - this.reference = imageStream.getPObjectReference(); - } - - public BufferedImage getImage() { - if (isNull) { - return null; - } - if (image != null && reference != null) { - imagePool.put(reference, image); - return image; - } - BufferedImage cached = imagePool.get(reference); - if (cached != null) { - return cached; - } else { - BufferedImage im = createImage(); - if (im != null && reference != null) { - imagePool.put(reference, im); - } else if (reference != null) { - isNull = true; - } - return im; - } - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/CalGray.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/CalGray.java deleted file mode 100644 index c84a53ffd3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/CalGray.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.color.ColorSpace; -import java.util.HashMap; - -/** - * A CalGray colour space (PDF 1.1) is a special case of a single-component - * CIE-based colour space, known as a CIE-based A colour space. This type of - * space is the one-dimensional (and usually achromatic) analog of CIE-based - * ABC spaces. Colour values in a CIE-based A space shall have a single component, - * arbitrarily named A.Figure 23 illustrates the transformations of the A - * component to X, Y, and Z components of the CIE 1931 XYZ space. - * - * @since 5.0.1 - */ -public class CalGray extends PColorSpace { - - public static final Name WHITE_POINT_KEY = new Name("WhitePoint"); - public static final Name GAMMA_KEY = new Name("Gamma"); - public static final Name MATRIX_KEY = new Name("Matrix"); - public static final Name CAL_GRAY_KEY = new Name("CalGray"); - - private static ColorSpace grayCS = ColorSpace.getInstance(ColorSpace.CS_GRAY); - - protected float[] whitepoint = { - 1, 1, 1 - }; - protected float gamma = 1.0f; - - public CalGray(Library l, HashMap h) { - super(l, h); - - java.util.List m = (java.util.List) h.get(WHITE_POINT_KEY); - if (m != null) { - for (int i = 0; i < 3; i++) { - whitepoint[i] = ((Number) m.get(i)).floatValue(); - } - } - - Object o = h.get(GAMMA_KEY); - if (o instanceof Float) { - gamma = (Float) o; - } - } - - @Override - public Color getColor(float[] f, boolean fillAndStroke) { - - float A = (float) Math.pow(f[0], gamma); - - float X = whitepoint[0] * A; - float Y = whitepoint[1] * A; - float Z = whitepoint[2] * A; - if (X < 0) { - X = 0; - } - if (Y < 0) { - Y = 0; - } - if (Z < 0) { - Z = 0; - } - if (X > 1) { - X = 1; - } - if (Y > 1) { - Y = 1; - } - if (Z > 1) { - Z = 1; - } - Color tmp = new Color(grayCS, new float[]{Z, Y, Z}, 1.0f); - return tmp; - } - - @Override - public int getNumComponents() { - return 1; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/CalRGB.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/CalRGB.java deleted file mode 100644 index 6546d266a4..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/CalRGB.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; -import java.util.List; - -/** - * A CalRGB colour space is a CIE-based ABC colour space with only one - * transformation stage instead of two. In this type of space, A, B, and C - * represent calibrated red, green, and blue colour values. These three colour - * components shall be in the range 0.0 to 1.0; component values falling outside - * that range shall be adjusted to the nearest valid value without error indication. - * The decoding functions (denoted by “Decode ABC†in Figure 22) are gamma - * functions whose coefficients shall be specified by the Gamma entry in the - * colour space dictionary (see Table 64). The transformation matrix denoted by - * “Matrix ABC†in Figure 22 shall be defined by the dictionary’s Matrix entry. - * Since there is no second transformation stage, “Decode LMN†and “Matrix LMN†- * shall be implicitly taken to be identity transformations. - * - * @since 1.0 - */ -public class CalRGB extends PColorSpace { - - public static final Name WHITE_POINT_KEY = new Name("WhitePoint"); - public static final Name GAMMA_KEY = new Name("Gamma"); - public static final Name MATRIX_KEY = new Name("Matrix"); - public static final Name CALRGB_KEY = new Name("CalRGB"); - - protected float[] whitepoint = { - 1, 1, 1 - }; - protected float[] gamma = { - 1, 1, 1 - }; - protected float[] matrix = { - 1, 0, 0, 0, 1, 0, 0, 0, 1 - }; - - - CalRGB(Library l, HashMap h) { - super(l, h); - List m = (List) h.get(WHITE_POINT_KEY); - if (m != null) { - for (int i = 0; i < 3; i++) { - whitepoint[i] = ((Number) m.get(i)).floatValue(); - } - } - m = (List) h.get(GAMMA_KEY); - if (m != null) { - for (int i = 0; i < 3; i++) { - gamma[i] = ((Number) m.get(i)).floatValue(); - } - } - m = (List) h.get(MATRIX_KEY); - if (m != null) { - for (int i = 0; i < 9; i++) { - matrix[i] = ((Number) m.get(i)).floatValue(); - } - } - } - - - public int getNumComponents() { - return 3; - } - - - public Color getColor(float[] f, boolean fillAndStroke) { - if (true) { - return new java.awt.Color(f[2], f[1], f[0]); - } - /* float A = (float)Math.exp(gamma[0]*Math.log(f[2])); - float B = (float)Math.exp(gamma[1]*Math.log(f[1])); - float C = (float)Math.exp(gamma[2]*Math.log(f[0]));*/ - float A = (float) Math.pow(f[2], gamma[0]); - float B = (float) Math.pow(f[1], gamma[1]); - float C = (float) Math.pow(f[0], gamma[2]); - float X = matrix[0] * A + matrix[3] * B + matrix[6] * C; - float Y = matrix[1] * A + matrix[4] * B + matrix[7] * C; - float Z = matrix[2] * A + matrix[5] * B + matrix[8] * C; - if (X < 0) { - X = 0; - } - if (Y < 0) { - Y = 0; - } - if (Z < 0) { - Z = 0; - } - if (X > 1) { - X = 1; - } - if (Y > 1) { - Y = 1; - } - if (Z > 1) { - Z = 1; - } - return new Color(X, Y, Z); - // return new java.awt.Color(f[2]*255/max_val, f[1]*255/max_val, f[0]*255/max_val); - } -} - - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ColorSpaceCMYK.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ColorSpaceCMYK.java deleted file mode 100644 index c1c93661af..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ColorSpaceCMYK.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import java.awt.color.ColorSpace; - -/** - * @author Mark Collette - * @since 2.0 - */ -@SuppressWarnings("serial") -public class ColorSpaceCMYK extends ColorSpace { - private static final String[] NAMES = new String[]{"Cyan", "Magenta", "Yellow", "Black"}; - private static final ColorSpace COLOR_SPACE_sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); - - public ColorSpaceCMYK() { - super(TYPE_CMYK, 4); - } - - public int getNumComponents() { - return 4; - } - - public String getName(int index) { - return NAMES[index]; - } - - public int getType() { - return TYPE_CMYK; - } - - public boolean isCS_sRGB() { - return false; - } - - public float[] fromRGB(float[] rgbValues) { - float c = 1.0f - rgbValues[0]; - float m = 1.0f - rgbValues[1]; - float y = 1.0f - rgbValues[2]; - float k = Math.min(c, Math.min(m, y)); - float km = Math.max(c, Math.max(m, y)); - if (km > k) - k = k * k * k / (km * km); - - c -= k; - m -= k; - y -= k; - - float[] cmykValues = new float[4]; - cmykValues[0] = c; - cmykValues[1] = m; - cmykValues[2] = y; - cmykValues[3] = k; - return cmykValues; - } - - public float[] toRGB(float[] cmykValues) { -//System.out.println("CMYK: " + cmykValues[0] + " " + cmykValues[1] + " " + cmykValues[2] + " " + cmykValues[3]); - /* - float c = 1.0f - cmykValues[0]; - float m = 1.0f - cmykValues[1]; - float y = 1.0f - cmykValues[2]; - float k = cmykValues[3]; - - c -= k; - m -= k; - y -= k; - - if( c < 0.0f ) - c = 0.0f; - if( m < 0.0f ) - m = 0.0f; - if( y < 0.0f ) - y = 0.0f; - */ - - float c = cmykValues[0]; - float m = cmykValues[1]; - float y = cmykValues[2]; - float k = cmykValues[3]; - - c += k; - m += k; - y += k; - - if (c < 0.0f) - c = 0.0f; - else if (c > 1.0f) - c = 1.0f; - if (m < 0.0f) - m = 0.0f; - else if (m > 1.0f) - m = 1.0f; - if (y < 0.0f) - y = 0.0f; - else if (y > 1.0f) - y = 1.0f; - - c = 1.0f - c; - m = 1.0f - m; - y = 1.0f - y; - - float[] rgbValues = new float[4]; - rgbValues[0] = c; - rgbValues[1] = m; - rgbValues[2] = y; - return rgbValues; - } - - private float[] _rgbValues = new float[4]; - - public float[] fromCIEXYZ(float[] colorvalue) { - return fromRGB(COLOR_SPACE_sRGB.fromCIEXYZ(colorvalue)); - } - - public float[] toCIEXYZ(float[] colorvalue) { - return COLOR_SPACE_sRGB.toCIEXYZ(toRGB(colorvalue)); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceCMYK.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceCMYK.java deleted file mode 100644 index b70a76653a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceCMYK.java +++ /dev/null @@ -1,321 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.color.ICC_ColorSpace; -import java.awt.color.ICC_Profile; -import java.io.FileInputStream; -import java.io.InputStream; -import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Logger; - -/** - * Device CMYK colour space definitions. The primary purpose of this colour - * space is to convert cymk colours to rgb. No ICC profile is used in this - * process and the generated rgb colour is just and approximation. - */ -public class DeviceCMYK extends PColorSpace { - - private static final Logger logger = - Logger.getLogger(DeviceCMYK.class.toString()); - - public static final Name DEVICECMYK_KEY = new Name("DeviceCMYK"); - public static final Name CMYK_KEY = new Name("CMYK"); - - private static final DeviceGray DEVICE_GRAY = new DeviceGray(null, null); - - // default cmyk value, > 255 will lighten the image. - private static float blackRatio; - - // CMYK ICC color profile. - private static ICC_ColorSpace iccCmykColorSpace; - // basic cache to speed up the lookup. always 4 bands, can be static - private ConcurrentHashMap iccCmykColorCache = - new ConcurrentHashMap(); - - // disable icc color profile lookups as they can be slow. n - private static boolean disableICCCmykColorSpace; - - static { - // black ratio - blackRatio = (float) Defs.doubleProperty("org.icepdf.core.cmyk.colorant.black", 1.0); - - disableICCCmykColorSpace = Defs.booleanProperty("org.icepdf.core.cmyk.disableICCProfile", false); - - // check for a custom CMYK ICC colour profile specified using system properties. - iccCmykColorSpace = getIccCmykColorSpace(); - } - - public DeviceCMYK(Library l, HashMap h) { - super(l, h); - } - - - public int getNumComponents() { - return 4; - } - - /** - * Converts a 4 component cmyk colour to rgb. With out a valid ICC colour - * profile this is just an approximation. - * - * @param f 4 component values of the cmyk, assumes compoents between - * 0.0 and 1.0 - * @return valid rgb colour object. - */ - public Color getColor(float[] f, boolean fillAndStroke) { - return alternative2(f, iccCmykColorCache); - } - - /** - * Ah yes the many possible ways to go from cmyk to rgb. Everybody has - * an opinion but no one has the solution that is 100% - */ - - /** - * Adobe photo shop algorithm or so they say. K is assumed to be f[0] - * - * @param f 4 component values of the cmyk, assumes comopents between - * 0.0 and 1.0 - * @return valid rgb colour object. - */ - private static Color alternative1(float[] f) { - - float c = f[3]; - float m = f[2]; - float y = f[1]; - float k = f[0]; - - float r = 1.0f - Math.min(1.0f, c + k); - float g = 1.0f - Math.min(1.0f, m + k); - float b = 1.0f - Math.min(1.0f, y + k); - - return new Color(r, g, b); - } - - /** - * @param f 4 component values of the cmyk, assumes components between - * 0.0 and 1.0 - * @return valid rgb colour object. - */ - private static Color alternative3(float[] f) { - - float c = f[3]; - float m = f[2]; - float y = f[1]; - float k = f[0]; - - float r = 1.0f - Math.min(1.0f, (c * (1 - k)) + k); - float g = 1.0f - Math.min(1.0f, (m * (1 - k)) + k); - float b = 1.0f - Math.min(1.0f, (y * (1 - k)) + k); - - return new Color(r, g, b); - } - - /** - * Auto cad color model - * var R=Math.round((1-C)*(1-K)*255); - * var B=Math.round((1-Y)*(1-K)*255); - * var G=Math.round((1-M)*(1-K)*255); - * - * @param f 4 component values of the cmyk, assumes compoents between - * 0.0 and 1.0 - * @return valid rgb colour object. - */ - private static Color getAutoCadColor(float[] f) { - - float c = f[3]; - float m = f[2]; - float y = f[1]; - float k = f[0]; - - int red = Math.round((1.0f - c) * (1.0f - k) * 255); - int blue = Math.round((1.0f - y) * (1.0f - k) * 255); - int green = Math.round((1.0f - m) * (1.0f - k) * 255); - - return new Color(red, green, blue); - } - - /** - * GNU Ghost Script algorithm or so they say. - *

      - * rgb[0] = colors * (255 - cyan)/255; - * rgb[1] = colors * (255 - magenta)/255; - * rgb[2] = colors * (255 - yellow)/255; - * - * @param f 4 component values of the cmyk, assumes compoents between - * 0.0 and 1.0 - * @return valid rgb colour object. - */ - private static Color getGhostColor(float[] f) { - - int cyan = (int) (f[3] * 255); - int magenta = (int) (f[2] * 255); - int yellow = (int) (f[1] * 255); - int black = (int) (f[0] * 255); - float colors = 255 - black; - - float[] rgb = new float[3]; - rgb[0] = colors * (255 - cyan) / 255; - rgb[1] = colors * (255 - magenta) / 255; - rgb[2] = colors * (255 - yellow) / 255; - - return new Color((int) rgb[0], (int) rgb[1], (int) rgb[2]); - - } - - /** - * Current runner for conversion that looks closest to acrobat. - * The algorithm is a little expensive but it does the best approximation. - * - * @param f 4 component values of the cmyk, assumes compoents between - * 0.0 and 1.0 - * @return valid rgb colour object. - */ - private static Color alternative2(float[] f, - ConcurrentHashMap iccCmykColorCache) { - float inCyan = f[3]; - float inMagenta = f[2]; - float inYellow = f[1]; - float inBlack = f[0]; - - // check if we have a valid ICC profile to work with - if (!disableICCCmykColorSpace && iccCmykColorSpace != null) { - // generate a key for the colour - int key = (((int) (f[0] * 255) & 0xff) << 24) | - (((int) (f[1] * 255) & 0xff) << 16) | - (((int) (f[2] * 255) & 0xff) << 8) | - (((int) (f[3] * 255) & 0xff) & 0xff); - Color color = iccCmykColorCache.get(key); - if (color != null) { - return color; - } else { - try { - f = iccCmykColorSpace.toRGB(reverse(f)); - color = new Color(f[0], f[1], f[2]); - iccCmykColorCache.put(key, color); - return color; - } catch (Throwable e) { - logger.warning("Error using iccCmykColorSpace in DeviceCMYK."); - } - } - } - - // soften the amount of black, but exclude explicit black colorant. - if (!(inCyan == 0 && inMagenta == 0 && inYellow == 0)) { - inBlack = inBlack * blackRatio; - } - // if only the black colorant then we can treat the colour as gray, - // cmyk is subtractive. - else { - f[0] = 1.0f - f[0]; - return DEVICE_GRAY.getColor(f); - } - - double c, m, y, aw, ac, am, ay, ar, ag, ab; - c = clip(0.0, 1.0, inCyan + inBlack); - m = clip(0.0, 1.0, inMagenta + inBlack); - y = clip(0.0, 1.0, inYellow + inBlack); - aw = (1 - c) * (1 - m) * (1 - y); - ac = c * (1 - m) * (1 - y); - am = (1 - c) * m * (1 - y); - ay = (1 - c) * (1 - m) * y; - ar = (1 - c) * m * y; - ag = c * (1 - m) * y; - ab = c * m * (1 - y); - - float outRed = (float) clip(0.0, 1.0, aw + 0.9137 * am + 0.9961 * ay + 0.9882 * ar); - float outGreen = (float) clip(0.0, 1.0, aw + 0.6196 * ac + ay + 0.5176 * ag); - float outBlue = (float) clip(0.0, 1.0, aw + 0.7804 * ac + 0.5412 * am + 0.0667 * ar + 0.2118 * ag + 0.4863 * ab); - - return new Color(outRed, outGreen, outBlue); - } - - /** - * Clips the value according to the specified floor and ceiling. - * - * @param floor floor value of clip - * @param ceiling ceiling value of clip - * @param value value to clip. - * @return clipped value. - */ - private static double clip(double floor, double ceiling, double value) { - if (value < floor) { - value = floor; - } - if (value > ceiling) { - value = ceiling; - } - return value; - } - - /** - * Gets the ICC Color Profile found in the icepdf-core.jar at the location - * /org/icepdf/core/pobjects/graphics/res/ or the ICC Color Profiel - * specified by the system property org.icepdf.core.pobjects.graphics.cmyk. - * - * @return associated ICC CMYK Color space. - */ - public static ICC_ColorSpace getIccCmykColorSpace() { - // would prefer to only have one instance but becuase of JDK-8033238 - // we can run into decode issue if we share the profile across - String customCMYKProfilePath = null; - try { - Object profileStream; - customCMYKProfilePath = Defs.sysProperty("org.icepdf.core.pobjects.graphics.cmyk"); - if (customCMYKProfilePath == null) { - customCMYKProfilePath = "/org/icepdf/core/pobjects/graphics/res/CoatedFOGRA27.icc"; - profileStream = DeviceCMYK.class.getResourceAsStream(customCMYKProfilePath); - } else { - profileStream = new FileInputStream(customCMYKProfilePath); - } - - ICC_Profile icc_profile = ICC_Profile.getInstance((InputStream) profileStream); - return new ICC_ColorSpace(icc_profile); - } catch (Exception exception) { - logger.warning("Error loading ICC color profile: " + customCMYKProfilePath); - } - return null; - } - - /** - * Determines if the ICC CMYK color space should be used to convert - * CMYK images to RGB. - * - * @return true if the ICC CMYK color space should be used, false otherwise. - */ - public static boolean isDisableICCCmykColorSpace() { - return disableICCCmykColorSpace; - } - - /** - * Set the value of the disableICCCmykColorSpace property. This property - * can be set using the system property org.icepdf.core.cmyk.disableICCProfile - * or overridden using this mehtod. - * - * @param disableICCCmykColorSpace true to disable the ICC CMYK color space - * conversion, false otherwise. - */ - public static void setDisableICCCmykColorSpace(boolean disableICCCmykColorSpace) { - DeviceCMYK.disableICCCmykColorSpace = disableICCCmykColorSpace; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceGray.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceGray.java deleted file mode 100644 index 4826cc6c2c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceGray.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.color.ColorSpace; -import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; - -/** - * @since 1.0 - */ -public class DeviceGray extends PColorSpace { - - public static final Name DEVICEGRAY_KEY = new Name("DeviceGray"); - public static final Name G_KEY = new Name("G"); - private static final ColorSpace RGB_COLOR_SPACE = ColorSpace.getInstance(ColorSpace.CS_sRGB); - - private static ConcurrentHashMap colorHashMap = new ConcurrentHashMap(255); - - public DeviceGray(Library l, HashMap h) { - super(l, h); - } - - - public int getNumComponents() { - return 1; - } - - public Color getColor(float[] f, boolean fillAndStroke) { - float gray = f[0] > 1.0 ? f[0] / 255.f : f[0]; - Color color = colorHashMap.get(f[0]); - if (color != null) { - return color; - } else { - color = new Color(RGB_COLOR_SPACE, - new Color(gray, gray, gray).getRGBComponents(null), - 1); - colorHashMap.put(f[0], color); - return color; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceN.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceN.java deleted file mode 100644 index cae1375c73..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceN.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.functions.Function; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -/** - * DeviceN colour spaces shall be defined in a similar way to Separation colour - * spaces-in fact, a Separationcolour space can be defined as a DeviceN colour - * space with only one component. - *

      - * A DeviceN colour space shall be specified as follows: - * [/DeviceN names alternateSpace tintTransform] - * or - * [/DeviceN names alternateSpace tintTransform attributes] - *

      - * It is a four- or five-element array whose first element shall be the colour - * space family name DeviceN. The remaining elements shall be parameters that a - * DeviceN colour space requires. - */ -public class DeviceN extends PColorSpace { - - public static final Name DEVICEN_KEY = new Name("DeviceN"); - public static final Name COLORANTS_KEY = new Name("Colorants"); - - List names; - PColorSpace alternate; - Function tintTransform; - ConcurrentHashMap colorants = new ConcurrentHashMap(); - PColorSpace colorspaces[]; - - boolean foundCMYK; - - @SuppressWarnings("unchecked") - DeviceN(Library l, HashMap h, Object o1, Object o2, Object o3, Object o4) { - super(l, h); - names = (java.util.List) o1; - alternate = getColorSpace(l, o2); - tintTransform = Function.getFunction(l, l.getObject(o3)); - if (o4 != null) { - HashMap h1 = (HashMap) library.getObject(o4); - HashMap h2 = (HashMap) library.getObject(h1, COLORANTS_KEY); - if (h2 != null) { - Set e = h2.keySet(); - Object oo; - for (Object o : e) { - oo = h2.get(o); - colorants.put(o, getColorSpace(library, library.getObject(oo))); - } - } - } - colorspaces = new PColorSpace[names.size()]; - for (int i = 0; i < colorspaces.length; i++) { - colorspaces[i] = (PColorSpace) colorants.get(names.get(i).toString()); - } - // check to see if cymk is specified int the names, if so we can - // uses the cmyk colour space directly, otherwise we fallback to the alternative - // and hope it was setup correctly. - int cmykCount = 0; - foundCMYK = true; - for (Name name : names) { - if (name.getName().toLowerCase().startsWith("c")) { - cmykCount++; - } else if (name.getName().toLowerCase().startsWith("m")) { - cmykCount++; - } else if (name.getName().toLowerCase().startsWith("y")) { - cmykCount++; - } else if (name.getName().toLowerCase().startsWith("k")) { - cmykCount++; - } else if (name.getName().toLowerCase().startsWith("b")) { - cmykCount++; - } - } - if (cmykCount < 1) { - foundCMYK = false; - } - } - - public int getNumComponents() { - return names.size(); - } - - private float[] assignCMYK(float[] f) { - float[] f2 = new float[4]; - Name name; - for (int i = 0, max = names.size(); i < max; i++) { - name = names.get(i); - if (name.getName().toLowerCase().startsWith("c")) { - f2[0] = i < f.length ? f[i] : 0; - } else if (name.getName().toLowerCase().startsWith("m")) { - f2[1] = i < f.length ? f[i] : 0; - } else if (name.getName().toLowerCase().startsWith("y")) { - f2[2] = i < f.length ? f[i] : 0; - } else if (name.getName().toLowerCase().startsWith("b") || - name.getName().toLowerCase().startsWith("k")) { - f2[3] = i < f.length ? f[i] : 0; - } - } - if (f.length != 4) { - f2 = reverse(f2); - } - return f2; - } - - - public Color getColor(float[] f, boolean fillAndStroke) { - // calculate cmyk color - if (foundCMYK && (f.length == 4 )) { - f = assignCMYK(f); - return new DeviceCMYK(null, null).getColor((f)); - }else if (foundCMYK && (f.length == 3)) { - f = assignCMYK(reverse(f)); - return new DeviceCMYK(null, null).getColor((f)); - } - // check order, mainly look for length > 1 and black not at the end - // assumption on a few corner cases is that we are looking for cmyk ordering - // and thus black last. -// if (f.length > 4 && names.size() > 4) { -// String name = names.get(names.size() - 1).getName().toLowerCase(); -// if (!name.startsWith("b")) { -// f = reverse(f); -// } -// } - // otherwise use the alternative colour space. - float y[] = tintTransform.calculate(reverse(f)); - return alternate.getColor(reverse(y)); - } -} - - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceRGB.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceRGB.java deleted file mode 100644 index d85c87cf2e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/DeviceRGB.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; - -/** - * put your documentation comment here - */ -public class DeviceRGB extends PColorSpace { - - public static final Name DEVICERGB_KEY = new Name("DeviceRGB"); - public static final Name RGB_KEY = new Name("RGB"); - - /** - * @param l - * @param h - */ - DeviceRGB(Library l, HashMap h) { - super(l, h); - } - - /** - * @return - */ - public int getNumComponents() { - return 3; - } - - private float validateColorRange(float component) { - if (component < 0.0f) { - return 0.0f; - } else if (component > 1.0f) { - return 1.0f; - } else { - return component; - } - } - - /** - * Get the awt Color value for for a given colours data. - * - * @param colours array containing the RGB colour values. - * @return a awt colour based on the colours array RGB values. - */ - public Color getColor(float[] colours, boolean fillAndStroke) { - - return new Color(validateColorRange(colours[2]), - validateColorRange(colours[1]), - validateColorRange(colours[0])); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ExtGState.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ExtGState.java deleted file mode 100644 index e2b24ec930..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ExtGState.java +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      This class represents an External Graphics State (ExtGState) object. An - * ExtGState is an extension of the individual operators which sets a graphics - * state, q, Q, cm, w, J, j, M, d, ri, i and gs. The gs operand points to a - * named ExtGState resource which contains a dictionary whose contents specify - * the values of one or more graphics state parameters. All the entries in this - * dictionary are summarized in the following table. An ExtGSate dictionary - * does not need to specify all entries and the results of gs operations are - * cumulative.

      - *

      - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
      Key Type Desription
      Typename(Optional) The type of PDF object that this dictionary describes; - * must be ExtGState for a graphics state parameter dictionary.
      LWnumber(Optional; PDF 1.3) The line width
      - * integer(Optional; PDF 1.3) The line cap style.
      LJinteger(Optional; PDF 1.3) The line join styl.
      MLnumber(Optional; PDF 1.3) The miter limit.
      Darray(Optional; PDF 1.3) The line dash pattern, expressed as an array of - * the form [dashArray dashPhase], where dashArray is itself an array - * and dashPhase is an integer
      RIname(Optional; PDF 1.3) The name of the rendering intent.
      OPboolean(Optional) A flag specifying whether to apply overprint. In PDF 1.2 - * and earlier, there is a single overprint parameter that applies to - * all painting operations. Beginning with PDF 1.3, there are two - * separate overprint parameters: one for stroking and one for all other - * painting operations. Specifying an OP entry sets both parameters - * unless there is also an op entry in the same graphics state parameter - * dictionary, in which case the OP entry sets only the overprint - * parameter for stroking.
      opboolean(Optional; PDF 1.3) A flag specifying whether to apply overprint for - * painting operations other than stroking. If this entry is absent, - * the OP entry, if any, sets this parameter.
      OPMinteger(Optional; PDF 1.3) The overprint mode
      Fontarray(Optional; PDF 1.3) An array of the form [font size], where font is - * an indirect reference to a font dictionary and size is a number - * expressed in text space units. These two objects correspond to the - * operands of the Tf operator; however, the first operand is an - * indirect object reference instead of a resource name.
      BGfunction(Optional) The black-generation function, which maps the interval - * [0.0 1.0] to the interval [0.0 1.0]
      BG2function or name(Optional; PDF 1.3) Same as BG except that the value may also be the - * name Default, denoting the black-generation function that was in effect at the - * start of the page. If both BG and BG2 are present in the same graphics state - * parameter dictionary, BG2 takes precedence.
      UCRfunction(Optional) The undercolor-removal function, which maps the interval - * [0.0 1.0] to the interval [?1.0 1.0] (see Section 6.2.3, "Conversion - * from DeviceRGB to DeviceCMYK").
      UCR2function or name(Optional; PDF 1.3) Same as UCR except that the value may also be - * the name Default, denoting the undercolor-removal function that was - * in effect at the start of the page. If both UCR and UCR2 are present - * in the same graphics state parameter dictionary, UCR2 takes precedence.
      TRfunction, array, or name(Optional) The transfer function, which maps the interval [0.0 1.0] - * to the interval [0.0 1.0] (see Section 6.3, "Transfer Functions"). - * The value is either a single function (which applies to all process - * colorants) or an array of four functions (which apply to the process - * colorants individually). The name Identity may be used to represent - * the identity function.
      TR2function, array, or name(Optional; PDF 1.3) Same as TR except that the value may also be the name - * Default, denoting the transfer function that was in effect at the start of the - * page. If both TR and TR2 are present in the same graphics state parameter dictionary, - * TR2 takes precedence.
      HTdictionary, stream, or name(Optional) The halftone dictionary or stream (see Section 6.4, "Halftones") or - * the name Default, denoting the halftone that was in effect at the start of the - * page.
      FLnumber(Optional; PDF 1.3) The flatness tolerance
      SMnumber(Optional; PDF 1.3) The smoothness tolerance
      SAboolean(Optional) A flag specifying whether to apply automatic stroke adjustment - * (see Section 6.5.4, "Automatic Stroke Adjustment").
      BMname or array(Optional; PDF 1.4) The current blend mode to be used in the - * transparent imaging model.
      SMaskdictionary or name(Optional; PDF 1.4) The current soft mask, specifying the mask shape - * or mask opacity values to be used in the transparent imaging model
      CA number(Optional; PDF 1.4) The current stroking alpha constant, - * specifying the constant shape or constant opacity value to be used for - * stroking operations in the transparent imaging model.
      canumber(Optional; PDF 1.4) Same as CA, but for nonstroking operations.
      - *

      - *

      An ExtGState object is is referenced by a named resource of - * the type ExtGSate. The Resources class method getExtGState() will try and - * return an ExtGState object of the specified name. If successful - * the ExtGState object should be concatenated with the current - * GraphicsState object.

      - *

      - *

      Note: many of the external graphics state parameters have not - * yet been been implemented in the context of the content parser. - * The GraphicsSate object and other relevant rendering pipeline - * classes can be updated as needed.

      - * - * @since 1.4 - */ -public class ExtGState extends Dictionary { - - private static final Logger logger = - Logger.getLogger(ExtGState.class.toString()); - - public static final Name SMASK_KEY = new Name("SMask"); - public static final Name LW_KEY = new Name("LW"); - public static final Name LC_KEY = new Name("LC"); - public static final Name LJ_KEY = new Name("LJ"); - public static final Name ML_KEY = new Name("ML"); - public static final Name CA_KEY = new Name("CA"); - public static final Name ca_KEY = new Name("ca"); - public static final Name BM_KEY = new Name("BM"); - public static final Name OP_KEY = new Name("OP"); - public static final Name op_KEY = new Name("op"); - public static final Name OPM_KEY = new Name("OPM"); - public static final Name D_KEY = new Name("D"); - public static final Name AIS_KEY = new Name("AIS"); - public static final Name HT_KEY = new Name("HT"); - public static final Name BG2_KEY = new Name("BG2"); - // (Optional) A flag specifying whether to apply automatic stroke adjustment - // (see 10.6.5, "Automatic Stroke Adjustment"). - public static final Name SA_KEY = new Name("SA"); - - /** - * Creates a a new Graphics State object. - * - * @param library document object library - * @param graphicsState dictionary containing entries from teh graphcis - * state parameters dictionary. - */ - public ExtGState(Library library, HashMap graphicsState) { - super(library, graphicsState); - } - - /** - * Gets the line width specified by the external graphics state. - * - * @return the line width with Number value. If the line width was not - * specified in the dictionary null is returned. - */ - public Number getLineWidth() { - return getNumber(LW_KEY); - } - - /** - * Gets the line cap style specified by the external graphics state. - * - * @return the line cap style Number value. If the cap style was not - * specified in the dictionary null is returned. - */ - public Number getLineCapStyle() { - return getNumber(LC_KEY); - } - - /** - * Gets the blending mode assigned to the GS. - * - * @return - */ - public Name getBlendingMode() { - Object tmp = library.getObject(entries, BM_KEY); - if (tmp instanceof Name) { - return (Name) tmp; - } else if (tmp instanceof List) { - List list = (List) tmp; - return (Name) list.get(0); - } - return null; - } - - /** - * Gets the line join style specified by the external graphics state. - * - * @return the line join style Number value. If the join style was not - * specified in the dictionary null is returned. - */ - public Number getLineJoinStyle() { - return getNumber(LJ_KEY); - } - - /** - * Gets the miter limit specified by the external graphics state. - * - * @return the miter limit Number value. If the miter limit was not - * specified in the dictionary null is returned. - */ - Number getMiterLimit() { - return getNumber(ML_KEY); - } - - /** - * Gets the line dash pattern specified by the external graphics state. - * - * @return the line dash array [dashArray dashPhase]. If the dash pattern - * is not specified the dictionary null is returned. - */ - public List getLineDashPattern() { - List dashPattern = null; - Number dashPhase; - float[] dashArray = null; - if (entries.containsKey(D_KEY)) { - try { - List dashData = (List) entries.get(D_KEY); - // pop dashPhase off the stack - dashPhase = (Number) dashData.get(1); - // pop the dashVector of the stack - List dashVector = (List) dashData.get(0); - // if the dash vector size is zero we have a default none dashed - // line and thus we skip out - if (dashVector.size() > 0) { - // conver dash vector to a array of floats - final int sz = dashVector.size(); - dashArray = new float[sz]; - for (int i = 0; i < sz; i++) { - dashArray[i] = ((Number) dashVector.get(i)).floatValue(); - } - } - // default to standard black line - else { - dashPhase = 0f; - dashArray = null; - } - dashPattern = new ArrayList(2); - dashPattern.add(dashArray); - dashPattern.add(dashPhase); - } catch (ClassCastException e) { - logger.log(Level.FINE, "Dash pattern syntax error: ", e); - } - } - return dashPattern; - } - - /** - * Gets the stroking alpha constant specified by the external graphics state. - * - * @return the stroking alpha constant value. If the stroking alpha constant - * was not specified in the dictionary null is returned. - */ - public float getStrokingAlphConstant() { - if (getNumber(CA_KEY) != null) - return getFloat(CA_KEY); - else { - return -1; - } - } - - /** - * Gets the non-stroking alpha constant specified by the external graphics state. - * - * @return the non stroking alpha constant value. If the non-stroking alpha constant - * was not specified in the dictionary null is returned. - */ - public float getNonStrokingAlphConstant() { - if (getNumber(ca_KEY) != null) - return getFloat(ca_KEY); - else { - return -1; - } - } - - /** - * An optional flag specifying whether to apply overprint. In PDF 1.2 - * and earlier, there is a single overprint parameter that applies to - * all painting operations. Beginning with PDF 1.3, there are two - * separate overprint parameters: one for stroking and one for all other - * painting operations. Specifying an OP entry sets both parameters - * unless there is also an op entry in the same graphics state parameter - * dictionary, in which case the OP entry sets only the overprint - * parameter for stroking. - * - * @return true if OP is enabled. - */ - public Boolean getOverprint() { - Object o = getObject(OP_KEY); - if (o instanceof String) - return Boolean.valueOf((String) o); - else if (o instanceof Boolean) { - return (Boolean) o; - } - return null; - } - - public Boolean isAlphaAShape() { - Object o = getObject(AIS_KEY); - if (o instanceof String) - return Boolean.valueOf((String) o); - else if (o instanceof Boolean) { - return (Boolean) o; - } - return false; - } - - /** - * An optional flag specifying whether to apply overprint for - * painting operations other than stroking. If this entry is absent, - * the OP entry, if any, sets this parameter. - * - * @return true if enabled, false otherwise. - */ - public Boolean getOverprintFill() { - Object o = getObject(op_KEY); - if (o instanceof String) - return Boolean.valueOf((String) o); - else if (o instanceof Boolean) { - return (Boolean) o; - } - return null; - } - - /** - * The overprint mode - * - * @return - */ - public int getOverprintMode() { - return getInt(OPM_KEY); - } - - public boolean hasOverPrintMode() { - return library.getObject(entries, OPM_KEY) != null; - } - - public boolean hasAlphaIsShape() { - return library.getObject(entries, AIS_KEY) != null; - } - - public boolean hasHalfTone() { - return library.getObject(entries, HT_KEY) != null; - } - - public boolean hasBG2Function() { - return library.getObject(entries, BG2_KEY) != null; - } - - - public SoftMask getSMask() { - Object tmp = library.getObject(entries, SMASK_KEY); - if (tmp != null && tmp instanceof HashMap) { - // create a new SMask dictionary - SoftMask softMask = new SoftMask(library, (HashMap) tmp); - softMask.setPObjectReference(library.getReference(entries, SMASK_KEY)); - return softMask; - } - return null; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/FloydSteinbergImageReference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/FloydSteinbergImageReference.java deleted file mode 100644 index d9f3bb7605..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/FloydSteinbergImageReference.java +++ /dev/null @@ -1,183 +0,0 @@ -package org.icepdf.core.pobjects.graphics; - /* -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.util.Library; - -import javax.media.jai.*; -import javax.media.jai.operator.ErrorDiffusionDescriptor; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.awt.image.ColorModel; -import java.awt.image.DataBuffer; -import java.awt.image.IndexColorModel; -import java.awt.image.renderable.ParameterBlock; -import java.util.logging.Logger; - */ - -/** - * @since 5.0.1 - */ -public class FloydSteinbergImageReference{// extends CachedImageReference { - /* - private static final Logger logger = - Logger.getLogger(ScaledImageReference.class.toString()); - - // scaled image size. - private int width; - private int height; - - protected FloydSteinbergImageReference(ImageStream imageStream, Color fillColor, Resources resources) { - super(imageStream, fillColor, resources); - - // get eh original image width. - width = imageStream.getWidth(); - height = imageStream.getHeight(); - - // kick off a new thread to load the image, if not already in pool. - ImagePool imagePool = imageStream.getLibrary().getImagePool(); - if (useProxy && imagePool.get(reference) == null) { - Library.executePainter(futureTask); - } else if (!useProxy && imagePool.get(reference) == null) { - call(); - } - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public BufferedImage call() { - try { - image = imageStream.getImage(fillColor, resources); -// DitherFloydSteinberg tmp = new DitherFloydSteinberg(); -// tmp.Process(image); - if (image != null) { - // JAI filter code - PlanarImage surrogateImage = PlanarImage.wrapRenderedImage(image); - ParameterBlock pb = new ParameterBlock(); - pb.addSource(surrogateImage); - String opName = null; - LookupTableJAI lut; - if (true) { - opName = "errordiffusion"; - lut = new LookupTableJAI(new byte[]{(byte) 0x00, (byte) 0xff}); - pb.add(lut); - pb.add(KernelJAI.ERROR_FILTER_FLOYD_STEINBERG); - } else { - opName = "ordereddither"; - ColorCube cube = ColorCube.createColorCube(DataBuffer.TYPE_BYTE, - 0, new int[]{2}); - pb.add(cube); - pb.add(KernelJAI.DITHER_MASK_441); - - } - ImageLayout layout = new ImageLayout(); - byte[] map = new byte[] {(byte)0x00, (byte)0xff}; - ColorModel cm = new IndexColorModel(1, 2, map, map, map); - layout.setColorModel(cm); - RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout); - PlanarImage op = ErrorDiffusionDescriptor.create(surrogateImage, lut, - KernelJAI.ERROR_FILTER_FLOYD_STEINBERG, hints); - BufferedImage dst = op.getAsBufferedImage(); -// PlanarImage dst = JAI.create(opName, pb, hints); - - image = dst; - } - } catch (Throwable e) { - logger.warning("Error loading image: " + imageStream.getPObjectReference() + - " " + imageStream.toString()); - } - return image; - } - - public class DitherFloydSteinberg { - int max_intensity, min_intensity; - - private int decode(int oldPixel) { - int r = (oldPixel >> 16) & 0xff; - int g = (oldPixel >> 8) & 0xff; - int b = (oldPixel) & 0xff; - return (int) ((r + g + b) / 3); - } - - private int encode(int oldPixel) { - return (0xff << 24) | (oldPixel << 16) | (oldPixel << 8) | (oldPixel); - } - - private int ScaleIntensity(int i) { - float scale = (float) (i - min_intensity) / (float) (max_intensity - min_intensity); - return (int) (255 * scale); - } - - private int find_closest_palette_color(int oldPixel) { - int i = ScaleIntensity(oldPixel); - return (i > 127) ? 255 : 0; - } - - - private void FindIntensityRange(BufferedImage img) { - int w = img.getWidth(); - int h = img.getHeight(); - int x, y, i; - - max_intensity = 0; - min_intensity = 255; -// max_intensity=255; -// min_intensity=000; - for (y = 0; y < h; ++y) { - // for each x from left to right - for (x = 0; x < w; ++x) { - // oldpixel := pixel[x][y] - i = decode(img.getRGB(x, y)); - if (max_intensity < i) max_intensity = i; - if (min_intensity > i) min_intensity = i; - img.setRGB(x, y, encode(i)); - } - } - } - - // Floyd-Steinberg dithering - public void Process(BufferedImage img) { - int x, y, oldPixel, newPixel; - float quant_error; - int w = img.getWidth(); - int h = img.getHeight(); - - FindIntensityRange(img); - - // for each y from top to bottom - for (y = 0; y < h; ++y) { - // for each x from left to right - for (x = 0; x < w; ++x) { - // oldpixel := pixel[x][y] - oldPixel = decode(img.getRGB(x, y)); - // newpixel := find_closest_palette_color(oldpixel) - newPixel = find_closest_palette_color(oldPixel); - // pixel[x][y] := newpixel - img.setRGB(x, y, encode(newPixel)); - // quant_error := oldpixel - newpixel - quant_error = oldPixel - newPixel; - // pixel[x+1][y ] := pixel[x+1][y ] + 7/16 * quant_error - // pixel[x-1][y+1] := pixel[x-1][y+1] + 3/16 * quant_error - // pixel[x ][y+1] := pixel[x ][y+1] + 5/16 * quant_error - // pixel[x+1][y+1] := pixel[x+1][y+1] + 1/16 * quant_error - if (x < w - 1) - img.setRGB(x + 1, y, encode((int) ((float) decode(img.getRGB(x + 1, y)) + (7.0 / 16.0 * quant_error)))); - if (y < h - 1) { - if (x > 0) - img.setRGB(x - 1, y + 1, encode((int) ((float) decode(img.getRGB(x - 1, y + 1)) + (3.0 / 16.0 * quant_error)))); - img.setRGB(x, y + 1, encode((int) ((float) decode(img.getRGB(x, y + 1)) + (5.0 / 16.0 * quant_error)))); - if (x < w - 1) - img.setRGB(x + 1, y + 1, encode((int) ((float) decode(img.getRGB(x + 1, y + 1)) + (1.0 / 16.0 * quant_error)))); - } - } - } - } - } - */ -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/GlyphOutlineClip.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/GlyphOutlineClip.java deleted file mode 100644 index 2bea7ee7c3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/GlyphOutlineClip.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import java.awt.*; -import java.awt.geom.Area; -import java.awt.geom.GeneralPath; - -/** - * GlyphOutlineClip is contains the glyph outlines for glyph contained - * within a TextBlock. This utility method makes it possible to apply - * text rendering modes that require glyph outlines for clipping such - * as modes 4-7. - * - * @since 4.3.3 - */ -public class GlyphOutlineClip { - - private GeneralPath path; - - public void addTextSprite(TextSprite nextSprite) { - Area area = nextSprite.getGlyphOutline(); - // When TJ/Tj and Other text operators are called on a font using - // modes 5-7 we don't actually craw anything but we still need to - // transform the glyph to the correct coordinate, so each - // outline is place correctly with in the total outline shape. - Area tmp = area.createTransformedArea(nextSprite.getGraphicStateTransform()); - if (path == null) { - path = new GeneralPath(tmp); - } else { - path.append(tmp, false); - } - } - - /** - * Check to see if the glyph outline contains any outline data. - * - * @return true if the are no glyph outlines, otherwise; false. - */ - public boolean isEmpty() { - return path == null; - } - - /** - * Gets the glyph outline shape which can be used for painting or clipping. - * - * @return glyph outline shape. - */ - public Shape getGlyphOutlineClip() { - return path; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/GraphicsState.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/GraphicsState.java deleted file mode 100644 index 487fc8e917..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/GraphicsState.java +++ /dev/null @@ -1,828 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.graphics.commands.*; -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      The PDF viewer application maintains an internal data structure called the - * graphics state that holds current graphics control parameters. These - * parameters define the global framework within which the graphics operators - * execute.

      - *

      - *

      The graphics state is initialized at the beginning of each page, using the - * default values specified in Tables 4.2 and 4.3. Table 4.2 lists those - * graphics state parameters that are device-independent and are appropriate - * to specify in page descriptions. The parameters listed in Table 4.3 control - * details of the rendering (scan conversion) process and are device-dependent; - * a page description that is intended to be device-independent should not - * modify these parameters.

      - *

      - *

      Graphics State Stack Info

      - *

      A well-structured PDF document typically contains many graphical elements - * that are essentially independent of each other and sometimes nested to - * multiple levels. The graphics state stack allows these elements to make local - * changes to the graphics state without disturbing the graphics state of the - * surrounding environment. The stack is a LIFO (last in, first out) data - * structure in which the contents of the graphics state can be saved and later - * restored using the following operators: - *

        - *
      • The q operator pushes a copy of the entire graphics state onto the - * stack. This is handled by the save() method in this class

      • - *
      • The Q operator restores the entire graphics state to its former - * value by popping it from the stack. This is handled by the - * restore() method in this class

      • - *
      - *

      When a graphics state is saved a new GraphicsState object is created and - * a pointer is set to the origional graphics state. This creates a linked - * list of graphics states that can be easily restored when needed (LIFO staack) - *

      - *

      Shapes Stack

      - *

      The graphics state also manipulates the Shapes stack that contains all of - * the rendering components dealing with graphics states. As the content parser - * encounters different graphic state manipulators they are added to the stack - * and then when the page is rendered the stack (actually a vector) is read - * in a FIFO to generate the drawing commands.

      - *

      - *

      Device-independent graphics state parameters - (Table 4.2)

      - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
      Paramater Type Value
      CTMarrayThe current transformation matrix, which maps positions from user - * coordinates to device coordinates. This matrix is modified by each - * application of the coordinate transformation operator, cm. Initial - * value: a matrix that transforms default user coordinates to device - * coordinates.
      clipping path(internal)The current clipping path, which defines the boundary against which - * all output is to be cropped. Initial value: the boundary of the - * entire imageable portion of the output page.
      color spacename or arrayThe current color space in which color values are to be interpreted. - * There are two separate color space parameters: one for stroking and - * one for all other painting operations. Initial value: DeviceGray.
      color(variousThe current color to be used during painting operations. The type - * and interpretation of this parameter depend on the current color - * space; for most color spaces, a color value consists of one to four - * numbers. There are two separate color parameters: one for stroking - * and one for all other painting operations. Initial value: black.
      text state(various)A set of nine graphics state parameters that pertain only to the - * painting of text. These include parameters that select the font, - * scale the glyphs to an appropriate size, and accomplish other effects. - * The text state parameters are described in Section 5.2, "Text State - * Parameters and Operators."
      line widthnumberThe thickness, in user space units, of paths to be stroked.
      line capintegerA code specifying the shape of the endpoints for any open path that - * is stroked (see "Line Cap Style" on page 186). Initial value: 0, for - * square butt caps.
      line joinintegerA code specifying the shape of joints between connected segments of - * a stroked path. Initial value: 0, for mitered joins.
      miter limitnumberThe maximum length of mitered line joins for stroked paths. This - * parameter limits the length of "spikes" produced when line segments - * join at sharp angles. Initial value: 10.0, for a miter cutoff below - * approximately 11.5 degrees.
      dash patternarray and numberA description of the dash pattern to be used when paths are stroked. - * Initial value: a solid line.
      rendering intent (Not supported)nameThe rendering intent to be used when converting CIE-based colors to - * device colors. Default value: RelativeColorimetric.
      stroke adjustment (Not supported)boolean(PDF 1.2) A flag specifying whether to compensate for possible - * rasterization effects when stroking a path with a line width that is - * small relative to the pixel resolution of the output device.. - * Note that this is considered a device-independent parameter, even - * though the details of its effects are device-dependent. - * Initial value: false.
      blend mode (Not supported)name or array(PDF 1.4) The current blend mode to be used in the transparent - * imaging model. This parameter is implicitly reset to its initial - * value at the beginning of execution of a transparency group XObject. - * Initial value: Normal.
      soft mask (Not supported)dictionary or name(PDF 1.4) A soft-mask dictionary specifying the mask shape or mask - * opacity values to be used in the transparent imaging model, or the - * name None if no such mask is specified. This parameter is implicitly - * reset to its initial value at the beginning of execution of a - * transparency group XObject. Initial value: None.
      alpha constantnumber(PDF 1.4) The constant shape or constant opacity value to be used in - * the transparent imaging model. There are two separate alpha constant - * parameters: one for stroking and one for all other painting - * operations. This parameter is implicitly reset to its initial value - * at the beginning of execution of a transparency group XObject. - * Initial value: 1.0.
      alpha sourceboolean(PDF 1.4) A flag specifying whether the current soft mask and alpha - * constant parameters are to be interpreted as shape values (true) or - * opacity values (false). This flag also governs the interpretation of - * the SMask entry, if any, in an image dictionary. - * Initial value: false.
      - *

      - *

      Device-Dependent graphics state parameters - (Table 4.3)

      - *

      Currently Not supported

      - * - * @since 1.0 - */ -public class GraphicsState { - - private static final Logger logger = - Logger.getLogger(GraphicsState.class.toString()); - - public static final Name CA_STROKING_KEY = new Name("CA"); - public static final Name CA_NON_STROKING_KEY = new Name("ca"); - - // allow over paint support for fill and stroke. Still experimental - // enabled buy default but can be turned off if required. - private static boolean enabledOverpaint; - - static { - enabledOverpaint = - Defs.sysPropertyBoolean("org.icepdf.core.overpaint", - true); - } - - - // Current transformation matrix. - private AffineTransform CTM; - - private static ClipDrawCmd clipDrawCmd = new ClipDrawCmd(); - private static NoClipDrawCmd noClipDrawCmd = new NoClipDrawCmd(); - - // Specifies the shape of the endpoint for any open path. - private int lineCap; - - // Specifies the thickness in user parse of a path to be stroked. - private float lineWidth; - - // Specifies the shape of the joints between connected segments. - private int lineJoin; - - // Maximum length of mitered line join for stroked paths. - private float miterLimit; - - // Stores the lengths of the dash segments - private float[] dashArray; - - // Stores the current dash phase - private float dashPhase; - - // color used to fill a stroked path. - private Color fillColor; - - // The current color to be used during a painting operation. - private Color strokeColor; - - // Stroking alpha constant for "CA" - private float strokeAlpha; - - // Fill alpha constant for "ca" or non-stroking alpha - private float fillAlpha; - - // Transparency grouping changes which transparency rule is applied. - // Normally it is simply a SRC_OVER rule but the group can also have isolated - // and knockout values that directly affect which rule is used for the - // transparency. - private ExtGState extGState; - private int alphaRule; - - private boolean transparencyGroup; - private boolean isolated; - private boolean knockOut; - - // Color space of the fill color, non-stroking colour. - private PColorSpace fillColorSpace; - - // Color space of the stroke color, stroking colour. - private PColorSpace strokeColorSpace; - - // Set of graphics stat parameter for painting text. - private TextState textState; - - // parent graphics state if it exists. - private GraphicsState parentGraphicState; - - // all shapes associated with this graphics state. - private Shapes shapes; - - // current clipping area. - private Area clip; - private boolean clipChange; - - // over print mode - private int overprintMode; - // over printing stroking - private boolean overprintStroking; - // over printing everything other than stroking - private boolean overprintOther; - - /** - * Constructs a new GraphicsState which will have default - * values and shapes specified by the shapes stack. - * - * @param shapes stack containing pages graphical elements. - */ - public GraphicsState(Shapes shapes) { - this.shapes = shapes; - CTM = new AffineTransform(); - - lineCap = BasicStroke.CAP_BUTT; - lineWidth = 1; - lineJoin = BasicStroke.JOIN_MITER; - miterLimit = 10; - - fillColor = Color.black; - strokeColor = Color.black; - strokeAlpha = 1.0f; - fillAlpha = 1.0f; - - alphaRule = AlphaComposite.SRC_OVER; - fillColorSpace = new DeviceGray(null, null); - strokeColorSpace = new DeviceGray(null, null); - textState = new TextState(); - - } - - /** - * Constructs a new GraphicsState that is a copy of - * the specified GraphicsState object. - * - * @param parentGraphicsState the GraphicsState object to copy - */ - public GraphicsState(GraphicsState parentGraphicsState) { - - // copy/clone the parentGraphicsState and return the new object. - - CTM = new AffineTransform(parentGraphicsState.CTM); - - lineCap = parentGraphicsState.lineCap; - lineWidth = parentGraphicsState.lineWidth; - miterLimit = parentGraphicsState.miterLimit; - lineJoin = parentGraphicsState.lineJoin; - - - fillColor = new Color(parentGraphicsState.fillColor.getRGB(), true); - - strokeColor = new Color(parentGraphicsState.strokeColor.getRGB(), true); - - shapes = parentGraphicsState.shapes; - if (parentGraphicsState.clip != null) { - clip = (Area) parentGraphicsState.clip.clone(); - } - - fillColorSpace = parentGraphicsState.fillColorSpace; - strokeColorSpace = parentGraphicsState.strokeColorSpace; - textState = new TextState(parentGraphicsState.textState); - dashPhase = parentGraphicsState.dashPhase; - dashArray = parentGraphicsState.dashArray; - - // copy over printing attributes - overprintMode = parentGraphicsState.overprintMode; - overprintOther = parentGraphicsState.overprintOther; - overprintStroking = parentGraphicsState.overprintStroking; - - // copy the alpha rules - fillAlpha = parentGraphicsState.fillAlpha; - strokeAlpha = parentGraphicsState.strokeAlpha; - alphaRule = parentGraphicsState.alphaRule; - - // extra graphics - if (parentGraphicsState.getExtGState() != null) { - extGState = new ExtGState(parentGraphicsState.getExtGState().getLibrary(), - parentGraphicsState.getExtGState().getEntries()); - } - - // copy the parent too. - this.parentGraphicState = parentGraphicsState.parentGraphicState; - - } - - /** - * Sets the Shapes vector. - * - * @param shapes shapes for a given content stream. - */ - public void setShapes(Shapes shapes) { - this.shapes = shapes; - } - - /** - * Concatenates this transform with a translation transformation specified - * by the graphics state current CTM. An updated CTM is added to the - * shapes stack. - * - * @param x the distance by which coordinates are translated in the - * X axis direction - * @param y the distance by which coordinates are translated in the - * Y axis direction - */ - public void translate(double x, double y) { - CTM.translate(x, y); - shapes.add(new TransformDrawCmd(new AffineTransform(CTM))); - } - - /** - * Concatenates this transform with a scaling transformation specified - * by the graphics state current CTM. An update CTM is added to the - * shapes stack. - * - * @param x the factor by which coordinates are scaled along the - * X axis direction - * @param y the factor by which coordinates are scaled along the - * Y axis direction - */ - public void scale(double x, double y) { - CTM.scale(x, y); - shapes.add(new TransformDrawCmd(new AffineTransform(CTM))); - } - - /** - * Sets the graphics state CTM to a new transform, the old CTM transform is - * lost. The new CTM value is added to the shapes stack. - * - * @param af the AffineTranform object to set the CTM to. - */ - public void set(AffineTransform af) { - // appling a CTM can be expensive, so only do it if it's needed. - if (!CTM.equals(af)) { - CTM = new AffineTransform(af); - } - shapes.add(new TransformDrawCmd(new AffineTransform(CTM))); - } - - /** - * Saves the current graphics state. - * - * @return copy of the current graphics state. - * @see #restore() - */ - public GraphicsState save() { - GraphicsState gs = new GraphicsState(this); - gs.parentGraphicState = this; - return gs; - } - - /** - * Concatenate the specified ExtGState to the current graphics state. - * Note: currently only a few of the ExtGState attributes are - * supported. - * - * @param extGState external graphics state. - * @see org.icepdf.core.pobjects.graphics.ExtGState - */ - public void concatenate(ExtGState extGState) { - // keep a reference for our partial Transparency group support. - this.extGState = new ExtGState(extGState.getLibrary(), - extGState.getEntries()); - - // Map over extGState attributes if present. - // line width - if (extGState.getLineWidth() != null) { - setLineWidth(extGState.getLineWidth().floatValue()); - } - // line cap style - if (extGState.getLineCapStyle() != null) { - setLineCap(extGState.getLineCapStyle().intValue()); - } - // line join style - if (extGState.getLineJoinStyle() != null) { - setLineJoin(extGState.getLineJoinStyle().intValue()); - } - // line miter limit - if (extGState.getMiterLimit() != null) { - setMiterLimit(extGState.getMiterLimit().floatValue()); - } - // line dash pattern - if (extGState.getLineDashPattern() != null) { - List dasshPattern = extGState.getLineDashPattern(); - try { - setDashArray((float[]) dasshPattern.get(0)); - setDashPhase(((Number) dasshPattern.get(1)).floatValue()); - } catch (ClassCastException e) { - logger.log(Level.FINE, "Dash cast error: ", e); - } - } - // Stroking alpha - if (extGState.getNonStrokingAlphConstant() != -1) { - setFillAlpha(extGState.getNonStrokingAlphConstant()); - } - // none stroking alpha - if (extGState.getStrokingAlphConstant() != -1) { - setStrokeAlpha(extGState.getStrokingAlphConstant()); - } - - setOverprintMode(extGState.getOverprintMode()); - - // apply over print logic - processOverPaint(extGState.getOverprint(), extGState.getOverprintFill()); - } - - /** - * Process the OP and op over printing attributes. - * - * @param OP OP graphics state param - * @param op op graphics state param - */ - private void processOverPaint(Boolean OP, Boolean op) { - // PDF 1.2 and earlier, only a single overprint parameter - if (enabledOverpaint && - OP != null && op == null && overprintMode == 1) { - overprintStroking = OP; - overprintOther = overprintStroking; - } - // PDF 1.2 and over -// else if (OP != null) { -// overprintStroking = OP.booleanValue(); -// overprintOther = op.booleanValue(); -// } - // else default inits of false for each is fine. - } - - - /** - * Restores the previously saved graphic state. - * - * @return the last saved graphics state. - * @see #save() - */ - public GraphicsState restore() { - // make sure we have a parent to restore to - if (parentGraphicState != null) { - // Add the parents CTM to the stack, - parentGraphicState.set(parentGraphicState.CTM); - // Add the parents clip to the stack - if (clipChange) { - if (parentGraphicState.clip != null) { - if (!parentGraphicState.clip.equals(clip)) { - parentGraphicState.shapes.add(new ShapeDrawCmd(new Area(parentGraphicState.clip))); - parentGraphicState.shapes.add(clipDrawCmd); - } - } else { - parentGraphicState.shapes.add(noClipDrawCmd); - } - } - // Update the stack with the parentGraphicsState stack. - parentGraphicState.shapes.add(new StrokeDrawCmd( - new BasicStroke(parentGraphicState.lineWidth, - parentGraphicState.lineCap, - parentGraphicState.lineJoin, - parentGraphicState.miterLimit, - parentGraphicState.dashArray, - parentGraphicState.dashPhase))); - - // Note the following aren't officially part of the graphic state parameters - // but they need to be restored in order to show some PDF content correctly - - // restore the fill color of the last paint - parentGraphicState.shapes.add(new ColorDrawCmd(parentGraphicState.getFillColor())); - - // apply the old alpha fill - if (fillAlpha != parentGraphicState.getFillAlpha()) { - parentGraphicState.shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(parentGraphicState.getAlphaRule(), parentGraphicState.getFillAlpha()))); - } - - if (strokeAlpha != parentGraphicState.getStrokeAlpha()) { - parentGraphicState.shapes.add(new AlphaDrawCmd( - AlphaComposite.getInstance(parentGraphicState.getAlphaRule(), parentGraphicState.getStrokeAlpha()))); - } - // stroke Color -// parentGraphicState.shapes.add(parentGraphicState.getStrokeColor()); - } - - return parentGraphicState; - } - - /** - * Updates the clip every time the tranformation matrix is updated. This is - * needed to insure that when a new shape is interesected with the - * previous clip that they are both in the same space. - * - * @param af transform to be applied to the clip. - */ - public void updateClipCM(AffineTransform af) { - // we need to update the current clip with the new transform, which is - // actually the inverse of the matrix defined by "cm" in the content - // parser. - - if (clip != null) { - // get the inverse of the transform and apply it to clipCM - AffineTransform afInverse = new AffineTransform(); - try { - afInverse = af.createInverse(); - } catch (Exception e) { - logger.log(Level.FINER, "Error generating clip inverse.", e); - } - - // transform the clip. - clip.transform(afInverse); - } - } - - /** - * Set the graphics state clipping area. The new clipping area is - * intersected with the current current clip to generate the new clipping - * area which is saved to the stack. - * - * @param newClip new clip for graphic state. - */ - public void setClip(Shape newClip) { - if (newClip != null) { - // intersect can only be calculated on a an area. - Area area = new Area(newClip); - // make sure the clip is not null - if (clip != null) { - area.intersect(clip); - } - // update the clip with the new value if it is new. - if (clip == null || !clip.equals(area)) { - clip = new Area(area); - shapes.add(new ShapeDrawCmd(area)); - shapes.add(clipDrawCmd); - clipChange = true; - if (parentGraphicState != null) parentGraphicState.clipChange = true; - } else { - clip = new Area(area); - } - } else { - // add a null clip for a null shape, should not normally happen - clip = null; - shapes.add(noClipDrawCmd); - clipChange = true; - if (parentGraphicState != null) parentGraphicState.clipChange = true; - } - - } - - public Area getClip() { - return clip; - } - - public AffineTransform getCTM() { - return CTM; - } - - public void setCTM(AffineTransform ctm) { - CTM = ctm; - } - - public int getLineCap() { - return lineCap; - } - - public void setLineCap(int lineCap) { - this.lineCap = lineCap; - } - - public float getLineWidth() { - return lineWidth; - } - - public void setLineWidth(float lineWidth) { - // Automatic Stroke Adjustment - if (lineWidth <= Float.MIN_VALUE || lineWidth >= Float.MAX_VALUE || - lineWidth == 0) { - // set line width to a very small none zero number. - this.lineWidth = 0.001f; - } else { - this.lineWidth = lineWidth; - } - - } - - public int getLineJoin() { - return lineJoin; - } - - public void setLineJoin(int lineJoin) { - this.lineJoin = lineJoin; - } - - public float[] getDashArray() { - return dashArray; - } - - public void setDashArray(float[] dashArray) { - this.dashArray = dashArray; - } - - public float getDashPhase() { - return dashPhase; - } - - public void setDashPhase(float dashPhase) { - this.dashPhase = dashPhase; - } - - public float getMiterLimit() { - return miterLimit; - } - - public void setMiterLimit(float miterLimit) { - this.miterLimit = miterLimit; - } - - public Color getFillColor() { - return fillColor; - } - - public void setFillColor(Color fillColor) { - this.fillColor = fillColor; - } - - public Color getStrokeColor() { - return strokeColor; - } - - public void setStrokeAlpha(float alpha) { - if (alpha > 1.0f) { - alpha = 1.0f; - } - strokeAlpha = alpha; - } - - public float getStrokeAlpha() { - return strokeAlpha; - } - - public void setFillAlpha(float alpha) { - if (alpha > 1.0f) { - alpha = 1.0f; - } - fillAlpha = alpha; - } - - public float getFillAlpha() { - return fillAlpha; - } - - public void setStrokeColor(Color strokeColor) { - this.strokeColor = strokeColor; - } - - public PColorSpace getFillColorSpace() { - return fillColorSpace; - } - - public void setFillColorSpace(PColorSpace fillColorSpace) { - this.fillColorSpace = fillColorSpace; - } - - public PColorSpace getStrokeColorSpace() { - return strokeColorSpace; - } - - public void setStrokeColorSpace(PColorSpace strokeColorSpace) { - this.strokeColorSpace = strokeColorSpace; - } - - public TextState getTextState() { - return textState; - } - - public void setTextState(TextState textState) { - this.textState = textState; - } - - public int getOverprintMode() { - return overprintMode; - } - - public boolean isOverprintStroking() { - return overprintStroking; - } - - public boolean isOverprintOther() { - return overprintOther; - } - - public void setOverprintMode(int overprintMode) { - this.overprintMode = overprintMode; - } - - public void setOverprintStroking(boolean overprintStroking) { - this.overprintStroking = overprintStroking; - } - - public void setOverprintOther(boolean overprintOther) { - this.overprintOther = overprintOther; - } - - public int getAlphaRule() { - return alphaRule; - } - - public void setAlphaRule(int alphaRule) { - this.alphaRule = alphaRule; - } - - public boolean isTransparencyGroup() { - return transparencyGroup; - } - - public void setTransparencyGroup(boolean transparencyGroup) { - this.transparencyGroup = transparencyGroup; - } - - public boolean isIsolated() { - return isolated; - } - - public void setIsolated(boolean isolated) { - this.isolated = isolated; - } - - public boolean isKnockOut() { - return knockOut; - } - - public void setKnockOut(boolean knockOut) { - this.knockOut = knockOut; - } - - public ExtGState getExtGState() { - return extGState; - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ICCBased.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ICCBased.java deleted file mode 100644 index e6946668b5..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ICCBased.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import java.awt.*; -import java.awt.color.ColorSpace; -import java.awt.color.ICC_ColorSpace; -import java.awt.color.ICC_Profile; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * put your documentation comment here - */ -public class ICCBased extends PColorSpace { - - private static final Logger logger = - Logger.getLogger(ICCBased.class.toString()); - - public static final Name ICCBASED_KEY = new Name("ICCBased"); - public static final Name N_KEY = new Name("N"); - - private int numcomp; - private PColorSpace alternate; - private Stream stream; - private ColorSpace colorSpace; - - // basic cache to speed up the lookup, can't be static as we handle - // 3 and 4 band colours. - private ConcurrentHashMap iccColorCache3B; - private ConcurrentHashMap iccColorCache4B; - - // setting up an ICC colour look up is expensive, so if we get a failure - // we just fallback to the alternative space to safe cpu time. - private boolean failed; - - public ICCBased(Library l, Stream h) { - super(l, h.getEntries()); - iccColorCache3B = new ConcurrentHashMap(); - iccColorCache4B = new ConcurrentHashMap(); - numcomp = h.getInt(N_KEY); - switch (numcomp) { - case 1: - alternate = new DeviceGray(l, null); - break; - case 3: - alternate = new DeviceRGB(l, null); - break; - case 4: - alternate = new DeviceCMYK(l, null); - break; - } - stream = h; - } - - /** - * - */ - public synchronized void init() { - if (inited) { - return; - } - - byte[] in; - try { - stream.init(); - in = stream.getDecodedStreamBytes(0); - if (logger.isLoggable(Level.FINEST)) { - String content = Utils.convertByteArrayToByteString(in); - logger.finest("Content = " + content); - } - if (in != null) { - ICC_Profile profile = ICC_Profile.getInstance(in); - colorSpace = new ICC_ColorSpace(profile); - } - } catch (Exception e) { - logger.log(Level.FINE, "Error Processing ICCBased Colour Profile", e); - } - inited = true; - } - - /** - * Get the alternative colour specified by the N dictionary entry. DeviceGray, - * DeviceRGB, or DeviceCMYK, depending on whether the value of N is 1, 3 - * or 4, respectively. - * - * @return PDF colour space represented by the N (number of components)key. - */ - public PColorSpace getAlternate() { - return alternate; - } - - private static int generateKey(float[] f) { - int key = 0; - if (f.length == 1) { - key = ((int) (f[0] * 255) & 0xff); - } else if (f.length == 2) { - key = (((int) (f[0] * 255) & 0xff) << 8) | - (((int) (f[1] * 255) & 0xff) & 0xff); - } else if (f.length == 3) { - key = (((int) (f[0] * 255) & 0xff) << 16) | - (((int) (f[1] * 255) & 0xff) << 8) | - (((int) (f[2] * 255) & 0xff) & 0xff); - } else if (f.length == 4) { - key = (((int) (f[0] * 255) & 0xff) << 24) | - (((int) (f[1] * 255) & 0xff) << 16) | - (((int) (f[2] * 255) & 0xff) << 8) | - (((int) (f[3] * 255) & 0xff) & 0xff); - } - return key; - } - - private static Color addColorToCache( - ConcurrentHashMap iccColorCache, int key, - ColorSpace colorSpace, float[] f) { - Color color = iccColorCache.get(key); - if (color != null) { - return color; - } else { - color = new Color(calculateColor(f, colorSpace)); - iccColorCache.put(key, color); - return color; - } - } - - public Color getColor(float[] f, boolean fillAndStroke) { - init(); - if (colorSpace != null && !failed) { - try { - // generate a key for the colour - int key = generateKey(f); - if (f.length <= 3) { - return addColorToCache(iccColorCache3B, key, colorSpace, f); - } else { - return addColorToCache(iccColorCache4B, key, colorSpace, f); - } - } catch (Exception e) { - logger.log(Level.FINE, "Error getting ICCBased colour", e); - failed = true; - } - } - return alternate.getColor(f); - } - - private static int calculateColor(float[] f, ColorSpace colorSpace) { - int n = colorSpace.getNumComponents(); - // Get the reverse of f, and only take n values - // Might as well limit the bounds while we're at it - float[] fvalue = new float[n]; - int toCopy = n; - int fLength = f.length; - if (fLength < toCopy) { - toCopy = fLength; - } - for (int i = 0; i < toCopy; i++) { - int j = fLength - 1 - i; - float curr = f[j]; - if (curr < colorSpace.getMinValue(j)) { - curr = 0.0f; - } else if (curr > colorSpace.getMaxValue(j)) { - curr = 1.0f; - } - fvalue[i] = curr; - } - float[] frgbvalue = colorSpace.toRGB(fvalue); - return (0xFF000000) | - ((((int) (frgbvalue[0] * 255)) & 0xFF) << 16) | - ((((int) (frgbvalue[1] * 255)) & 0xFF) << 8) | - ((((int) (frgbvalue[2] * 255)) & 0xFF)); - } - - public ColorSpace getColorSpace() { - return colorSpace; - } - - /** - * Gets the number of components specified by the N entry. - * - * @return number of colour components in color space - */ - public int getNumComponents() { - return numcomp; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImagePool.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImagePool.java deleted file mode 100644 index 03b23fbd33..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImagePool.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.util.Defs; - -import java.awt.image.BufferedImage; -import java.util.Collections; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.logging.Logger; - -/** - * The Image pool is a Map of the most recently used images. The pools size - * by default is setup to be 1/4 the heap size. So as the pool grows it - * will self trim to keep the memory foot print at the specified max. The - * max pool size can be specified by using the org.icepdf.core.views.imagePoolSize - * system property. The value is specified in MB. - *

      - * The pool also contains an executor pool for processing Images. The executor - * allows the pageInitialization thread to continue while the executor processes - * the image data on another thread. - *

      - * Teh pool size can be set with the system property org.icepdf.core.views.imagePoolSize - * where the default value is 1/4 the heap size. The pool set can be specified in - * using a int value representing the desired size in MB. - *

      - * The pool can also be disabled using the boolean system property - * org.icepdf.core.views.imagePoolEnabled=false. The default state is for the - * ImagePool to be enabled. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class ImagePool { - private static final Logger log = - Logger.getLogger(ImagePool.class.toString()); - - // Image pool - private final Map fCache; - - - private static boolean enabled; - static { - // enable/disable the image pool all together. - enabled = Defs.booleanProperty("org.icepdf.core.views.imagePoolEnabled", true); - } - - - public ImagePool() { - fCache = Collections.synchronizedMap(new WeakHashMap(50)); - } - - public void put(Reference ref, BufferedImage image) { - // create a new reference so we don't have a hard link to the page - // which will likely keep a page from being GC'd. - if (enabled) { -// synchronized (fCache) { - fCache.put(new Reference(ref.getObjectNumber(), ref.getGenerationNumber()), image); -// } - } - } - - public BufferedImage get(Reference ref) { - if (enabled) { -// synchronized (fCache) { - return fCache.get(ref); -// } - } else { - return null; - } - } - - public boolean containsKey(Reference ref) { - if (enabled) { -// synchronized (fCache) { - return fCache.containsKey(ref); -// } - } else { - return false; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImageReference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImageReference.java deleted file mode 100644 index 6eda974356..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImageReference.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.events.PageImageEvent; -import org.icepdf.core.events.PageLoadingEvent; -import org.icepdf.core.events.PageLoadingListener; -import org.icepdf.core.pobjects.*; -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.FutureTask; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Abstract ImageReference defines the core methods used in ImageStreamReference - * MipMappedImageReference and ScaledImageReference. The creation of these - * objects is handled by the ImageReferenceFactory. - * - * @since 5.0 - */ -public abstract class ImageReference implements Callable { - - private static final Logger logger = - Logger.getLogger(ImageReference.class.toString()); - - protected static boolean useProxy; - - static { - // decide if large images will be scaled - useProxy = Defs.booleanProperty("org.icepdf.core.imageProxy", true); - } - - protected FutureTask futureTask; - - protected ImageStream imageStream; - protected GraphicsState graphicsState; - protected Resources resources; - protected BufferedImage image; - protected Reference reference; - - protected int imageIndex; - protected Page parentPage; - - protected ImageReference(ImageStream imageStream, GraphicsState graphicsState, - Resources resources, int imageIndex, Page parentPage) { - this.imageStream = imageStream; - this.graphicsState = graphicsState; - this.resources = resources; - this.imageIndex = imageIndex; - this.parentPage = parentPage; - } - - public abstract int getWidth(); - - public abstract int getHeight(); - - public abstract BufferedImage getImage(); - - public void drawImage(Graphics2D aG, int aX, int aY, int aW, int aH) { - BufferedImage image = getImage(); - if (image != null) { - try { - aG.drawImage(image, aX, aY, aW, aH, null); - } catch (Throwable e) { - logger.warning("There was a problem painting image, falling back to scaled instance " + - imageStream.getPObjectReference() + - "(" + imageStream.getWidth() + "x" + imageStream.getHeight() + ")"); - int width = image.getWidth(null); - Image scaledImage; - // do image scaling on larger images. This improves the softness - // of some images that contains black and white text. - if (width > 1000 && width < 2000) { - width = 1000; - } else if (width > 2000) { - width = 2000; - } - scaledImage = image.getScaledInstance( - width, -1, Image.SCALE_SMOOTH); - image.flush(); - // try drawing the scaled image one more time. - aG.drawImage(scaledImage, aX, aY, aW, aH, null); - // store the scaled image for future repaints. - this.image = ImageUtility.createBufferedImage(scaledImage); - } - } - } - - /** - * Creates a scaled image to match that of the instance vars width/height. - * - * @return decoded/encoded BufferedImage for the respective ImageStream. - */ - protected BufferedImage createImage() { - try { - // block until thread comes back. - if (futureTask != null) { - image = futureTask.get(); - } - if (image == null) { - image = call(); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Image loading interrupted"); - } catch (Exception e) { - logger.log(Level.FINE, "Image loading execution exception", e); - } - return image; - } - - public ImageStream getImageStream() { - return imageStream; - } - - public boolean isImage() { - return image != null; - } - - protected void notifyPageImageLoadedEvent(long duration, boolean interrupted) { - if (parentPage != null) { - PageImageEvent pageLoadingEvent = - new PageImageEvent(parentPage, imageIndex, - parentPage.getImageCount(), duration, interrupted); - PageLoadingListener client; - List pageLoadingListeners = - parentPage.getPageLoadingListeners(); - for (int i = pageLoadingListeners.size() - 1; i >= 0; i--) { - client = pageLoadingListeners.get(i); - client.pageImageLoaded(pageLoadingEvent); - } - } - } - - protected void notifyImagePageEvents(long duration) { - // sound out image loading event. - notifyPageImageLoadedEvent(duration, image == null); - // check to see if we're done loading and all we were waiting on was - // the completion of this image load. - if (parentPage != null && imageIndex == parentPage.getImageCount() && - parentPage.isPageInitialized() && parentPage.isPagePainted()) { - notifyPageLoadingEnded(); - } - } - - protected void notifyPageLoadingEnded() { - if (parentPage != null) { - PageLoadingEvent pageLoadingEvent = - new PageLoadingEvent(parentPage, parentPage.isInitiated()); - PageLoadingListener client; - List pageLoadingListeners = - parentPage.getPageLoadingListeners(); - for (int i = pageLoadingListeners.size() - 1; i >= 0; i--) { - client = pageLoadingListeners.get(i); - client.pageLoadingEnded(pageLoadingEvent); - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImageReferenceFactory.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImageReferenceFactory.java deleted file mode 100644 index 1ec23319f7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImageReferenceFactory.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.util.Defs; - -/** - * The ImageReferenceFactory determines which implementation of the - * Image Reference should be created. The ImageReference type can be specified - * by the following system properties or alternatively by the enum type. - *

        - *
      • org.icepdf.core.imageReference = default
      • - *
      • org.icepdf.core.imageReference = scaled
      • - *
      • org.icepdf.core.imageReference = mipmap
      • - *
      • org.icepdf.core.imageReference = smoothScaled
      • - *
      - * The default value returns an unaltered image, scaled returns a scaled - * image instance and there MIP mapped returns/picks a scaled image that - * best fits the current zoom level for a balance of render speed and quality. - * - * @see MipMappedImageReference - * @see ImageStreamReference - * @see ScaledImageReference - * @since 5.0 - */ -public class ImageReferenceFactory { - - // allow scaling of large images to improve clarity on screen - - public enum ImageReference { - DEFAULT, SCALED, MIP_MAP, SMOOTH_SCALED // FLOYD_STEINBERG - } - - private static ImageReference scaleType; - - static { - // decide if large images will be scaled - String imageReferencetype = - Defs.sysProperty("org.icepdf.core.imageReference", - "default"); - if ("scaled".equals(imageReferencetype)) { - scaleType = ImageReference.SCALED; - } else if ("mipmap".equals(imageReferencetype)) { - scaleType = ImageReference.MIP_MAP; - } else if ("smoothScaled".equals(imageReferencetype)) { - scaleType = ImageReference.SMOOTH_SCALED; - } else { - scaleType = ImageReference.DEFAULT; - } - } - - private ImageReferenceFactory() { - } - - public static ImageReference getScaleType() { - return scaleType; - } - - public static void setScaleType(ImageReference scaleType) { - ImageReferenceFactory.scaleType = scaleType; - } - - /** - * Gets an instance of an ImageReference object for the given image data. - * The ImageReference is specified by the system property org.icepdf.core.imageReference - * or by the static instance variable scale type. - * - * @param imageStream image data - * @param resources parent resource object. - * @param graphicsState image graphic state. - * @return newly create ImageReference. - */ - public static org.icepdf.core.pobjects.graphics.ImageReference - getImageReference(ImageStream imageStream, Resources resources, GraphicsState graphicsState, - Integer imageIndex, Page page) { - switch (scaleType) { - case SCALED: - return new ScaledImageReference(imageStream, graphicsState, resources, imageIndex, page); - case SMOOTH_SCALED: - return new SmoothScaledImageReference(imageStream, graphicsState, resources, imageIndex, page); - case MIP_MAP: - return new MipMappedImageReference(imageStream, graphicsState, resources, imageIndex, page); - default: - return new ImageStreamReference(imageStream, graphicsState, resources, imageIndex, page); - } - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImageStreamReference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImageStreamReference.java deleted file mode 100644 index 3ea43ea585..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ImageStreamReference.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.util.Library; - -import java.awt.image.BufferedImage; -import java.util.concurrent.FutureTask; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * The ImageStreamReference class is a rudimentary Image Proxy which will - * try and decode the image data into an Buffered image using a worker thread. - * The intent is that the content parser will continue parsing the content stream - * while the worker thread handles the image decode work. However the drawImage - * method will block until the worker thread returns. So generally put not - * a true image proxy but we do get significantly faster load times with the - * current implementation. - * - * @since 5.0 - */ -public class ImageStreamReference extends CachedImageReference { - - private static final Logger logger = - Logger.getLogger(ImageStreamReference.class.toString()); - - protected ImageStreamReference(ImageStream imageStream, GraphicsState graphicsState, - Resources resources, int imageIndex, - Page page) { - super(imageStream, graphicsState, resources, imageIndex, page); - - // kick off a new thread to load the image, if not already in pool. - ImagePool imagePool = imageStream.getLibrary().getImagePool(); - if (useProxy && imagePool.get(reference) == null) { - futureTask = new FutureTask(this); - Library.executeImage(futureTask); - } else if (!useProxy && imagePool.get(reference) == null) { - image = call(); - } - } - - @Override - public int getWidth() { - return imageStream.getWidth(); - } - - @Override - public int getHeight() { - return imageStream.getHeight(); - } - - public BufferedImage call() { - BufferedImage image = null; - long start = System.nanoTime(); - try { - image = imageStream.getImage(graphicsState, resources); - } catch (Throwable e) { - logger.log(Level.WARNING, "Error loading image: " + imageStream.getPObjectReference() + - " " + imageStream.toString(), e); - } - long end = System.nanoTime(); - notifyImagePageEvents((end - start)); - return image; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Indexed.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Indexed.java deleted file mode 100644 index 7bd143b1d0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Indexed.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; -import java.util.List; - -/** - * The class represents an indexed colour space. - */ -public class Indexed extends PColorSpace { - - public static final Name INDEXED_KEY = new Name("Indexed"); - public static final Name I_KEY = new Name("I"); - - PColorSpace colorSpace; - int hival; - byte[] colors = { - -1, -1, -1, 0, 0, 0 - }; - private boolean inited = false; - private Color[] cols; - - /** - * Constructs a new instance of the indexed colour space. Pares the indexed - * colour pattern: [/Indexed base hival lookup] where base is an array or - * name that identifies the base colour space. Hival parameter is an integer - * that specifies the maximum valid index value. Lookup is the colour table - * which must be of length m x (hival + 1) where m is the number of colour - * components in base. - * - * @param library document library. - * @param entries dictionary entries. - * @param dictionary indexed colour dictionary. - */ - Indexed(Library library, HashMap entries, List dictionary) { - super(library, entries); - // get the base colour space - colorSpace = getColorSpace(library, dictionary.get(1)); - // get the hival - hival = (((Number) (dictionary.get(2))).intValue()); - // check for an instance of a lookup table. - if (dictionary.get(3) instanceof StringObject) { - // peel and decrypt the literal string - StringObject tmpText = (StringObject) dictionary.get(3); - String tmp = tmpText.getDecryptedLiteralString(library.getSecurityManager()); - // build the colour lookup table. - byte[] textBytes = new byte[colorSpace.getNumComponents() * (hival + 1)]; // m * (hival + 1) - for (int i = 0; i < textBytes.length; i++) { - textBytes[i] = (byte) tmp.charAt(i); - } - colors = textBytes; - } else if (dictionary.get(3) instanceof Reference) { - colors = new byte[colorSpace.getNumComponents() * (hival + 1)]; - // make sure the colors array is the correct length, so we'll copy - // over the data from the stream just to be sure. - Stream lookup = (Stream) (library.getObject((Reference) (dictionary.get(3)))); - if (lookup != null) { - byte[] colorStream = lookup.getDecodedStreamBytes(0); - int length = colors.length < colorStream.length ? colors.length : colorStream.length; - System.arraycopy(colorStream, 0, colors, 0, length); - } - } - } - - /** - * Return the number of components in indexed colour. - * - * @return always returns 1. - */ - public int getNumComponents() { - return 1; - } - - public String getDescription() { - String desc = super.getDescription(); - if (colorSpace != null) - desc = desc + ":" + colorSpace.getDescription(); - return desc; - } - - /** - * Initiate the Indexed Colour Object - */ - public synchronized void init() { - if (inited) { - return; - } - int numCSComps = colorSpace.getNumComponents(); - int b1[] = new int[numCSComps]; - float f1[] = new float[numCSComps]; - cols = new Color[hival + 1]; - for (int j = 0; j <= hival; j++) { - for (int i = 0; i < numCSComps; i++) { - b1[numCSComps - 1 - i] = 0xFF & ((int) colors[j * numCSComps + i]); - } - colorSpace.normaliseComponentsToFloats(b1, f1, 255.0f); - cols[j] = colorSpace.getColor(f1, true); - } - inited = true; - } - - /** - * Gets the colour for the array of float values - * - * @param f - * @return - */ - public Color getColor(float[] f, boolean fillAndStroke) { - init(); - int index = (int) f[0];//(int) (f[0] * (cols.length - 1)); - if (index >= 0 && index <= hival) { - return cols[index]; - } else if (index > hival) { - return cols[hival]; - } else { - return cols[0]; - } - - } - - public Color[] accessColorTable() { - return cols; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/InlineImageStreamReference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/InlineImageStreamReference.java deleted file mode 100644 index 42bc1b8095..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/InlineImageStreamReference.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.util.Library; - -import java.awt.image.BufferedImage; -import java.util.concurrent.FutureTask; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Represents one inline images as define in a content stream. Inline images - * don't have object numbers and thus can't be cached. - * - * @since 5.0 - */ -public class InlineImageStreamReference extends ImageReference { - - private static final Logger logger = - Logger.getLogger(InlineImageStreamReference.class.toString()); - - public InlineImageStreamReference(ImageStream imageStream, GraphicsState graphicsState, - Resources resources, int iamgeIndex, - Page page) { - super(imageStream, graphicsState, resources, iamgeIndex, page); - - // kick off a new thread to load the image, if not already in pool. - ImagePool imagePool = imageStream.getLibrary().getImagePool(); - if (useProxy && imagePool.get(reference) == null) { - futureTask = new FutureTask(this); - Library.executeImage(futureTask); - } else if (!useProxy && imagePool.get(reference) == null) { - image = call(); - } - } - - @Override - public int getWidth() { - return imageStream.getWidth(); - } - - @Override - public int getHeight() { - return imageStream.getHeight(); - } - - @Override - public BufferedImage getImage() { - if (image == null && useProxy) { - image = createImage(); - } else { - image = call(); - } - return image; - } - - public BufferedImage call() { - BufferedImage image = null; - long start = System.nanoTime(); - try { - image = imageStream.getImage(graphicsState, resources); - } catch (Throwable e) { - logger.log(Level.WARNING, "Error loading image: " + imageStream.getPObjectReference() + - " " + imageStream.toString(), e); - } - long end = System.nanoTime(); - notifyImagePageEvents((end - start)); - return image; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Lab.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Lab.java deleted file mode 100644 index 7a70478e42..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Lab.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; -import java.util.List; - -/** - * put your documentation comment here - */ -public class Lab extends PColorSpace { - - public static final Name LAB_KEY = new Name("Lab"); - public static final Name WHITE_POINT_KEY = new Name("WhitePoint"); - public static final Name RANGE_KEY = new Name("Range"); - - private float[] whitePoint = { - 0.95047f, 1.0f, 1.08883f - }; - private float[] blackPoint = { - 0f, 0f, 0f - }; - private float[] range = { - -100, 100, -100, 100 - }; - private float lBase; - private float lSpread; - private float aBase; - private float aSpread; - private float bBase; - private float bSpread; - - private float xBase; - private float xSpread; - private float yBase; - private float ySpread; - private float zBase; - private float zSpread; - - /** - * @param l - * @param h - */ - Lab(Library l, HashMap h) { - super(l, h); - List v = (java.util.List) l.getObject(h, WHITE_POINT_KEY); - if (v != null) { - whitePoint[0] = ((Number) v.get(0)).floatValue(); - whitePoint[1] = ((Number) v.get(1)).floatValue(); - whitePoint[2] = ((Number) v.get(2)).floatValue(); - } - v = (List) l.getObject(h, RANGE_KEY); - if (v != null) { - range[0] = ((Number) v.get(0)).floatValue(); - range[1] = ((Number) v.get(1)).floatValue(); - range[2] = ((Number) v.get(2)).floatValue(); - range[3] = ((Number) v.get(3)).floatValue(); - } - - lBase = 0.0f; - lSpread = 100.0f; - aBase = range[0]; - aSpread = range[1] - aBase; - bBase = range[2]; - bSpread = range[3] - bBase; - - xBase = blackPoint[0]; - xSpread = whitePoint[0] - xBase; - yBase = blackPoint[1]; - ySpread = whitePoint[1] - yBase; - zBase = blackPoint[2]; - zSpread = whitePoint[2] - zBase; - } - - /** - * @return - */ - public int getNumComponents() { - return 3; - } - - /** - * @param x - * @return - */ - private double g(double x) { - if (x < 0.2069F) - x = 0.12842 * (x - 0.13793); - else - x = x * x * x; - return x; - } - - private double gg(double r) { - if (r > 0.0031308) - r = 1.055 * Math.pow(r, (1.0 / 2.4)) - 0.055; - else - r *= 12.92; - return r; - } - - public void normaliseComponentsToFloats(int[] in, float[] out, float maxval) { - super.normaliseComponentsToFloats(in, out, maxval); - out[2] = lBase + (lSpread * out[2]); // L - out[1] = aBase + (aSpread * out[1]); // a - out[0] = bBase + (bSpread * out[0]); // b - } - - /** - * @param f - * @return - */ - public Color getColor(float[] f, boolean fillAndStroke) { - double cie_b = f[0]; - double cie_a = f[1]; - double cie_L = f[2]; - - double var_Y = (cie_L + 16.0) / (116.0); - double var_X = var_Y + (cie_a * 0.002); - double var_Z = var_Y - (cie_b * 0.005); - double X = g(var_X); - double Y = g(var_Y); - double Z = g(var_Z); - X = xBase + X * xSpread; - Y = yBase + Y * ySpread; - Z = zBase + Z * zSpread; - X = Math.max(0, Math.min(1, X)); - Y = Math.max(0, Math.min(1, Y)); - Z = Math.max(0, Math.min(1, Z)); - - /* - * Algorithm from online - double r = X * 3.2406 + Y * -1.5372 + Z * -0.4986; - double g = X * -0.9689 + Y * 1.8758 + Z * 0.0415; - double b = X * 0.0557 + Y * -0.2040 + Z * 1.0570; - */ - double r = X * 3.241 + Y * -1.5374 + Z * -0.4986; - double g = X * -0.9692 + Y * 1.876 + Z * 0.0416; - double b = X * 0.0556 + Y * -0.204 + Z * 1.057; - r = gg(r); - g = gg(g); - b = gg(b); - int ir = (int) (r * 255.0); - int ig = (int) (g * 255.0); - int ib = (int) (b * 255.0); - ir = Math.max(0, Math.min(255, ir)); - ig = Math.max(0, Math.min(255, ig)); - ib = Math.max(0, Math.min(255, ib)); - return new Color(ir, ig, ib); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/MipMappedImageReference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/MipMappedImageReference.java deleted file mode 100644 index a3183207db..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/MipMappedImageReference.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.Resources; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.image.BufferedImage; -import java.util.ArrayList; - -/** - * The MipMappedImageReference will create several scaled instance of the - * specified image. The images are all smaller then the original image and - * are painted as the page zoom level is lowered. The main idea here is that small - * images are painted at smaller zoom levels which in theory speeds up the image - * paint time. - * - * @since 5.0 - */ -class MipMappedImageReference extends ImageReference { - - private ArrayList images; - - protected MipMappedImageReference(ImageStream imageStream, GraphicsState graphicsState, - Resources resources, int imageIndex, - Page page) { - - super(imageStream, graphicsState, resources, imageIndex, page); - - images = new ArrayList(); - - ImageReference imageReference = - new ImageStreamReference(imageStream, graphicsState, resources, imageIndex, page); - images.add(imageReference); - - int width = imageReference.getWidth(); - int height = imageReference.getHeight(); - // disable proxy as we need to scale each image from the previous - // and thus need to do the downscale in one shot. - useProxy = false; - while (width > 20 && height > 20) { - width /= 2; - height /= 2; - imageReference = new ScaledImageReference(imageReference, graphicsState, resources, - width, height, imageIndex, page); - images.add(imageReference); - } - } - - public int getWidth() { - return images.get(0).getWidth(); - } - - public int getHeight() { - return images.get(0).getHeight(); - } - - public BufferedImage getImage() { - return images.get(0).getImage(); - } - - public void drawImage(Graphics2D aG, int aX, int aY, int aW, int aH) { - ImageReference imageReference = chooseImage(aG, aX, aY, aW, aH); - imageReference.drawImage(aG, aX, aY, aW, aH); - } - - private ImageReference chooseImage(Graphics2D aG, int aX, int aY, int aW, int aH) { - Point2D.Double in = new Point2D.Double(aX, aY); - Point2D.Double p1 = new Point2D.Double(); - Point2D.Double p2 = new Point2D.Double(); - aG.getTransform().transform(in, p1); - in.x = aW; - aG.getTransform().transform(in, p2); - int distSq1 = (int) Math.round(p1.distanceSq(p2)); - in.x = aX; - in.y = aH; - aG.getTransform().transform(in, p2); - int distSq2 = (int) Math.round(p1.distanceSq(p2)); - int maxDistSq = Math.max(distSq1, distSq2); - - int level = 0; - ImageReference image = images.get(level); - int width = image.getWidth(); - int height = image.getHeight(); - - while (level < (images.size() - 1) && - (width * width / 4) > maxDistSq && - (height * height / 4) > maxDistSq) { - image = images.get(level++); - width = image.getWidth(); - height = image.getHeight(); - } - return image; - } - - // no need to implement as this class class calls ScaledImage and MipMapped - // as needed. - public BufferedImage call() { - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/OptionalContentState.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/OptionalContentState.java deleted file mode 100644 index fd75d37bf0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/OptionalContentState.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.OptionalContents; - -import java.util.LinkedList; - -/** - * OptionalContentState stores the state of the currently in play OptionalContent - * if specified. If now optional content is present then this class will simply - * return true when isVisible() is called. This class handles embedded - * optionalContentState correctly. - * - * @since 5.0 - */ -public class OptionalContentState { - - private LinkedList optionContents = new LinkedList(); - - private boolean isEmpty = true; - - public void add(OptionalContents optionContent) { - optionContents.add(optionContent); - isEmpty = false; - } - - public void remove() { - optionContents.removeLast(); - isEmpty = optionContents.isEmpty(); - } - - public boolean isVisible() { - return isEmpty || optionContents.getLast().isVisible(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/PColorSpace.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/PColorSpace.java deleted file mode 100644 index 5ad3387704..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/PColorSpace.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * put your documentation comment here - */ -public abstract class PColorSpace extends Dictionary { - - private static final Logger logger = - Logger.getLogger(PColorSpace.class.toString()); - - /** - * @return - */ - public abstract int getNumComponents(); - - - public String getDescription() { - String name = getClass().getName(); - int index = name.lastIndexOf('.'); - return name.substring(index + 1); - } - - /** - * @param l - * @param h - */ - PColorSpace(Library l, HashMap h) { - super(l, h); - } - - /** - * @param library - * @param o - * @return - */ - public static PColorSpace getColorSpace(Library library, Object o) { - if (o != null) { - PColorSpace colorSpace = null; - Reference ref = null; - if (o instanceof Reference) { - ref = (Reference) o; - o = library.getObject(ref); - } - - if (o instanceof PColorSpace) { - colorSpace = (PColorSpace) o; - } else if (o instanceof Name) { - if (o.equals(DeviceGray.DEVICEGRAY_KEY) || - o.equals(DeviceGray.G_KEY)) { - colorSpace = new DeviceGray(library, null); - } else if (o.equals(DeviceRGB.DEVICERGB_KEY) || - o.equals(DeviceRGB.RGB_KEY)) { - colorSpace = new DeviceRGB(library, null); - } else if (o.equals(DeviceCMYK.DEVICECMYK_KEY) || - o.equals(DeviceCMYK.CMYK_KEY)) { - colorSpace = new DeviceCMYK(library, null); - } else if (o.equals(PatternColor.PATTERN_KEY)) { - colorSpace = new PatternColor(library, null); - } - } else if (o instanceof List) { - List v = (List) o; - Name colorant = (Name) v.get(0); - if (colorant.equals(Indexed.INDEXED_KEY) - || colorant.equals(Indexed.I_KEY)) { - colorSpace = new Indexed(library, null, v); - } else if (colorant.equals(CalRGB.CALRGB_KEY)) { - colorSpace = new CalRGB(library, getHashMap(library, v.get(1))); - } else if (colorant.equals(CalGray.CAL_GRAY_KEY)) { - colorSpace = new CalGray(library, getHashMap(library, v.get(1))); - } else if (colorant.equals(Lab.LAB_KEY)) { - colorSpace = new Lab(library, getHashMap(library, v.get(1))); - } else if (colorant.equals(Separation.SEPARATION_KEY)) { - colorSpace = new Separation( - library, - null, - v.get(1), - v.get(2), - v.get(3)); - } else if (colorant.equals(DeviceN.DEVICEN_KEY)) { - colorSpace = new DeviceN( - library, - null, - v.get(1), - v.get(2), - v.get(3), - v.size() > 4 ? v.get(4) : null); - } else if (colorant.equals(ICCBased.ICCBASED_KEY)) { - /*Stream st = (Stream)library.getObject((Reference)v.elementAt(1)); - return PColorSpace.getColorSpace(library, library.getObject(st.getEntries(), - "Alternate"));*/ - colorSpace = library.getICCBased((Reference) v.get(1)); - } else if (colorant.equals(DeviceRGB.DEVICERGB_KEY)) { - colorSpace = new DeviceRGB(library, null); - } else if (colorant.equals(DeviceCMYK.DEVICECMYK_KEY)) { - colorSpace = new DeviceCMYK(library, null); - } else if (colorant.equals(DeviceGray.DEVICEGRAY_KEY)) { - colorSpace = new DeviceGray(library, null); - } else if (colorant.equals(PatternColor.PATTERN_KEY)) { - PatternColor patternColour = new PatternColor(library, null); - if (v.size() > 1) { - Object tmp = v.get(1); - if (tmp instanceof Reference) { - tmp = library.getObject((Reference) v.get(1)); - if (tmp instanceof PColorSpace) { - patternColour.setPColorSpace((PColorSpace) tmp); - } else if (tmp instanceof HashMap) { - patternColour.setPColorSpace( - getColorSpace(library, tmp)); - } - } else { - patternColour.setPColorSpace( - getColorSpace(library, - getHashMap(library, v.get(1)))); - } - - } - colorSpace = patternColour; - } - } else if (o instanceof HashMap) { - colorSpace = new PatternColor(library, (HashMap) o); - } - if (colorSpace == null && logger.isLoggable(Level.FINE)) { - logger.fine("Unsupported ColorSpace: " + o); - } - // cache the space proper. - if (ref != null && colorSpace != null) { - library.addObject(colorSpace, ref); - } - if (colorSpace != null) { - return colorSpace; - } - } - return new DeviceGray(library, null); - } - - /** - * Utility to get a valid hash map for the provided Object or Reference. - * - * @param obj object or Reference from color dictionary. - * @return a dictionary or null if the object is not of type Reference or - * HashMap. - */ - private static HashMap getHashMap(Library library, Object obj) { - HashMap entries = null; - if (obj instanceof HashMap) { - entries = (HashMap) obj; - } else if (obj instanceof Reference) { - obj = library.getObject((Reference) obj); - if (obj instanceof HashMap) { - entries = (HashMap) obj; - } - } - return entries; - } - - /** - * Gets the color space for the given n value. If n == 3 then the new color - * space with be RGB, if n == 4 then CMYK and finally if n == 1 then - * Gray. - * - * @param library hash of all library objects - * @param n number of colours in colour space - * @return a new PColorSpace given the value of n - */ - public synchronized static PColorSpace getColorSpace(Library library, float n) { - if (n == 3) { - return new DeviceRGB(library, null); - } else if (n == 4) { - return new DeviceCMYK(library, null); - } else { - return new DeviceGray(library, null); - } - } - - /** - * Gets the colour in RGB represented by the array of colour components - * - * @param components array of component colour data - * @return new RGB colour composed from the components array. - */ - public Color getColor(float[] components) { - return getColor(components, false); - } - - public abstract Color getColor(float[] components, boolean fillAndStroke); - - public void normaliseComponentsToFloats(int[] in, float[] out, float maxval) { - int count = getNumComponents(); - for (int i = 0; i < count; i++) - out[i] = (((float) in[i]) / maxval); - } - - /** - * @param f - * @return - */ - public static float[] reverse(float f[]) { - float n[] = new float[f.length]; - //System.out.print("R "); - for (int i = 0; i < f.length; i++) { - n[i] = f[f.length - i - 1]; - //System.out.print( n[i] + ","); - } - //System.out.println(); - return n; - } - - public static void reverseInPlace(float[] f) { - int num = f.length / 2; - for (int i = 0; i < num; i++) { - float tmp = f[i]; - f[i] = f[f.length - 1 - i]; - f[f.length - 1 - i] = tmp; - } - } - - public static void reverseInPlace(int[] f) { - int num = f.length / 2; - for (int i = 0; i < num; i++) { - int tmp = f[i]; - f[i] = f[f.length - 1 - i]; - f[f.length - 1 - i] = tmp; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/PaintTimer.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/PaintTimer.java deleted file mode 100644 index 53e9cc8c45..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/PaintTimer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.util.Defs; - -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * PaintTimer encapsulates the time calculation used to fire repaint events - * to the view. - * - * @since 5.0 - */ -public class PaintTimer { - - protected static final Logger logger = - Logger.getLogger(PaintTimer.class.toString()); - - protected static int paintDelay; - - static { - try { - // Delay between painting calls. - paintDelay = - Defs.intProperty("org.icepdf.core.views.refreshfrequency", - 250); - } catch (NumberFormatException e) { - logger.log(Level.FINE, "Error reading buffered scale factor"); - } - } - - private long lastPaintTime; - - public boolean shouldTriggerRepaint() { - long currentTime = System.currentTimeMillis(); - if (currentTime - lastPaintTime > paintDelay) { - lastPaintTime = currentTime; - return true; - } else { - return false; - } - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Pattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Pattern.java deleted file mode 100644 index dd37605d2e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Pattern.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - - -import org.icepdf.core.pobjects.Name; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; - - -/** - *

      Patterns come in two varieties:

      - *
        - *
      • Tiling patterns consist of a small graphical figure (called a - * pattern cell) that is replicated at fixed horizontal and vertical - * intervals to fill the area to be painted. The graphics objects to - * use for tiling are described by a content stream. (PDF 1.2)

      • - *

        - *

      • Shading patterns define a gradient fill that produces a smooth - * transition between colors across the area. The color to use is - * specified as a function of position using any of a variety of - * methods. (PDF 1.3)

      • - *
      - *

      Note Tiling pattern and shading patterns are not currently supported

      - * - * @since 1.0 - */ -public interface Pattern { - - /** - * The pattern type is a tiling pattern - */ - public static final int PATTERN_TYPE_TILING = 1; - - /** - * The pattern type is a shading pattern - */ - public static final int PATTERN_TYPE_SHADING = 2; - - public static final Name TYPE_VALUE = new Name("pattern"); - - public Name getType(); - - public int getPatternType(); - - public AffineTransform getMatrix(); - - public void setMatrix(AffineTransform matrix); - - public Rectangle2D getBBox(); - - void init(GraphicsState graphicsState); - - public Paint getPaint() throws InterruptedException; - - public void setParentGraphicState(GraphicsState graphicsState); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/PatternColor.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/PatternColor.java deleted file mode 100644 index 2f534d59b6..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/PatternColor.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; - -/** - *

      Pattern colour implements PColorSpace but is more of a parser placeholder - * for dealing with 'cs' token which sets a pattern Colour space. The pattern - * color space can either define a Pattern dictionary which contains valid - * pattern object which are then specified by the 'scn' or 'SCN' tokens. The - * pattern can also define straight up color space rgb, gray, N etc.

      - *

      If the PatternColor contains dictionary of Pattern Object from the - * pages resources then this object is created with the corrisponding - * dictionary reference.

      - * - * @since 1.0 - */ -public class PatternColor extends PColorSpace { - - public static final Name PATTERN_KEY = new Name("Pattern"); - - private Pattern pattern; - - private PColorSpace PColorSpace; - - /** - * Creates a new instance of PatternColor. - * - * @param library document library. - * @param entries dictionary entries. - */ - public PatternColor(Library library, HashMap entries) { - super(library, entries); - } - - /** - * Not applicable to a Pattern Colour space. - * - * @return value of zero - */ - public int getNumComponents() { - if (PColorSpace != null) { - return PColorSpace.getNumComponents(); - } - return 0; - } - - /** - * Not applicable to a Pattern Colour space. - * - * @param f any value. - * @return always returns null. - */ - public Color getColor(float[] f, boolean fillAndStroke) { - if (PColorSpace != null) { - return PColorSpace.getColor(f); - } - return Color.black; - } - - public Pattern getPattern(Reference reference) { - if (entries != null) { - return (Pattern) entries.get(reference); - } - return null; - } - - public PColorSpace getPColorSpace() { - return PColorSpace; - } - - public void setPColorSpace(PColorSpace PColorSpace) { - this.PColorSpace = PColorSpace; - } - - public Pattern getPattern() { - return pattern; - } - - public void setPattern(Pattern pattern) { - this.pattern = pattern; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/CMYKRasterOp.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/CMYKRasterOp.java deleted file mode 100644 index ee6972592a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/CMYKRasterOp.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.icepdf.core.pobjects.graphics.RasterOps; - -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.*; - -/** - * Raster operation for converting a CMYK colour to RGB using an a rough - * algorithm which generally results in images that are darker then they should - * be. The black value can be configured using the system property - * -Dorg.icepdf.core.cmyk.image.black=255. - *

      - * This colour conversion method should only be used if its not desirable to - * use the more accurate ICC Color Profile for colour conversion. - * - * @since 5.1 - */ -public class CMYKRasterOp implements RasterOp { - - // default cmyk value, > 255 will lighten the image. - private static float blackRatio; - private RenderingHints hints = null; - - public CMYKRasterOp(RenderingHints hints) { - this.hints = hints; - blackRatio = Defs.intProperty("org.icepdf.core.cmyk.image.black", 255); - } - - public static void setBlackRatio(float blackRatio) { - CMYKRasterOp.blackRatio = blackRatio; - } - - public WritableRaster filter(Raster src, WritableRaster dest) { - - if (dest == null) dest = src.createCompatibleWritableRaster(); - - // may have to add some instance of checks - byte[] srcPixels = ((DataBufferByte) src.getDataBuffer()).getData(); - int[] destPixels = ((DataBufferInt) dest.getDataBuffer()).getData(); - - // this convoluted cymk->rgba method is from DeviceCMYK class. - float inCyan, inMagenta, inYellow, inBlack; - float lastCyan = -1, lastMagenta = -1, lastYellow = -1, lastBlack = -1; - double c, m, y2, aw, ac, am, ay, ar, ag, ab; - float outRed, outGreen, outBlue; - int rValue = 0, gValue = 0, bValue = 0, alpha = 0; - - int bands = src.getNumBands(); - for (int pixel = 0, intPixels = 0; pixel < srcPixels.length; pixel += bands, intPixels++) { - - inCyan = (srcPixels[pixel] & 0xff) / 255.0f; - inMagenta = (srcPixels[pixel + 1] & 0xff) / 255.0f; - inYellow = (srcPixels[pixel + 2] & 0xff) / 255.0f; - // lessen the amount of black, standard 255 fraction is too dark - // increasing the denominator has the same affect of lighting up - // the image. - inBlack = (srcPixels[pixel + 3] & 0xff) / blackRatio; - - if (!(inCyan == lastCyan && inMagenta == lastMagenta && - inYellow == lastYellow && inBlack == lastBlack)) { - - c = clip(0, 1, inCyan + inBlack); - m = clip(0, 1, inMagenta + inBlack); - y2 = clip(0, 1, inYellow + inBlack); - aw = (1 - c) * (1 - m) * (1 - y2); - ac = c * (1 - m) * (1 - y2); - am = (1 - c) * m * (1 - y2); - ay = (1 - c) * (1 - m) * y2; - ar = (1 - c) * m * y2; - ag = c * (1 - m) * y2; - ab = c * m * (1 - y2); - - outRed = (float) clip(0, 1, aw + 0.9137 * am + 0.9961 * ay + 0.9882 * ar); - outGreen = (float) clip(0, 1, aw + 0.6196 * ac + ay + 0.5176 * ag); - outBlue = (float) clip(0, 1, aw + 0.7804 * ac + 0.5412 * am + 0.0667 * ar + 0.2118 * ag + 0.4863 * ab); - rValue = (int) (outRed * 255); - gValue = (int) (outGreen * 255); - bValue = (int) (outBlue * 255); - alpha = 0xFF; - } - lastCyan = inCyan; - lastMagenta = inMagenta; - lastYellow = inYellow; - lastBlack = inBlack; - - destPixels[intPixels] = ((alpha & 0xff) << 24) | - ((rValue & 0xff) << 16) | ((gValue & 0xff) << 8) | - (bValue & 0xff); - } - return dest; - } - - public Rectangle2D getBounds2D(Raster src) { - return null; - } - - public WritableRaster createCompatibleDestRaster(Raster src) { - return src.createCompatibleWritableRaster(); - } - - public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { - if (dstPt == null) - dstPt = (Point2D) srcPt.clone(); - else - dstPt.setLocation(srcPt); - return dstPt; - } - - public RenderingHints getRenderingHints() { - return hints; - } - - /** - * Clips the value according to the specified floor and ceiling. - * - * @param floor floor value of clip - * @param ceiling ceiling value of clip - * @param value value to clip. - * @return clipped value. - */ - private static double clip(double floor, double ceiling, double value) { - if (value < floor) { - value = floor; - } - if (value > ceiling) { - value = ceiling; - } - return value; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/DecodeRasterOp.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/DecodeRasterOp.java deleted file mode 100644 index 0252782b15..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/DecodeRasterOp.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.icepdf.core.pobjects.graphics.RasterOps; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.DataBufferByte; -import java.awt.image.Raster; -import java.awt.image.RasterOp; -import java.awt.image.WritableRaster; - -/** - * Applies the decode value array tot he specified raster. The decode array - * is specific to PDF and describes how to map image samples into the range of - * values appropriate for the image’s colour space. - *

      - * This Raster Operation should be applied to any image type before colour - * conversion takes place. - * - * @since 5.1 - */ -public class DecodeRasterOp implements RasterOp { - - private static final float NORMAL_DECODE_CEIL = 1.0f / 255; - - private RenderingHints hints = null; - private float[] decode; - - public DecodeRasterOp(float[] decode, RenderingHints hints) { - this.hints = hints; - this.decode = decode; - } - - /** - * Simple test to see if the decode is none standard where standard is - * [0,1,0,1,0,1]. - * - * @param decode decode array to check - * @return true if the decode is not normal, otherwise false. - */ - private static boolean isNormalDecode(float[] decode) { - // normal decode is always [0,1,0,1....] - for (int i = 0, max = decode.length; i < max; i += 2) { - if (decode[i] != 0.0f || decode[i + 1] != NORMAL_DECODE_CEIL) { - return false; - } - } - return true; - } - - public WritableRaster filter(Raster src, WritableRaster dest) { - - // check if we have none 0-1 decode, if so continue if not return - if (isNormalDecode(decode)) { - return (WritableRaster) src; - } - - if (dest == null) dest = src.createCompatibleWritableRaster(); - - // may have to add some instance of checks - byte[] srcPixels = ((DataBufferByte) src.getDataBuffer()).getData(); - byte[] destPixels = ((DataBufferByte) dest.getDataBuffer()).getData(); - - int bands = src.getNumBands(); - for (int pixel = 0; pixel < srcPixels.length; pixel += bands) { - // apply decode param. - for (int i = 0; i < bands; i++) { - destPixels[pixel + i] = normalizeComponents(srcPixels[pixel + i], decode, i); - } - } - return dest; - } - - public Rectangle2D getBounds2D(Raster src) { - return null; - } - - public WritableRaster createCompatibleDestRaster(Raster src) { - return src.createCompatibleWritableRaster(); - } - - public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { - if (dstPt == null) - dstPt = (Point2D) srcPt.clone(); - else - dstPt.setLocation(srcPt); - return dstPt; - } - - public RenderingHints getRenderingHints() { - return hints; - } - - /** - * Apply the Decode Array domain for each colour component. Assumes output - * range is 0-255 for each value in out. - * - * @param pixels colour to process by decode - * @param decode decode array for colour space - * @return decoded value.. - */ - private static byte normalizeComponents( - byte pixels, - float[] decode, - int i) { - // interpolate each colour component for the given decode domain. - return (byte) ((decode[i * 2] * 255) + (pixels & 0xff) * (decode[(i * 2) + 1] * 255)); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/GrayRasterOp.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/GrayRasterOp.java deleted file mode 100644 index e87bcda349..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/GrayRasterOp.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.icepdf.core.pobjects.graphics.RasterOps; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.DataBufferByte; -import java.awt.image.Raster; -import java.awt.image.RasterOp; -import java.awt.image.WritableRaster; - -/** - * Applies an algorithm to convert the Gray colour space to RGB. - * - * @since 5.1 - */ -public class GrayRasterOp implements RasterOp { - private RenderingHints hints = null; - private float[] decode; - - public GrayRasterOp(float[] decode, RenderingHints hints) { - this.hints = hints; - this.decode = decode; - } - - - public WritableRaster filter(Raster src, WritableRaster dest) { - - if (dest == null) dest = src.createCompatibleWritableRaster(); - - // may have to add some instance of checks - byte[] srcPixels = ((DataBufferByte) src.getDataBuffer()).getData(); - byte[] destPixels = ((DataBufferByte) dest.getDataBuffer()).getData(); - boolean defaultDecode = 0.0f == decode[0]; - - int Y; - int bands = src.getNumBands(); - for (int pixel = 0; pixel < srcPixels.length; pixel += bands) { - Y = srcPixels[pixel] & 0xff; - Y = defaultDecode ? 255 - Y : Y; - Y = (Y < 0) ? (byte) 0 : (Y > 255) ? (byte) 0xFF : (byte) Y; - destPixels[pixel] = (byte) Y; - } - return dest; - } - - public Rectangle2D getBounds2D(Raster src) { - return null; - } - - public WritableRaster createCompatibleDestRaster(Raster src) { - return src.createCompatibleWritableRaster(); - } - - public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { - if (dstPt == null) - dstPt = (Point2D) srcPt.clone(); - else - dstPt.setLocation(srcPt); - return dstPt; - } - - public RenderingHints getRenderingHints() { - return hints; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/PColorSpaceRasterOp.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/PColorSpaceRasterOp.java deleted file mode 100644 index 7fb39c8d66..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/PColorSpaceRasterOp.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.icepdf.core.pobjects.graphics.RasterOps; - -import org.icepdf.core.pobjects.graphics.DeviceRGB; -import org.icepdf.core.pobjects.graphics.PColorSpace; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.*; - -/** - * Convert a rgb encoded raster to the specified colour space. - * - * @since 5.1 - */ -public class PColorSpaceRasterOp implements RasterOp { - - private RenderingHints hints = null; - private PColorSpace colorSpace; - - public PColorSpaceRasterOp(PColorSpace colorSpace, RenderingHints hints) { - this.hints = hints; - this.colorSpace = colorSpace; - } - - public WritableRaster filter(Raster src, WritableRaster dest) { - - if (dest == null) dest = src.createCompatibleWritableRaster(); - - // may have to add some instance of checks - byte[] srcPixels = ((DataBufferByte) src.getDataBuffer()).getData(); - int[] destPixels = ((DataBufferInt) dest.getDataBuffer()).getData(); - - // already RGB not much to do so we just build the colour - if (colorSpace instanceof DeviceRGB) { - int bands = src.getNumBands(); - int[] rgbValues = new int[3]; - for (int pixel = 0, intPixels = 0; pixel < srcPixels.length; pixel += bands, intPixels++) { - - rgbValues[0] = (srcPixels[pixel] & 0xff); - rgbValues[1] = (srcPixels[pixel + 1] & 0xff); - rgbValues[2] = (srcPixels[pixel + 2] & 0xff); - - // reverse after the normalization to avoid looking gray data as - // array is trimmed above. - destPixels[intPixels] = ((rgbValues[0] & 0xff) << 16) | - ((rgbValues[1] & 0xff) << 8) | - (rgbValues[2] & 0xff); - } - } else { - int bands = src.getNumBands(); - float[] values = new float[3]; - for (int pixel = 0, intPixels = 0; pixel < srcPixels.length; pixel += bands, intPixels++) { - - for (int i = 0; i < bands; i++) { - values[i] = (srcPixels[pixel + i] & 0xff) / 255.0f; - } - // color space caching should help with the number of colors - // objects created. - PColorSpace.reverseInPlace(values); - destPixels[intPixels] = colorSpace.getColor(values).getRGB(); - } - } - - return dest; - } - - public Rectangle2D getBounds2D(Raster src) { - return null; - } - - public WritableRaster createCompatibleDestRaster(Raster src) { - return src.createCompatibleWritableRaster(); - } - - public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { - if (dstPt == null) { - dstPt = (Point2D) srcPt.clone(); - } else { - dstPt.setLocation(srcPt); - } - return dstPt; - } - - public RenderingHints getRenderingHints() { - return hints; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/YCCKRasterOp.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/YCCKRasterOp.java deleted file mode 100644 index 3292976acb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/YCCKRasterOp.java +++ /dev/null @@ -1,223 +0,0 @@ -package org.icepdf.core.pobjects.graphics.RasterOps; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.DataBufferByte; -import java.awt.image.Raster; -import java.awt.image.RasterOp; -import java.awt.image.WritableRaster; - -/** - * The basic idea is that we do a fuzzy colour conversion from YCCK to - * CMYK. The conversion is not perfect but when converted again from - * CMYK to RGB the result is much better then going directly from YCCK to - * RGB. - * NOTE: no masking here, as it is done later in the call to - * {@see alterRasterCMYK2BGRA} - * - * @sine 5.1 - */ -public class YCCKRasterOp implements RasterOp { - - private RenderingHints hints = null; - - public YCCKRasterOp(RenderingHints hints) { - this.hints = hints; - } - - public WritableRaster filter(Raster src, WritableRaster dest) { - - if (dest == null) dest = src.createCompatibleWritableRaster(); - - // may have to add some instance of checks - byte[] srcPixels = ((DataBufferByte) src.getDataBuffer()).getData(); - byte[] destPixels = ((DataBufferByte) dest.getDataBuffer()).getData(); - - double Y, Cb, Cr, K; - double lastY = -1, lastCb = -1, lastCr = -1, lastK = -1; - int c = 0, m = 0, y2 = 0, k = 0; - - int bands = src.getNumBands(); - for (int pixel = 0; pixel < srcPixels.length; pixel += bands) { - - Y = (srcPixels[pixel] & 0xff); - Cb = (srcPixels[pixel + 1] & 0xff); - Cr = (srcPixels[pixel + 2] & 0xff); - K = (srcPixels[pixel + 3] & 0xff); - - if (!(lastY == Y && lastCb == Cb && lastCr == Cr && lastK == K)) { - - // intel codecs, http://software.intel.com/sites/products/documentation/hpc/ipp/ippi/ippi_ch6/ch6_color_models.html - // Intel IPP conversion for JPEG codec. - c = 255 - (int) (Y + (1.402 * Cr) - 179.456); - m = 255 - (int) (Y - (0.34414 * Cb) - (0.71413636 * Cr) + 135.45984); - y2 = 255 - (int) (Y + (1.7718 * Cb) - 226.816); - k = (int) K; - - c = clip(0, 255, c); - m = clip(0, 255, m); - y2 = clip(0, 255, y2); - } - - lastY = Y; - lastCb = Cb; - lastCr = Cr; - lastK = K; - destPixels[pixel] = (byte) (c & 0xff); - destPixels[pixel + 1] = (byte) (m & 0xff); - destPixels[pixel + 2] = (byte) (y2 & 0xff); - destPixels[pixel + 3] = (byte) (k & 0xff); - } - return dest; - } - - public Rectangle2D getBounds2D(Raster src) { - return null; - } - - public WritableRaster createCompatibleDestRaster(Raster src) { - return src.createCompatibleWritableRaster(); - } - - public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { - if (dstPt == null) - dstPt = (Point2D) srcPt.clone(); - else - dstPt.setLocation(srcPt); - return dstPt; - } - - public RenderingHints getRenderingHints() { - return hints; - } - - /** - * Clips the value according to the specified floor and ceiling. - * - * @param floor floor value of clip - * @param ceiling ceiling value of clip - * @param value value to clip. - * @return clipped value. - */ - private static int clip(int floor, int ceiling, int value) { - if (value < floor) { - value = floor; - } - if (value > ceiling) { - value = ceiling; - } - return value; - } - - /* - // older method for conversion, keeping for historical context. - - protected static void alterRasterYCCK2BGRA(WritableRaster wr, - BufferedImage smaskImage, - BufferedImage maskImage, - float[] decode, - int bitsPerComponent) { - Raster smaskRaster = null; - int smaskWidth = 0; - int smaskHeight = 0; - if (smaskImage != null) { - smaskRaster = smaskImage.getRaster(); - smaskWidth = smaskRaster.getWidth(); - smaskHeight = smaskRaster.getHeight(); - } - - Raster maskRaster = null; - int maskWidth = 0; - int maskHeight = 0; - if (maskImage != null) { - maskRaster = maskImage.getRaster(); - maskWidth = maskRaster.getWidth(); - maskHeight = maskRaster.getHeight(); - } - - byte[] dataValues = new byte[wr.getNumBands()]; - float[] origValues = new float[wr.getNumBands()]; - double[] rgbaValues = new double[4]; - - int width = wr.getWidth(); - int height = wr.getHeight(); - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - // apply decode param. - ImageUtility.getNormalizedComponents( - (byte[]) wr.getDataElements(x, y, dataValues), - decode, - origValues); - - float Y = origValues[0] * 255; - float Cb = origValues[1] * 255; - float Cr = origValues[2] * 255; -// float K = origValues[3] * 255; - - // removing alteration for now as some samples are too dark. - // Y *= .95; // gives a darker image, as y approaches zero, - // the image becomes darke - - float Cr_128 = Cr - 128; - float Cb_128 = Cb - 128; - - // adobe conversion for CCIR Rec. 601-1 standard. - // http://partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf -// double rVal = Y + (1.4020 * Cr_128); -// double gVal = Y - (.3441363 * Cb_128) - (.71413636 * Cr_128); -// double bVal = Y + (1.772 * Cb_128); - - // intel codecs, http://software.intel.com/sites/products/documentation/hpc/ipp/ippi/ippi_ch6/ch6_color_models.html - // Intel IPP conversion for JPEG codec. -// double rVal = Y + (1.402 * Cr) - 179.456; -// double gVal = Y - (0.34414 * Cb) - (.71413636 * Cr) + 135.45984; -// double bVal = Y + (1.772 * Cb) - 226.816; - - // ICEsoft custom algorithm, results may vary, res are a little - // off but over all a better conversion/ then the stoke algorithms. - double rVal = Y + (1.4020 * Cr_128); - double gVal = Y + (.14414 * Cb_128) + (.11413636 * Cr_128); - double bVal = Y + (1.772 * Cb_128); - - // Intel IPP conversion for ITU-R BT.601 for video - // default 16, higher more green and darker blacks, lower less - // green hue and lighter blacks. -// double kLight = (1.164 * (Y -16 )); -// double rVal = kLight + (1.596 * Cr_128); -// double gVal = kLight - (0.392 * Cb_128) - (0.813 * Cr_128); -// double bVal = kLight + (1.017 * Cb_128); - // intel PhotoYCC Color Model [0.1], not a likely candidate for jpegs. -// double y1 = Y/255.0; -// double c1 = Cb/255.0; -// double c2 = Cr/255.0; -// double rVal = ((0.981 * y1) + (1.315 * (c2 - 0.537))) *255.0; -// double gVal = ((0.981 * y1) - (0.311 * (c1 - 0.612))- (0.669 * (c2 - 0.537))) *255.0; -// double bVal = ((0.981 * y1) + (1.601 * (c1 - 0.612))) *255.0; - - // check the range an convert as needed. - byte rByte = (rVal < 0) ? (byte) 0 : (rVal > 255) ? (byte) 0xFF : (byte) rVal; - byte gByte = (gVal < 0) ? (byte) 0 : (gVal > 255) ? (byte) 0xFF : (byte) gVal; - byte bByte = (bVal < 0) ? (byte) 0 : (bVal > 255) ? (byte) 0xFF : (byte) bVal; - int alpha = 0xFF; - if (y < smaskHeight && x < smaskWidth && smaskRaster != null) { - alpha = (smaskRaster.getSample(x, y, 0) & 0xFF); - } else if (y < maskHeight && x < maskWidth && maskRaster != null) { - // When making an ImageMask, the alpha channel is setup so that - // it both works correctly for the ImageMask being painted, - // and also for when it's used here, to determine the alpha - // of an image that it's masking - alpha = (maskImage.getRGB(x, y) >>> 24) & 0xFF; // Extract Alpha from ARGB - } - - rgbaValues[0] = bByte; - rgbaValues[1] = gByte; - rgbaValues[2] = rByte; - rgbaValues[3] = alpha; - - wr.setPixel(x, y, rgbaValues); - } - } - } - */ -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/YCbCrARasterOp.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/YCbCrARasterOp.java deleted file mode 100644 index ef3b651be0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/YCbCrARasterOp.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.icepdf.core.pobjects.graphics.RasterOps; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.Raster; -import java.awt.image.RasterOp; -import java.awt.image.WritableRaster; - -/** - * Raster operation that convers the YCbCrA to a ARGB colour space. - * - * @since 5.1 - */ -public class YCbCrARasterOp implements RasterOp { - - private RenderingHints hints = null; - - public YCbCrARasterOp(RenderingHints hints) { - this.hints = hints; - } - - public WritableRaster filter(Raster src, WritableRaster dest) { - - if (dest == null) dest = src.createCompatibleWritableRaster(); - - float[] origValues = new float[4]; - int[] rgbaValues = new int[4]; - int width = src.getWidth(); - int height = src.getHeight(); - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - src.getPixel(x, y, origValues); - - float Y = origValues[0]; - float Cb = origValues[1]; - float Cr = origValues[2]; - float K = origValues[3]; - Y = K - Y; - float Cr_128 = Cr - 128; - float Cb_128 = Cb - 128; - - float rVal = Y + (1370705 * Cr_128 / 1000000); - float gVal = Y - (337633 * Cb_128 / 1000000) - (698001 * Cr_128 / 1000000); - float bVal = Y + (1732446 * Cb_128 / 1000000); - - /* - // Formula used in JPEG standard. Gives pretty similar results - //int rVal = Y + (1402000 * Cr_128/ 1000000); - //int gVal = Y - (344140 * Cb_128 / 1000000) - (714140 * Cr_128 / 1000000); - //int bVal = Y + (1772000 * Cb_128 / 1000000); - */ - - byte rByte = (rVal < 0) ? (byte) 0 : (rVal > 255) ? (byte) 0xFF : (byte) rVal; - byte gByte = (gVal < 0) ? (byte) 0 : (gVal > 255) ? (byte) 0xFF : (byte) gVal; - byte bByte = (bVal < 0) ? (byte) 0 : (bVal > 255) ? (byte) 0xFF : (byte) bVal; - float alpha = K; - - rgbaValues[0] = rByte; - rgbaValues[1] = gByte; - rgbaValues[2] = bByte; - rgbaValues[3] = (int) alpha; - - dest.setPixel(x, y, rgbaValues); - } - } - return dest; - } - - public Rectangle2D getBounds2D(Raster src) { - return null; - } - - public WritableRaster createCompatibleDestRaster(Raster src) { - return src.createCompatibleWritableRaster(); - } - - public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { - if (dstPt == null) - dstPt = (Point2D) srcPt.clone(); - else - dstPt.setLocation(srcPt); - return dstPt; - } - - public RenderingHints getRenderingHints() { - return hints; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/YCbCrRasterOp.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/YCbCrRasterOp.java deleted file mode 100644 index 80abae0e7e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/RasterOps/YCbCrRasterOp.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.icepdf.core.pobjects.graphics.RasterOps; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.*; - -/** - * Raster operation that convers the YCbCr to a RGB colour space. - * - * @since 5.1 - */ -public class YCbCrRasterOp implements RasterOp { - - private RenderingHints hints = null; - - public YCbCrRasterOp(RenderingHints hints) { - this.hints = hints; - } - - public WritableRaster filter(Raster src, WritableRaster dest) { - - if (dest == null) dest = src.createCompatibleWritableRaster(); - - // my have to add some instance of checks - byte[] srcPixels = ((DataBufferByte) src.getDataBuffer()).getData(); - int[] destPixels = ((DataBufferInt) dest.getDataBuffer()).getData(); - - int Y, Cb, Cr; - int lastY = -1, lastCb = -1, lastCr = -1; - int rVal = 0, gVal = 0, bVal = 0; - int bands = src.getNumBands(); - for (int pixel = 0, intPixels = 0; pixel < srcPixels.length; pixel += bands, intPixels++) { - - Y = srcPixels[pixel] & 0xff; - Cb = srcPixels[pixel + 1] & 0xff; - Cr = srcPixels[pixel + 2] & 0xff; - - // no point recalculating if we are doing a band of colours. - if (!(lastY == Y && lastCb == Cb && lastCr == Cr)) { - // The Intel IPP color conversion functions specific for the JPEG codec - rVal = clamp((int) (Y + 1.402 * Cr - 179.456)); - gVal = clamp((int) (Y - 0.34414 * Cb - 0.71414 * Cr + 135.45984)); - bVal = clamp((int) (Y + 1.772 * Cb - 226.816)); - } - lastY = Y; - lastCb = Cb; - lastCr = Cr; - - destPixels[intPixels] = ((rVal & 0xff) << 16) | ((gVal & 0xff) << 8) | (bVal & 0xff); - } - return dest; - } - - // clamp the input between 0 ... 255 - private static int clamp(int x) { - return (x < 0) ? 0 : ((x > 255) ? 255 : x); - } - - public Rectangle2D getBounds2D(Raster src) { - return null; - } - - public WritableRaster createCompatibleDestRaster(Raster src) { - return src.createCompatibleWritableRaster(); - } - - public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { - if (dstPt == null) - dstPt = (Point2D) srcPt.clone(); - else - dstPt.setLocation(srcPt); - return dstPt; - } - - public RenderingHints getRenderingHints() { - return hints; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ScaledImageReference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ScaledImageReference.java deleted file mode 100644 index 963c723480..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ScaledImageReference.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.ImageUtility; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.image.BufferedImage; -import java.util.concurrent.FutureTask; -import java.util.logging.Logger; - -/** - * The ScaledImageReference stores the original image data as well as several - * smaller images instances which are painted at lower zoom values to improve - * paint speeds. - * - * @since 5.0 - */ -public class ScaledImageReference extends CachedImageReference { - - private static final Logger logger = - Logger.getLogger(ScaledImageReference.class.toString()); - - // scaled image size. - private int width; - private int height; - - protected ScaledImageReference(ImageStream imageStream, GraphicsState graphicsState, - Resources resources, int imageIndex, Page page) { - super(imageStream, graphicsState, resources, imageIndex, page); - - // get eh original image width. - width = imageStream.getWidth(); - height = imageStream.getHeight(); - - // kick off a new thread to load the image, if not already in pool. - ImagePool imagePool = imageStream.getLibrary().getImagePool(); - if (useProxy && imagePool.get(reference) == null) { - futureTask = new FutureTask(this); - Library.executeImage(futureTask); - } else if (!useProxy && imagePool.get(reference) == null) { - image = call(); - } - } - - public ScaledImageReference(ImageReference imageReference, GraphicsState graphicsState, Resources resources, - int width, int height, int imageIndex, Page page) { - super(imageReference.getImageStream(), graphicsState, resources, imageIndex, page); - - this.width = width; - this.height = height; - - // check for an repeated scale via a call from MipMap - if (imageReference.isImage()) { - image = imageReference.getImage(); - } - - // kick off a new thread to load the image, if not already in pool. - ImagePool imagePool = imageStream.getLibrary().getImagePool(); - if (useProxy && imagePool.get(reference) == null) { - futureTask = new FutureTask(this); - Library.executeImage(futureTask); - } else if (!useProxy && imagePool.get(reference) == null) { - image = call(); - } - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public BufferedImage call() { - BufferedImage image = null; - long start = System.nanoTime(); - try { - // get the stream image if need, otherwise scale what you have. - image = imageStream.getImage(graphicsState, resources); - - if (image != null) { - // get eh original image width. - int width = imageStream.getWidth(); - int height = imageStream.getHeight(); - - // apply scaling factor - double scaleFactor = 1.0; - if (width > 1000 && width < 1500) { - scaleFactor = 0.75; - } else if (width > 1500) { - scaleFactor = 0.5; - } - // update image size for any scaling. - if (scaleFactor < 1.0) { - width = (int) Math.ceil(width * scaleFactor); - height = (int) Math.ceil(height * scaleFactor); - - BufferedImage scaled; - if (ImageUtility.hasAlpha(image)) { - scaled = ImageUtility.createTranslucentCompatibleImage(width, height); - } else { - scaled = ImageUtility.createCompatibleImage(width, height); - } - Graphics2D g = scaled.createGraphics(); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - g.drawImage(image, 0, 0, width, height, null); - g.dispose(); - image.flush(); - image = scaled; - } - } - } catch (Throwable e) { - logger.warning("Error loading image: " + imageStream.getPObjectReference() + - " " + imageStream.toString()); - } - long end = System.nanoTime(); - notifyImagePageEvents((end - start)); - return image; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Separation.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Separation.java deleted file mode 100644 index 7e524de284..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Separation.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.functions.Function; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; - -/** - *

      Separation Color Space background:

      - *
        - *

        Color output devices produce full color by combining primary or process - * colorants in varying amounts. On an additive color device such as a display, - * the primary colorants consist of red, green, and blue phosphors; on a - * subtractive device such as a printer, they typically consist of cyan, magenta, - * yellow, and sometimes black inks. In addition, some devices can apply special - * colorants, often called spot colorants, to produce effects that cannot be - * achieved with the standard process colorants alone. Examples include metallic - * and fluorescent colors and special textures.

        - *
      - *

      A Separation color space (PDF 1.2) provides a means for specifying the use - * of additional colorants or for isolating the control of individual color - * components of a device color space for a subtractive device. When such a space - * is the current color space, the current color is a single-component value, - * called a tint, that controls the application of the given colorant or color - * components only.

      - *

      A Separation color space is defined as follows:
      - * [/Separation name alternateSpace tintTransform] - *

      - *
        - *
      • The alternateSpace parameter must be an array or name object that - * identifies the alternate color space, which can be any device or - * CIE-based color space but not another special color space (Pattern, - * Indexed, Separation, or DeviceN).
      • - *
      • The tintTransform parameter must be a function. - * During subsequent painting operations, an application - * calls this function to transform a tint value into color component values - * in the alternate color space. The function is called with the tint value - * and must return the corresponding color component values. That is, the - * number of components and the interpretation of their values depend on the - * alternate color space.
      • - *
      - * - * @since 1.0 - */ -public class Separation extends PColorSpace { - - public static final Name SEPARATION_KEY = new Name("Separation"); - - // named colour reference if valid conversion took place - protected Color namedColor; - // alternative colour space, named colour can not be resolved. - protected PColorSpace alternate; - // transform for colour tint, named function type - protected Function tintTransform; - // The special colorant name All shall refer collectively to all colorants - // available on an output device, including those for the standard process - // colorants. When a Separation space with this colorant name is the current - // colour space, painting operators shall apply tint values to all available - // colorants at once. - private boolean isAll; - public static final String COLORANT_ALL = "all"; - // The special colorant name None shall not produce any visible output. - // Painting operations in a Separationspace with this colorant name shall - // have no effect on the current page. - private boolean isNone; - public static final String COLORANT_NONE = "none"; - private float tint = 1.0f; - // basic cache to speed up the lookup. - private ConcurrentHashMap colorTable1B; - private ConcurrentHashMap colorTable3B; - private ConcurrentHashMap colorTable4B; - - /** - * Create a new Seperation colour space. Separation is specified using - * [/Seperation name alternateSpace tintTransform] - * - * @param l library - * @param h dictionary entries - * @param name name of colourspace, always seperation - * @param alternateSpace name of alternative colour space - * @param tintTransform function which defines the tint transform - */ - protected Separation(Library l, HashMap h, Object name, Object alternateSpace, Object tintTransform) { - super(l, h); - alternate = getColorSpace(l, alternateSpace); - colorTable1B = new ConcurrentHashMap(256); - colorTable3B = new ConcurrentHashMap(256); - colorTable4B = new ConcurrentHashMap(256); - - this.tintTransform = Function.getFunction(l, l.getObject(tintTransform)); - // see if name can be converted to a known colour. - if (name instanceof Name) { - String colorName = ((Name) name).getName().toLowerCase(); - // check for additive colours we can work with . - if (!(colorName.equals("red") || colorName.equals("blue") - || colorName.equals("blue") || colorName.equals("black") - || colorName.equals("cyan") || colorName.equals("brown") - || colorName.equals("auto"))) { - // sniff out All or Null - if (colorName.equals(COLORANT_ALL)) { - isAll = true; - } else if (colorName.equals(COLORANT_NONE)) { - isNone = true; - } - // return as we don't care about the namedColor if subtractive. - return; - } - // get colour value if any - int colorVaue = ColorUtil.convertNamedColor(colorName.toLowerCase()); - if (colorVaue != -1) { - namedColor = new Color(colorVaue); - } - // quick check for auto color which we'll paint as black - if (colorName.equalsIgnoreCase("auto")) { - namedColor = Color.BLACK; - } - } - } - - /** - * Returns the number of components in this colour space. - * - * @return number of components - */ - public int getNumComponents() { - return 1; - } - - public boolean isNamedColor() { - return namedColor != null; - } - - /** - * Gets the colour in RGB represented by the array of colour components - * - * @param components array of component colour data - * @param fillAndStroke true indicates a fill or stroke operation, so we - * will try to used the named colour and tint. This - * is generally not do for images. - * @return new RGB colour composed from the components array. - */ - public Color getColor(float[] components, boolean fillAndStroke) { - // there are couple notes in the spec that say that even know namedColor - // is for subtractive color devices, if the named colour can be represented - // in a additive device then it should be used over the alternate colour. - if (namedColor != null) { - // apply tint - tint = components[0]; - // apply tint as an alpha value. - float[] colour = namedColor.getComponents(null); -// namedColor = new Color(colour[0] * tint, colour[1] * tint, colour[2] * tint); - Color namedColor = new Color(colour[0], colour[1], colour[2], tint); - // The color model doesn't actually have transparency, so white with an alpha of 0. - // is still just white, not transparent. - if (tint < 0.1f && colour[0] == 0 && colour[1] == 0 && colour[2] == 0) { - return Color.WHITE; - } - return namedColor; - } - - // the function couldn't be initiated then use the alternative colour - // space. The alternate colour space can be any device or CIE-based - // colour space. However Separation is usually specified using only one - // component so we must generate the output colour - if (tintTransform == null) { - float colour = components[0]; - // copy the colour values into the needed length of the alternate colour - float[] alternateColour = new float[alternate.getNumComponents()]; - for (int i = 0, max = alternate.getNumComponents(); i < max; i++) { - alternateColour[i] = colour; - } - return alternate.getColor(alternateColour); - } - if (alternate != null && !isNone) { - // component is our key which we can use to avoid doing the tintTransform. - int key = 0; - int bands = components.length; - for (int i = 0, bit = 0; i < bands; i++, bit += 8) { - key |= (((int) (components[i] * 255) & 0xff) << bit); - } - if (bands == 1) { - return addColorToCache(colorTable1B, key, alternate, tintTransform, components); - } else if (bands == 3) { - return addColorToCache(colorTable3B, key, alternate, tintTransform, components); - } else if (bands == 4) { - return addColorToCache(colorTable4B, key, alternate, tintTransform, components); - } - } - if (isNone) { - return new Color(0, 0, 0, 0); - } - // return the named colour if it was resolved, otherwise assemble the - // alternative colour. - // -- Only applies to subtractive devices, screens are additive but I'm - // leaving this in encase something goes horribly wrong. - return namedColor; - } - - private static Color addColorToCache( - ConcurrentHashMap colorCache, int key, - PColorSpace alternate, Function tintTransform, float[] f) { - Color color = colorCache.get(key); - if (color == null) { - float y[] = tintTransform.calculate(reverse(f)); - color = alternate.getColor(reverse(y)); - colorCache.put(key, color); - return color; - } else { - return color; - } - } - - public float getTint() { - return tint; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingMeshPattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingMeshPattern.java deleted file mode 100644 index df16f2a05b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingMeshPattern.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.io.BitStream; -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.functions.Function; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.io.IOException; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * Base class for Mesh shading types 4-7. Each subtype parses the shading vertex information slighly differently - * but the decode and base parse for flag, coordinate and colour is the same. - * - * @since 6.2 - */ -public abstract class ShadingMeshPattern extends ShadingPattern implements Pattern { - - private static final Logger logger = - Logger.getLogger(ShadingMeshPattern.class.toString()); - - public static final Name BITS_PER_FLAG_KEY = new Name("BitsPerFlag"); - public static final Name BITS_PER_COORDINATE_KEY = new Name("BitsPerCoordinate"); - - protected static final int DECODE_X_MIN = 0; - protected static final int DECODE_X_MAX = 1; - protected static final int DECODE_Y_MIN = 2; - protected static final int DECODE_Y_MAX = 3; - - // (Required) The number of bits used to represent the edge flag for each vertex (see below). The value of - // BitsPerFlag shall be 2, 4, or 8, but only the least significant 2 bits in each flag value shall be used. - // The value for the edge flag shall be 0, 1, or 2. - protected int bitsPerFlag; - // (Required) The number of bits used to represent each vertex coordinate. - // The value shall be 1, 2, 4, 8, 12, 16, 24, or 32. - protected int bitsPerCoordinate; - // (Required) The number of bits used to represent each colour component. - // The value shall be 1, 2, 4, 8, 12, or 16. - protected int bitsPerComponent; - // colour space component count. - protected int colorSpaceCompCount; - - // vertex data - protected BitStream vertexBitStream; - protected Stream meshDataStream; - - // converted decode data to simply process later on, taken from our DecodeRasterOp class. - protected float[] decode; - - public ShadingMeshPattern(Library l, HashMap h, Stream meshDataStream) { - super(l, h); - this.meshDataStream = meshDataStream; - shadingDictionary = meshDataStream.getEntries(); - bitsPerFlag = library.getInt(shadingDictionary, BITS_PER_FLAG_KEY); - bitsPerCoordinate = library.getInt(shadingDictionary, BITS_PER_COORDINATE_KEY); - bitsPerComponent = library.getInt(shadingDictionary, ImageStream.BITSPERCOMPONENT_KEY); - colorSpace = PColorSpace.getColorSpace(library, library.getObject(shadingDictionary, COLORSPACE_KEY)); - colorSpaceCompCount = colorSpace.getNumComponents(); - - // Function is optional and cannot be used with indexed colour models. - Object tmp = library.getObject(shadingDictionary, FUNCTION_KEY); - if (tmp != null) { - if (!(tmp instanceof java.util.List)) { - function = new Function[]{Function.getFunction(library, - tmp)}; - } else { - java.util.List functionTemp = (java.util.List) tmp; - function = new Function[functionTemp.size()]; - for (int i = 0; i < functionTemp.size(); i++) { - function[i] = Function.getFunction(library, functionTemp.get(i)); - } - } - } - decode = processDecode(); - vertexBitStream = new BitStream(meshDataStream.getDecodedByteArrayInputStream()); - } - - public abstract Paint getPaint() throws InterruptedException; - - /** - * An array of numbers specifying how to map vertex coordinates and colour components into the - * appropriate ranges of values. The decoding method is similar to that used in image dictionaries - * (see 8.9.5.2, "Decode Arrays"). The ranges shall be specified as follows: - * [xmin xmax ymin ymax c1,min c1,max … cn,min cn,max] - * Only one pair of c values shall be specified if a Function entry is present. - */ - protected float[] processDecode() { - float[] decode = new float[6]; - if (function == null) { - decode = new float[4 + 2 * colorSpaceCompCount]; - } - - java.util.List decodeVec = (java.util.List) library.getObject(shadingDictionary, ImageStream.DECODE_KEY); - - float maxValue = bitsPerCoordinate < 32 ? (float) ((1 << bitsPerCoordinate) - 1) : (float) 2.3283064365386963e-10; // 2^-32; - for (int i = 0; i <= DECODE_Y_MAX; ) { - float Dmin = decodeVec.get(i).floatValue(); - float Dmax = decodeVec.get(i + 1).floatValue(); - decode[i++] = Dmin; - decode[i++] = (Dmax - Dmin) / maxValue; - } - maxValue = ((int) Math.pow(2, bitsPerComponent)) - 1; - for (int i = 4; i < decode.length; ) { - float Dmin = decodeVec.get(i).floatValue(); - float Dmax = decodeVec.get(i + 1).floatValue(); - decode[i++] = Dmin; - decode[i++] = (Dmax - Dmin) / maxValue; - } - return decode; - } - - /** - * Reads the vertex descriptor flag, length of flag is defined by the bitsPerFlag dictionary entry. - * - * @return int value of the vertex flag. - * @throws IOException bit stream issue. - */ - protected int readFlag() throws IOException { - return vertexBitStream.getBits(bitsPerFlag); - } - - /** - * Reads the vertex coordinate data, length of flag is defined by the bitsPerCoordinate dictionary entry. - * - * @return int value of the vertex coordinate. - * @throws IOException bit stream issue. - */ - protected Point2D.Float readCoord() throws IOException { - float x = vertexBitStream.getBits(bitsPerCoordinate); - float y = vertexBitStream.getBits(bitsPerCoordinate); - // normalize components to decode array - x *= decode[DECODE_X_MAX] - decode[DECODE_X_MIN] + decode[DECODE_X_MIN]; - y *= decode[DECODE_Y_MAX] - decode[DECODE_Y_MIN] + decode[DECODE_Y_MIN]; - return new Point2D.Float(x, y); - } - - /** - * Reads the vertex colour data, length of flag is defined by the colorSpaceCompCount dictionary entry. - * Color data is generate using the function if present as well as the defined colour space. - * - * @return int value of the vertex colour. - * @throws IOException bit stream issue. - */ - protected Color readColor() throws IOException { - float[] primitives; - if (function == null) { - primitives = new float[colorSpaceCompCount]; - for (int i = 0, j = 4; i < colorSpaceCompCount; i++, j += 2) { - primitives[i] = vertexBitStream.getBits(bitsPerComponent); - // normalize - primitives[i] *= decode[j + 1] - decode[j] + decode[j]; - } - primitives = PColorSpace.reverse(primitives); - return colorSpace.getColor(primitives, true); - } else { - float value = vertexBitStream.getBits(bitsPerComponent); - // normalize - value *= (decode[5] - decode[4]) + decode[4]; - primitives = new float[]{value}; - float[] output = calculateValues(primitives); - if (output != null) { - output = PColorSpace.reverse(output); - return colorSpace.getColor(output, true); - } - } - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingPattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingPattern.java deleted file mode 100644 index 733a69dfae..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingPattern.java +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.functions.Function; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      Shading Pattern is a Base class for a all shading Types. It contains - * all common dictionary entries and acts a factory examing the patternType - * entry and returning a know Pattern Type implementation. Currently the - * factory only support Shading Type2 and Type3 patterns, as thses are the only - * types we have concrete examples of.

      - * - * @author ICEsoft Technologies Inc. - * @since 3.0 - */ -public abstract class ShadingPattern extends Dictionary implements Pattern { - - private static final Logger logger = - Logger.getLogger(ShadingPattern.class.toString()); - - public static final Name PATTERN_TYPE_KEY = new Name("PatternType"); - public static final Name EXTGSTATE_KEY = new Name("ExtGState"); - public static final Name MATRIX_KEY = new Name("Matrix"); - public static final Name SHADING_KEY = new Name("Shading"); - public static final Name SHADING_TYPE_KEY = new Name("ShadingType"); - public static final Name BBOX_KEY = new Name("BBox"); - public static final Name COLORSPACE_KEY = new Name("ColorSpace"); - public static final Name BACKGROUND_KEY = new Name("Background"); - public static final Name ANTIALIAS_KEY = new Name("AntiAlias"); - public static final Name DOMAIN_KEY = new Name("Domain"); - public static final Name COORDS_KEY = new Name("Coords"); - public static final Name EXTEND_KEY = new Name("Extend"); - public static final Name FUNCTION_KEY = new Name("Function"); - // pattern types by number. - public static final int SHADING_PATTERN_TYPE_1 = 1; - public static final int SHADING_PATTERN_TYPE_2 = 2; - public static final int SHADING_PATTERN_TYPE_3 = 3; - public static final int SHADING_PATTERN_TYPE_4 = 4; - public static final int SHADING_PATTERN_TYPE_5 = 5; - public static final int SHADING_PATTERN_TYPE_6 = 6; - public static final int SHADING_PATTERN_TYPE_7 = 7; - - // type of PObject, should always be "Pattern" - protected Name type; - - // A code identifying the type of pattern that this dictionary describes - protected int patternType; - - // shadingDictionary dictionary, entries vary depending on shading type. - protected HashMap shadingDictionary; - - // shadingDictionary type 1-7, most common, 2,3,6.. - protected int shadingType; - - // start of common shading dictionary entries. - - // A 1-in, n-out function or an array of n 1-in, 1-out functions (where n - // is the number of colour components in the shadingDictionary dictionary's colour - // space). The function(s) are called with values of the parametric variables - // t in the domain defined by the domain entry. Each function's domain must - // be a superset of that of the shadingDictionary dictionary. If the return value - // is out of range it is adjusted to the nearest value. - protected Function[] function; - - // An array of four numbers in the pattern coordinate system giving the - // coordinates of the left, bottom, right, and top edges, respectively, of - // the pattern cell's bounding box. These boundaries are used to clip the - // pattern cell. - protected Rectangle2D bBox; - - // any device, cie-based or special color except Pattern, required. - protected PColorSpace colorSpace; - - // background colors (optional), not applicable on 'sh' - protected List background; - - // turn on/off antiAliasing. (optional) - protected boolean antiAlias; - - // end of common shading dictionary entries. - - // An array of six numbers specifying the pattern matrix. The default value - // is the identity matrix [1 0 0 1 0 0]. - protected AffineTransform matrix; - - // graphics state for shading pattern - protected ExtGState extGState; - - // initiated flag - protected boolean inited; - - public ShadingPattern(Library library, HashMap entries) { - super(library, entries); - - type = library.getName(entries, TYPE_KEY); - - patternType = library.getInt(entries, PATTERN_TYPE_KEY); - - Object attribute = library.getObject(entries, EXTGSTATE_KEY); - if (attribute instanceof HashMap) { - extGState = new ExtGState(library, (HashMap) attribute); - } else if (attribute instanceof Reference) { - extGState = new ExtGState(library, - (HashMap) library.getObject( - (Reference) attribute)); - } - - List v = (List) library.getObject(entries, MATRIX_KEY); - if (v != null) { - matrix = getAffineTransform(v); - } else { - // default is identity matrix - matrix = new AffineTransform(); - } - } - - /** - * Factory method to resolve the shading dictionaries ShadingType 1 - 3. - * - * @param library library for document - * @param attribute dictionary for potential shading object. - * @return returns a Shading object based ont he shadingType criteria. - * if the proper constructor cannot be found then null is returned. - */ - public static ShadingPattern getShadingPattern(Library library, HashMap attribute) { - // factory type approach, find shading entries and get type - Object shading = library.getObject(attribute, SHADING_KEY); - // setup 1-3 as they are dictionary based. - if (shading != null && shading instanceof HashMap) { - return shadingFactory(library, attribute, (HashMap) shading); - } else if (shading != null && shading instanceof Stream) { - return getShadingPattern(library, attribute, (Stream) shading); - } - return null; - } - - /** - * Factory method to resolve the shadingDictionary dictionaries ShadingType 4- 6 which are Stream based. - * - * @param library library for document - * @param attribute dictionary for potential shadingDictionary object. - * @return returns a ShadingPattern object based ont he shadingType criteria. - * if the proper constructor cannot be found then null is returned. - */ - public static ShadingPattern getShadingPattern(Library library, HashMap attribute, Stream shadingStream) { - int shadingType = library.getInt(shadingStream.getEntries(), SHADING_TYPE_KEY); - switch (shadingType) { - case SHADING_PATTERN_TYPE_4: - return new ShadingType4Pattern(library, attribute, shadingStream); - case SHADING_PATTERN_TYPE_5: - return new ShadingType5Pattern(library, attribute, shadingStream); - case SHADING_PATTERN_TYPE_6: - return new ShadingType6Pattern(library, attribute, shadingStream); - case SHADING_PATTERN_TYPE_7: - return new ShadingType7Pattern(library, attribute, shadingStream); - } - return null; - } - - /** - * Factory call create a support pattern type. Currently only types 2 and - * 3 are supported. - * - * @param library document library - * @param entries entries in the the currently dictionary. - * @param shading shading dictionary. - * @return shading pattern - */ - public static ShadingPattern getShadingPattern(Library library, - HashMap entries, - HashMap shading) { - // resolve shading pattern - if (entries != null) { - ShadingPattern shadingPattern = shadingFactory(library, shading, shading); - // assign shading dictionary for sh instances that only define - // the shading dictionary and not the full pattern dictionary. - shadingPattern.setShadingDictionary(shading); - return shadingPattern; - } - - return null; - } - - // create a new shading pattern. - private static ShadingPattern shadingFactory(Library library, - HashMap attribute, - HashMap patternDictionary) { - int shadingType = library.getInt(patternDictionary, SHADING_TYPE_KEY); - if (shadingType == ShadingPattern.SHADING_PATTERN_TYPE_2) { - return new ShadingType2Pattern(library, attribute); - } else if (shadingType == ShadingPattern.SHADING_PATTERN_TYPE_3) { - return new ShadingType3Pattern(library, attribute); - } else if (shadingType == ShadingPattern.SHADING_PATTERN_TYPE_1) { - return new ShadingType1Pattern(library, attribute); - } else { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Shading pattern of Type " + shadingType + - " are not currently supported"); - } - } - return null; - } - - /** - * Utility method for parsing a vector of affinetranform values to an - * affine transform. - * - * @param v vector containing affine transform values. - * @return affine transform based on v - */ - private static AffineTransform getAffineTransform(List v) { - float f[] = new float[6]; - for (int i = 0; i < 6; i++) { - f[i] = ((Number) v.get(i)).floatValue(); - } - return new AffineTransform(f); - } - - /** - * Applies the function data to the values array. - * @param values values to feed functions. - * @return new values after function execution. - */ - protected float[] calculateValues(float[] values) { - float[] output; - int length = function.length; - if (length == 1) { - output = function[0].calculate(values); - } else { - // vector of function for each colour component, 1 in 1 out. - output = new float[length]; - for (int i = 0; i < length; i++) { - output[i] = function[i].calculate(values)[0]; - } - } - return output; - } - - /** - * Gets the Paint object need to fill a shape etc. Each individual - * implementation will return a particular paint type. - * - * @return Paint type for fill. - */ - public abstract Paint getPaint() throws InterruptedException; - - /** - * Initialized shading dictionary attributes. Discrepancies between sh and - * scn tokens cause us to handle initialization at a later time. - */ - public abstract void init(GraphicsState graphicsState); - - public void setParentGraphicState(GraphicsState graphicsState) { - // nothing to be done for shading. - } - - public void setMatrix(AffineTransform matrix) { - this.matrix = matrix; - } - - public int getPatternType() { - return patternType; - } - - public Rectangle2D getBBox() { - return bBox; - } - - public AffineTransform getMatrix() { - return matrix; - } - - public int getShadingType() { - return shadingType; - } - - public void setShadingDictionary(HashMap shadingDictionary) { - this.shadingDictionary = shadingDictionary; - } - - public Name getType() { - return type; - } - - public PColorSpace getColorSpace() { - return colorSpace; - } - - public List getBackground() { - return background; - } - - public boolean isAntiAlias() { - return antiAlias; - } - - public ExtGState getExtGState() { - return extGState; - } - - public boolean isInited() { - return inited; - } - - public String toString() { - return "Shading Pattern: \n" + - " type: pattern " + - "\n patternType: shadingDictionary" + - "\n matrix: " + matrix + - "\n extGState: " + extGState + - "\n shading dictionary: " + shadingDictionary + - "\n shadingType: " + shadingType + - "\n colourSpace: " + colorSpace + - "\n background: " + background + - "\n bbox: " + bBox + - "\n antiAlias: " + antiAlias; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType1Pattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType1Pattern.java deleted file mode 100644 index cf79e89e7e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType1Pattern.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.functions.Function; -import org.icepdf.core.pobjects.graphics.batik.ext.awt.LinearGradientPaint; -import org.icepdf.core.pobjects.graphics.batik.ext.awt.MultipleGradientPaint; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -/** - * In Type 1 (function-based) shadings, the colour at every point in the domain - * is defined by a specified mathematical function. The function need not be - * smooth or continuous. This type is the most general of the available shading - * types and is useful for shadings that cannot be adequately described with any - * of the other types. Table 79 shows the shading dictionary entries specific - * to this type of shading, in addition to those common to all shading - * dictionaries - * - * @author ICEsoft Technologies Inc. - * @since 5.0 - */ -public class ShadingType1Pattern extends ShadingType2Pattern { - - private static final Logger logger = - Logger.getLogger(ShadingType1Pattern.class.toString()); - - /** - * (Optional) An array of four numbers [xmin xmax ymin ymax] specifying the - * rectangular domain of coordinates over which the colour function(s) are - * defined. Default value: [0.0 1.0 0.0 1.0]. - */ -// protected java.util.List domain; - - /** - * (Required) A 2-in, n-out function or an array of n 2-in, 1-out functions - * (where n is the number of colour components in the shading dictionary’s - * colour space). Each function’s domain shall be a superset of that of the - * shading dictionary. If the value returned by the function for a given - * colour component is out of range, it shall be adjusted to the nearest - * valid value. - */ -// protected Function[] function; - - // linear gradient paint describing the gradient. - private LinearGradientPaint linearGradientPaint; - - public ShadingType1Pattern(Library library, HashMap entries) { - super(library, entries); - } - - @SuppressWarnings("unchecked") - public synchronized void init(GraphicsState graphicsState) { - if (inited) { - return; - } - - // shading dictionary - if (shadingDictionary == null) { - shadingDictionary = library.getDictionary(entries, SHADING_KEY); - } - - colorSpace = PColorSpace.getColorSpace(library, - library.getObject(shadingDictionary, COLORSPACE_KEY)); - - // get type 2 specific data. - Object tmp = library.getObject(shadingDictionary, DOMAIN_KEY); - if (tmp instanceof java.util.List) { - domain = (List) tmp; - } else { - domain = new ArrayList(2); - domain.add(0.0f); - domain.add(1.0f); - domain.add(0.0f); - domain.add(1.0f); - } - - // functions - tmp = library.getObject(shadingDictionary, FUNCTION_KEY); - if (tmp != null) { - if (!(tmp instanceof java.util.List)) { - function = new Function[]{Function.getFunction(library, - tmp)}; - } else { - java.util.List functionTemp = (java.util.List) tmp; - function = new Function[functionTemp.size()]; - for (int i = 0; i < functionTemp.size(); i++) { - function[i] = Function.getFunction(library, functionTemp.get(i)); - } - } - } - - // first off, create the two needed start and end points of the line - Point2D.Float startPoint = new Point2D.Float( - domain.get(0).floatValue(), - domain.get(2).floatValue()); - - Point2D.Float endPoint = new Point2D.Float( - domain.get(0).floatValue(), - domain.get(3).floatValue()); - - // calculate the t's - float t0 = domain.get(0).floatValue(); - float t1 = domain.get(3).floatValue(); - - // calculate colour based on points that make up the line, 10 is a good - // number for speed and gradient quality. - try { - int numberOfPoints = 10; - Color[] colors = calculateColorPoints(numberOfPoints, startPoint, endPoint, t0, t1); - float[] dist = calculateDomainEntries(numberOfPoints, t0, t1); - - linearGradientPaint = new LinearGradientPaint( - startPoint, endPoint, dist, colors, - MultipleGradientPaint.NO_CYCLE, - MultipleGradientPaint.LINEAR_RGB, - matrix); - inited = true; - } catch (Exception e) { - logger.finer("Failed ot initialize gradient paint type 1."); - } - } - - /** - * Not implemented - * - * @return will always return null; - */ - public Paint getPaint() { - return null; - } - - - public String toSting() { - return super.toString() + - "\n domain: " + domain + - "\n matrix: " + matrix + - "\n function: " + function; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType2Pattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType2Pattern.java deleted file mode 100644 index 7dedc72874..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType2Pattern.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.functions.Function; -import org.icepdf.core.pobjects.graphics.batik.ext.awt.LinearGradientPaint; -import org.icepdf.core.pobjects.graphics.batik.ext.awt.MultipleGradientPaint; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -/** - *

      Type 2 (axial) shadings define colour blend that varies along a linear - * axis between two endpoints and extends indefinitely perpendicular to the - * that axis.

      - * - * @author ICEsoft Technologies Inc. - * @since 2.7 - */ -public class ShadingType2Pattern extends ShadingPattern { - - private static final Logger logger = - Logger.getLogger(ShadingType2Pattern.class.toString()); - - // An array of two numbers [t0, t1] specifying the limiting values of a - // parametric variable t. The variable is considered to vary linearly between - // these two values as the colour gradient varies between the starting and - // ending points of the axis. The variable t becomes the argument to the - // colour function(s). Default [0,1]. - protected List domain; - - // An array of four numbers [x0, y0, x1, y1] specifying the starting and - // ending coordinates of the axis, expressed in the shading's target - // coordinate space. - protected java.util.List coords; - - // An array of two Boolean values specifying whether to extend the shading - // beyond the starting and ending points of the axis, Default [false, false]. - protected List extend; - - // linear gradient paint describing the gradient. - private LinearGradientPaint linearGradientPaint; - - public ShadingType2Pattern(Library library, HashMap entries) { - super(library, entries); - } - - @SuppressWarnings("unchecked") - public synchronized void init(GraphicsState graphicsState) { - - if (inited) { - return; - } - - // shadingDictionary dictionary - if (shadingDictionary == null) { - shadingDictionary = library.getDictionary(entries, SHADING_KEY); - } - - shadingType = library.getInt(shadingDictionary, SHADING_TYPE_KEY); - bBox = library.getRectangle(shadingDictionary, BBOX_KEY); - colorSpace = PColorSpace.getColorSpace(library, - library.getObject(shadingDictionary, COLORSPACE_KEY)); - Object tmp = library.getObject(shadingDictionary, BACKGROUND_KEY); - if (tmp != null && tmp instanceof List) { - background = (java.util.List) tmp; - } - antiAlias = library.getBoolean(shadingDictionary, ANTIALIAS_KEY); - - // get type 2 specific data. - tmp = library.getObject(shadingDictionary, DOMAIN_KEY); - if (tmp instanceof List) { - domain = (List) tmp; - } else { - domain = new ArrayList(2); - domain.add(0.0f); - domain.add(1.0f); - } - - tmp = library.getObject(shadingDictionary, COORDS_KEY); - if (tmp instanceof List) { - coords = (java.util.List) tmp; - } - tmp = library.getObject(shadingDictionary, EXTEND_KEY); - if (tmp instanceof List) { - extend = (List) tmp; - } else { - extend = new ArrayList(2); - extend.add(false); - extend.add(false); - } - tmp = library.getObject(shadingDictionary, FUNCTION_KEY); - if (tmp != null) { - if (!(tmp instanceof List)) { - function = new Function[]{Function.getFunction(library, - tmp)}; - } else { - List functionTemp = (List) tmp; - function = new Function[functionTemp.size()]; - for (int i = 0; i < functionTemp.size(); i++) { - function[i] = Function.getFunction(library, functionTemp.get(i)); - } - } - } - - // calculate the t's - float t0 = domain.get(0).floatValue(); - float t1 = domain.get(1).floatValue(); - - // first off, create the two needed start and end points of the line - Point2D.Float startPoint = new Point2D.Float( - ((Number) coords.get(0)).floatValue(), - ((Number) coords.get(1)).floatValue()); - - Point2D.Float endPoint = new Point2D.Float( - ((Number) coords.get(2)).floatValue(), - ((Number) coords.get(3)).floatValue()); - - // corner case where a pdf engine give zero zero coords which batik - // can't handle so we pad it slightly. - if (startPoint.equals(endPoint)) { - endPoint.x++; - } - - // calculate colour based on points that make up the line, 10 is a good - // number for speed and gradient quality. - try { - int numberOfPoints = 10; - Color[] colors = calculateColorPoints(numberOfPoints, startPoint, endPoint, t0, t1); - float[] dist = calculateDomainEntries(numberOfPoints, t0, t1); - - linearGradientPaint = new LinearGradientPaint( - startPoint, endPoint, dist, colors, - MultipleGradientPaint.NO_CYCLE, - MultipleGradientPaint.LINEAR_RGB, - matrix); - inited = true; - } catch (Exception e) { - logger.finer("Failed ot initialize gradient paint type 2."); - } - } - - /** - * Calculates x number of points on long the line defined by the start and - * end point. - * - * @param numberOfPoints number of points to generate. - * @param startPoint start of line segment. - * @param endPoint end of line segment. - * @return list of points found on line - */ - protected Color[] calculateColorPoints(int numberOfPoints, - Point2D.Float startPoint, - Point2D.Float endPoint, - float t0, float t1) { - // calculate the slope - float m = (startPoint.y - endPoint.y) / (startPoint.x - endPoint.x); - // calculate the y intercept - float b = startPoint.y - (m * startPoint.x); - - // let calculate x points between startPoint.x and startPoint.y that - // are on the line using y = mx + b. - Color[] color; - // if we don't have a y-axis line we can uses y=mx + b to get our points. - if (!Float.isInfinite(m)) { - float xDiff = (endPoint.x - startPoint.x) / numberOfPoints; - float xOffset = startPoint.x; - color = new Color[numberOfPoints + 1]; - Point2D.Float point; - for (int i = 0, max = color.length; i < max; i++) { - point = new Point2D.Float(xOffset, (m * xOffset) + b); - color[i] = calculateColour(colorSpace, point, startPoint, endPoint, t0, t1); - xOffset += xDiff; - } - } - // otherwise we have a infinite m and can just pick y values - else { - float yDiff = (endPoint.y - startPoint.y) / numberOfPoints; - float yOffset = startPoint.y; - color = new Color[numberOfPoints + 1]; - Point2D.Float point; - for (int i = 0, max = color.length; i < max; i++) { - point = new Point2D.Float(0, yOffset); - color[i] = calculateColour(colorSpace, point, startPoint, endPoint, t0, t1); - yOffset += yDiff; - } - } - return color; - } - - /** - * Calculate domain entries givent the number of point between t0 and t1 - * - * @param numberOfPoints number of points to calculate - * @param t0 lower limit - * @param t1 upper limit - * @return array of floats the evenly divide t0 and t1, length is - * numberOfPoints + 1 - */ - protected float[] calculateDomainEntries(int numberOfPoints, float t0, float t1) { - - float offset = 1.0f / numberOfPoints; - float[] domainEntries = new float[numberOfPoints + 1]; - - domainEntries[0] = t0; - for (int i = 1, max = domainEntries.length; i < max; i++) { - domainEntries[i] = domainEntries[i - 1] + offset; - } - domainEntries[domainEntries.length - 1] = t1; - return domainEntries; - } - - /** - * Calculate the colours value of the point xy on the line point1 and point2. - * - * @param colorSpace colour space to apply to the function output - * @param xy point to calcualte the colour of. - * @param point1 start of gradient line - * @param point2 end of gradient line. - * @param t0 domain min - * @param t1 domain max - * @return colour derived from the input parameters. - */ - private Color calculateColour(PColorSpace colorSpace, Point2D.Float xy, - Point2D.Float point1, Point2D.Float point2, - float t0, float t1) { - // find colour at point 1 - float xPrime = linearMapping(xy, point1, point2); - float t = parametrixValue(xPrime, t0, t1, extend); - // find colour at point 2 - float[] input = new float[1]; - input[0] = t; - // apply the function to the given input - if (function != null) { - float[] output = calculateValues(input); - if (output != null) { - output = PColorSpace.reverse(output); - return colorSpace.getColor(output, true); - } else { - return null; - } - - } else { - logger.fine("Error processing Shading Type 2 Pattern."); - return null; - } - - } - - /** - * Colour blend function to be applied to a point on the line with endpoints - * point1 and point1 for a given point x,y. - * - * @param xy point to linearize. - * @param point1 end point of line - * @param point2 end poitn of line. - * @return linearized x' value. - */ - private float linearMapping(Point2D.Float xy, Point2D.Float point1, Point2D.Float point2) { - float x = xy.x; - float y = xy.y; - float x0 = point1.x; - float y0 = point1.y; - float x1 = point2.x; - float y1 = point2.y; - float top = (((x1 - x0) * (x - x0)) + ((y1 - y0) * (y - y0))); - float bottom = (((x1 - x0) * (x1 - x0)) + ((y1 - y0) * (y1 - y0))); - // have a couple corner cases where 1.00000046 isn't actually 1.0 - // so I'm going to tweak the calculation to have 3 decimals. - int map = (int) ((top / bottom) * 100); - return map / 100.0f; - } - - /** - * Parametric variable t calculation as defined in Section 4.6, Type 2 - * (axial) shadings. - * - * @param linearMapping linear mapping of some point x' - * @param t0 domain of axial shading, limit 1 - * @param t1 domain of axial shading, limit 2 - * @param extended 2 element vector, indicating line extension along domain - * @return parametric value. - */ - private float parametrixValue(float linearMapping, float t0, float t1, - List extended) { - - if (linearMapping < 0 && ((Boolean) extended.get(0))) { - return t0; - } else if (linearMapping > 1 && ((Boolean) extended.get(1))) { - return t1; - } else { - return t0 + ((t1 - t0) * linearMapping); - } - } - - public Paint getPaint() { - try { - init(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("ShadingType2Pattern initialization interrupted"); - } - return linearGradientPaint; - } - - public String toString() { - return super.toString() + - "\n domain: " + domain + - "\n coords: " + coords + - "\n extend: " + extend + - "\n function: " + function; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType3Pattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType3Pattern.java deleted file mode 100644 index b0555347e3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType3Pattern.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.functions.Function; -import org.icepdf.core.pobjects.graphics.batik.ext.awt.MultipleGradientPaint; -import org.icepdf.core.pobjects.graphics.batik.ext.awt.RadialGradientPaint; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -/** - *

      Type 3 (radial) shading define a colour blend that varies between two - * circles. Shading of this type are commonly used to depict three-dimensional - * spheres and cones.

      - * - * @author ICEsoft Technologies Inc. - * @since 3.0 - */ -public class ShadingType3Pattern extends ShadingPattern { - - private static final Logger logger = - Logger.getLogger(ShadingType3Pattern.class.toString()); - - // An array of two numbers [t0, t1] specifying the limiting values of a - // parametric variable t. The variable is considered to vary linearly between - // these two values as the colour gradient varies between the starting and - // ending points of the axis. The variable t becomes the argument to the - // colour function(s). Default [0,1]. - protected List domain; - - // An array of six numbers [x0, y0, r0, x1, y1, r1] specifying the centers - // and radii of the starting and ending circles. Expressed in the shading - // target coordinate space. The radii r0 and r1 must both be greater than - // or equal to 0. If both are zero nothing is painted. - protected List coords; - - // An array of two Boolean values specifying whether to extend the shading - // beyond the starting and ending points of the axis, Default [false, false]. - protected List extend; - - // radial gradient paint that is used by java for paint. - protected RadialGradientPaint radialGradientPaint; - - - public ShadingType3Pattern(Library library, HashMap entries) { - super(library, entries); - } - - @SuppressWarnings("unchecked") - public synchronized void init(GraphicsState graphicsState) { - - if (inited) { - return; - } - - // shadingDictionary dictionary - if (shadingDictionary == null) { - shadingDictionary = library.getDictionary(entries, SHADING_KEY); - } - - shadingType = library.getInt(shadingDictionary, SHADING_TYPE_KEY); - bBox = library.getRectangle(shadingDictionary, BBOX_KEY); - colorSpace = PColorSpace.getColorSpace(library, - library.getObject(shadingDictionary, COLORSPACE_KEY)); - if (library.getObject(shadingDictionary, BACKGROUND_KEY) != null && - library.getObject(shadingDictionary, BACKGROUND_KEY) instanceof List) { - background = (List) library.getObject(shadingDictionary, BACKGROUND_KEY); - } - antiAlias = library.getBoolean(shadingDictionary, ANTIALIAS_KEY); - - // get type 2 specific data. - Object tmp = library.getObject(shadingDictionary, DOMAIN_KEY); - if (tmp instanceof List) { - domain = (List) tmp; - } else { - domain = new ArrayList(2); - domain.add(0.0f); - domain.add(1.0f); - } - tmp = library.getObject(shadingDictionary, COORDS_KEY); - if (tmp instanceof List) { - coords = (List) tmp; - } - tmp = library.getObject(shadingDictionary, EXTEND_KEY); - if (tmp instanceof List) { - extend = (List) tmp; - } else { - extend = new ArrayList(2); - extend.add(false); - extend.add(false); - } - tmp = library.getObject(shadingDictionary, FUNCTION_KEY); - if (tmp != null) { - if (!(tmp instanceof List)) { - function = new Function[]{Function.getFunction(library, - tmp)}; - } else { - List functionTemp = (List) tmp; - function = new Function[functionTemp.size()]; - for (int i = 0; i < functionTemp.size(); i++) { - function[i] = Function.getFunction(library, functionTemp.get(i)); - } - } - } - - float t0 = domain.get(0).floatValue(); - float t1 = domain.get(1).floatValue(); - float s[] = new float[]{0.0f, 0.25f, 0.5f, 0.75f, 1.0f}; - - Point2D.Float center = new Point2D.Float( - ((Number) coords.get(0)).floatValue(), - ((Number) coords.get(1)).floatValue()); - - Point2D.Float focus = new Point2D.Float( - ((Number) coords.get(3)).floatValue(), - ((Number) coords.get(4)).floatValue()); - - float radius = ((Number) coords.get(2)).floatValue(); - float radius2 = ((Number) coords.get(5)).floatValue(); - - // approximation, as we don't full support radial point via the paint - // class. - if (radius2 > radius) { - radius = radius2; - } - - try { - // get the number off components in the colour - Color color1 = calculateColour(colorSpace, s[0], t0, t1); - Color color2 = calculateColour(colorSpace, s[1], t0, t1); - Color color3 = calculateColour(colorSpace, s[2], t0, t1); - Color color4 = calculateColour(colorSpace, s[3], t0, t1); - Color color5 = calculateColour(colorSpace, s[4], t0, t1); - - if (color1 == null || color2 == null) { - return; - } - // Construct a LinearGradientPaint object to be use by java2D - Color[] colors = {color1, color2, color3, color4, color5}; - - radialGradientPaint = new RadialGradientPaint( - center, radius, - focus, - s, - colors, - MultipleGradientPaint.NO_CYCLE, - MultipleGradientPaint.LINEAR_RGB, - matrix); - - // get type 3 specific data. - inited = true; - } catch (Exception e) { - logger.finer("Failed ot initialize gradient paint type 3."); - } - } - - private Color calculateColour(PColorSpace colorSpace, float s, - float t0, float t1) { - - // find colour at point 1 - float t = parametrixValue(s, t0, t1, extend); - // find colour at point - float[] input = new float[1]; - input[0] = t; - if (function != null) { - float[] output = calculateValues(input); - if (output != null) { - if (!(colorSpace instanceof DeviceN)) { - output = PColorSpace.reverse(output); - } - return colorSpace.getColor(output); - } else { - return null; - } - } else { - logger.fine("Error processing Shading Type 3 Pattern."); - return null; - } - } - - /** - * Parametric variable t calculation as defined in Section 4.6, Type 2 - * (axial) shadings. - * - * @param linearMapping linear mapping of some point x' - * @param t0 domain of axial shading, limit 1 - * @param t1 domain of axial shading, limit 2 - * @param extended 2 element vector, indicating line extension along domain - * @return parametric value. - */ - private float parametrixValue(float linearMapping, float t0, float t1, - List extended) { - return t0 + ((t1 - t0) * linearMapping); - } - - public Paint getPaint() throws InterruptedException { - init(); - return radialGradientPaint; - } - - public String toSting() { - return super.toString() + - "\n domain: " + domain + - "\n coords: " + coords + - "\n extend: " + extend + - "\n function: " + function; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType4Pattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType4Pattern.java deleted file mode 100644 index 80f8b5cc4a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType4Pattern.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * Free-form Gouraud-shaded Triangle Meshes support. - * - * Note: currently only parsing data and returning the first colour of the first vertex. - * - * @since 6.2 - */ -public class ShadingType4Pattern extends ShadingMeshPattern { - - private static final Logger logger = - Logger.getLogger(ShadingType4Pattern.class.toString()); - - private ArrayList vertexEdgeFlag = new ArrayList(); - private ArrayList coordinates = new ArrayList(); - private ArrayList colorComponents = new ArrayList(); - - public ShadingType4Pattern(Library l, HashMap h, Stream meshDataStream) { - super(l, h, meshDataStream); - } - - public void init(GraphicsState graphicsState) { - - vertexEdgeFlag = new ArrayList(); - coordinates = new ArrayList(); - colorComponents = new ArrayList(); - try { - while (vertexBitStream.available() > 0) { - vertexEdgeFlag.add(readFlag()); - coordinates.add(readCoord()); - colorComponents.add(readColor()); - } - } catch (IOException e) { - logger.warning("Error parsing Shading type 4 pattern vertices."); - } - } - - public Paint getPaint() throws InterruptedException { - return colorComponents.get(0); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType5Pattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType5Pattern.java deleted file mode 100644 index 66e63d61c2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType5Pattern.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * Lattice-Form Gouraud-shaded Triangle Meshes support. - * - * Note: currently only parsing data and returning the first colour of the first vertex. - * - * @since 6.2 - */ -public class ShadingType5Pattern extends ShadingMeshPattern { - - private static final Logger logger = - Logger.getLogger(ShadingType5Pattern.class.toString()); - - private ArrayList coordinates = new ArrayList(); - private ArrayList colorComponents = new ArrayList(); - - public ShadingType5Pattern(Library l, HashMap h, Stream meshDataStream) { - super(l, h, meshDataStream); - } - - public void init(GraphicsState graphicsState) { - coordinates = new ArrayList(); - colorComponents = new ArrayList(); - try { - while (vertexBitStream.available() > 0) { - coordinates.add(readCoord()); - colorComponents.add(readColor()); - } - } catch (IOException e) { - logger.warning("Error parsing Shading type 5 pattern vertices."); - } - } - - public Paint getPaint() throws InterruptedException { - return colorComponents.get(0); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType6Pattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType6Pattern.java deleted file mode 100644 index 5dc537dd1c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType6Pattern.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * Coons Patch Meshes support. - * - * Note: currently only parsing data and returning the first colour of the first vertex. - * - * @since 6.2 - */ -public class ShadingType6Pattern extends ShadingMeshPattern { - - private static final Logger logger = - Logger.getLogger(ShadingType6Pattern.class.toString()); - - private ArrayList coordinates = new ArrayList(); - private ArrayList colorComponents = new ArrayList(); - - public ShadingType6Pattern(Library l, HashMap h, Stream meshDataStream) { - super(l, h, meshDataStream); - } - - public void init(GraphicsState graphicsState) { - coordinates = new ArrayList(); - colorComponents = new ArrayList(); - try { - while (vertexBitStream.available() > 0) { - int flag = readFlag(); - // read control points. - for (int i = 0, ii = (flag != 0 ? 8 : 12); i < ii; i++) { - coordinates.add(readCoord()); - } - for (int i = 0, ii = (flag != 0 ? 2 : 4); i < ii; i++) { - colorComponents.add(readColor()); - } - } - } catch (IOException e) { - logger.warning("Error parsing Shading type 6 pattern vertices."); - } - } - - public Paint getPaint() throws InterruptedException { - return colorComponents.get(0); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType7Pattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType7Pattern.java deleted file mode 100644 index 77f009ac9f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/ShadingType7Pattern.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.Point2D; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.logging.Logger; - -/** - * Tensor-Product Patch Meshes support. - * - * Note: currently only parsing data and returning the first colour of the first vertex. - * - * @since 6.2 - */ -public class ShadingType7Pattern extends ShadingMeshPattern { - - private static final Logger logger = - Logger.getLogger(ShadingType7Pattern.class.toString()); - - private ArrayList coordinates = new ArrayList(); - private ArrayList colorComponents = new ArrayList(); - - public ShadingType7Pattern(Library l, HashMap h, Stream meshDataStream) { - super(l, h, meshDataStream); - } - - public void init(GraphicsState graphicsState) { - coordinates = new ArrayList(); - colorComponents = new ArrayList(); - try { - while (vertexBitStream.available() > 0) { - int flag = readFlag(); - // read control points. - for (int i = 0, ii = (flag != 0 ? 12 : 16); i < ii; i++) { - coordinates.add(readCoord()); - } - for (int i = 0, ii = (flag != 0 ? 2 : 4); i < ii; i++) { - colorComponents.add(readColor()); - } - } - } catch (IOException e) { - logger.warning("Error parsing Shading type 7 pattern vertices."); - } - } - - public Paint getPaint() throws InterruptedException { - return colorComponents.get(1); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Shapes.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Shapes.java deleted file mode 100644 index fa7c687cd6..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/Shapes.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.commands.DrawCmd; -import org.icepdf.core.pobjects.graphics.commands.FormDrawCmd; -import org.icepdf.core.pobjects.graphics.commands.ImageDrawCmd; -import org.icepdf.core.pobjects.graphics.commands.ShapesDrawCmd; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      The Shapes class hold all object that are parsed from a Page's content - * streams. These contained object make up a pages graphics stack which can - * be iterated through to paint a page's content.

      - *

      - *

      This class is generally only used by the Content parser during content - * parsing. The class also stores points to the images found in the content - * as well as the text that is encoded on a page.

      - * - * @since 1.0 - */ -public class Shapes { - - private static final Logger logger = - Logger.getLogger(Shapes.class.toString()); - - private static int shapesInitialCapacity = 5000; - // disables alpha painting. - protected boolean paintAlpha = - !Defs.sysPropertyBoolean("org.icepdf.core.paint.disableAlpha", false); - - static { - shapesInitialCapacity = Defs.sysPropertyInt( - "org.icepdf.core.shapes.initialCapacity", shapesInitialCapacity); - } - - // cache of common draw state, we try to avoid adding new operands if the - // stack already has the needed state, more ops take longer to paint. - private int rule; - private float alpha; - private boolean interrupted; - - // Graphics stack for a page's content. - protected ArrayList shapes = new ArrayList(shapesInitialCapacity); - - // stores the state of the currently visible optional content. - protected OptionalContentState optionalContentState = new OptionalContentState(); - - // the collection of objects listening for page paint events - private Page parentPage; - - // text extraction data structure - private PageText pageText = new PageText(); - - public PageText getPageText() { - return pageText; - } - - /** - * Gets the number of shapes on the shapes stack. - * - * @return number of shapes on the stack - */ - public int getShapesCount() { - if (shapes != null) { - return shapes.size(); - } else { - return 0; - } - } - - public ArrayList getShapes() { - return shapes; - } - - public void add(ArrayList shapes) { - shapes.addAll(shapes); - } - - public void setPageParent(Page parent) { - parentPage = parent; - } - - public void add(DrawCmd drawCmd){ - - if (!(drawCmd instanceof FormDrawCmd)){ - shapes.add(drawCmd); - }else{ - shapes.add(drawCmd); - } - } - - public boolean isPaintAlpha() { - return paintAlpha; - } - - public void setPaintAlpha(boolean paintAlpha) { - this.paintAlpha = paintAlpha; - } - - - /** - * Paint the graphics stack to the graphics context - * - * @param g graphics context to paint to. - */ - public void paint(Graphics2D g) throws InterruptedException{ - try { - interrupted = false; - AffineTransform base = new AffineTransform(g.getTransform()); - Shape clip = g.getClip(); - - PaintTimer paintTimer = new PaintTimer(); - Shape previousShape = null; - - DrawCmd nextShape; - // for loops actually faster in this case. - for (int i = 0, max = shapes.size(); i < max; i++) { - // try and minimize interrupted checks, costly. - if (interrupted || (i % 1000 == 0 && Thread.currentThread().isInterrupted())) { - interrupted = false; - throw new InterruptedException("Page painting thread interrupted"); - } - - nextShape = shapes.get(i); - previousShape = nextShape.paintOperand(g, parentPage, - previousShape, clip, base, optionalContentState, paintAlpha, paintTimer); - } - } - catch (InterruptedException e){ - throw new InterruptedException(e.getMessage()); - } catch (Exception e) { - logger.log(Level.FINE, "Error painting shapes.", e); - } - } - - /** - * @deprecated use Thread.interrupt() instead. - */ - public void interruptPaint() { - interrupted = true; - } - - /** - * @deprecated use Thread.interrupt() instead. - */ - public boolean isInterrupted() { - return interrupted; - } - - /** - * Iterates over the Shapes objects extracting all Image objects. - * - * @return all images in a page's content, if any. - */ - public ArrayList getImages() { - ArrayList images = new ArrayList(); - for (Object object : shapes) { - if (object instanceof ImageDrawCmd) { - images.add(((ImageDrawCmd) object).getImage()); - } else if (object instanceof ShapesDrawCmd) { - images.addAll(((ShapesDrawCmd) object).getShapes().getImages()); - } - } - return images; - } - - /** - * Contracts the shapes ArrayList to the actual size of the elements - * it contains. - */ - public void contract() { - if (shapes != null) { - shapes.trimToSize(); - } - } - - public int getRule() { - return rule; - } - - public void setRule(int rule) { - this.rule = rule; - } - - public float getAlpha() { - return alpha; - } - - public void setAlpha(float alpha) { - this.alpha = alpha; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/SmoothScaledImageReference.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/SmoothScaledImageReference.java deleted file mode 100644 index 04bedcf312..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/SmoothScaledImageReference.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.ImageStream; -import org.icepdf.core.pobjects.ImageUtility; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.util.concurrent.FutureTask; -import java.util.logging.Logger; - -/** - * The SmoothScaledImageReference scales large images using the - * bufferedImage.getScaledInstance() method for colour imges and the - * a custom trilinear scale for black and white images. The scaled instance - * uses a minimum of memory and can improve clarity of some CCITTFax images. - * - * @since 5.0 - */ -public class SmoothScaledImageReference extends CachedImageReference { - - private static final Logger logger = - Logger.getLogger(ScaledImageReference.class.toString()); - - private static int maxImageWidth = 7000; - private static int maxImageHeight = 7000; - - static { - try { - maxImageWidth = - Integer.parseInt(Defs.sysProperty("org.icepdf.core.imageReference.smoothscaled.maxwidth", - String.valueOf(maxImageWidth))); - - maxImageHeight = - Integer.parseInt(Defs.sysProperty("org.icepdf.core.imageReference.smoothscaled.maxheight", - String.valueOf(maxImageHeight))); - } catch (NumberFormatException e) { - logger.warning("Error reading buffered scale factor"); - } - } - - // scaled image size. - private int width; - private int height; - - protected SmoothScaledImageReference(ImageStream imageStream, GraphicsState graphicsState, - Resources resources, int imageIndex, - Page page) { - super(imageStream, graphicsState, resources, imageIndex, page); - - // get eh original image width. - width = imageStream.getWidth(); - height = imageStream.getHeight(); - - // kick off a new thread to load the image, if not already in pool. - ImagePool imagePool = imageStream.getLibrary().getImagePool(); - if (useProxy && imagePool.get(reference) == null) { - futureTask = new FutureTask(this); - Library.executeImage(futureTask); - } else if (!useProxy && imagePool.get(reference) == null) { - image = call(); - } - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public BufferedImage call() { - BufferedImage image = null; - long start = System.nanoTime(); - try { - // get the stream image if need, otherwise scale what you have. - if (image == null) { - image = imageStream.getImage(graphicsState, resources); - if (width > maxImageWidth || height > maxImageHeight) { - return image; - } - } - if (image != null) { - // update the width height encase it as scaled during masking. - int width = image.getWidth(); - int height = image.getHeight(); - - // do image scaling on larger images. This improves the softness - // of some images that contains black and white text. - double imageScale = 1.0; - - // for device gray colour spaces use the trilinear scaling method - // to basically blur the image so it more easily read and less jagged. - if (imageStream.getColourSpace() != null && - imageStream.getColourSpace() instanceof DeviceGray) { - // catch type 3 fonts. - if ((width < 50 || height < 50)) { - imageScale = 0.90; - } - // smooth out everything else. - else { - imageScale = 0.99; - } - if (imageScale != 1.0) { - image = (BufferedImage) getTrilinearScaledInstance(image, - (int) Math.ceil(width * imageScale), - (int) Math.ceil(height * imageScale)); - } - } - // normal rgb scale as before, as the trilinear scale causes excessive blurring. - else { - if ((width >= 250 || height >= 250) && (width < 500 || height < 500)) { - imageScale = 0.90; - } else if ((width >= 500 || height >= 500) && (width < 1000 || height < 1000)) { - imageScale = 0.80; - } else if ((width >= 1000 || height >= 1000) && (width < 1500 || height < 1500)) { - imageScale = 0.70; - } else if ((width >= 1500 || height >= 1500) && (width < 2000 || height < 2000)) { - imageScale = 0.60; - } else if ((width >= 2000 || height >= 2000) && (width < 2500 || height < 2500)) { - imageScale = 0.50; - } else if ((width >= 2500 || height >= 2500) && (width < 3000 || height < 3000)) { - imageScale = 0.40; - } else if ((width >= 3000 || height >= 3000)) { - imageScale = 0.30; - } - if (imageScale != 1.0) { - AffineTransform tx = new AffineTransform(); - tx.scale(imageScale, imageScale); - AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BICUBIC); - BufferedImage sbim = op.filter(image, null); - image.flush(); - image = sbim; - } - } - } - } catch (Throwable e) { - logger.warning("Error loading image: " + imageStream.getPObjectReference() + - " " + imageStream.toString()); - } - long end = System.nanoTime(); - notifyImagePageEvents((end - start)); - return image; - } - - /** - * Applies an iterative scaling method to provide a smooth end result, once complete - * apply a trilinear blend based on the desired width and height. Technique - * derived from Jim Graham example code. - * - * @param img image to scale - * @param targetWidth target width - * @param targetHeight target height - * @return scaled instance. - */ - private static Image getTrilinearScaledInstance(BufferedImage img, - int targetWidth, - int targetHeight) { - // Use multi-step technique: start with original size, then - // scale down in multiple passes with drawImage() - // until the target size is reached - int iw = img.getWidth(); - int ih = img.getHeight(); - - Object hint = RenderingHints.VALUE_INTERPOLATION_BILINEAR; - int type = (img.getTransparency() == Transparency.OPAQUE) ? - BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB; - - // First get down to no more than 2x in W & H - while (iw > targetWidth * 2 || ih > targetHeight * 2) { - iw = (iw > targetWidth * 2) ? iw / 2 : iw; - ih = (ih > targetHeight * 2) ? ih / 2 : ih; - img = scaleImage(img, type, hint, iw, ih); - } - - // If still too wide - do a horizontal trilinear blend - // of img and a half-width img - if (iw > targetWidth) { - int iw2 = iw / 2; - BufferedImage img2 = scaleImage(img, type, hint, iw2, ih); - if (iw2 < targetWidth) { - img = scaleImage(img, type, hint, targetWidth, ih); - img2 = scaleImage(img2, type, hint, targetWidth, ih); - interpolate(img2, img, iw - targetWidth, targetWidth - iw2); - } - img = img2; - iw = targetWidth; - } - // iw should now be targetWidth or smaller - - // If still too tall - do a vertical trilinear blend - // of img and a half-height img - if (ih > targetHeight) { - int ih2 = ih / 2; - BufferedImage img2 = scaleImage(img, type, hint, iw, ih2); - if (ih2 < targetHeight) { - img = scaleImage(img, type, hint, iw, targetHeight); - img2 = scaleImage(img2, type, hint, iw, targetHeight); - interpolate(img2, img, ih - targetHeight, targetHeight - ih2); - } - img = img2; - ih = targetHeight; - } - // ih should now be targetHeight or smaller - - // If we are too small, then it was probably because one of - // the dimensions was too small from the start. - if (iw < targetWidth && ih < targetHeight) { - img = scaleImage(img, type, hint, targetWidth, targetHeight); - } - - return img; - } - - /** - * Utility to interpolate the two imges. - */ - private static void interpolate(BufferedImage img1, - BufferedImage img2, - int weight1, - int weight2) { - float alpha = weight1; - alpha /= (weight1 + weight2); - Graphics2D g2 = img1.createGraphics(); - g2.setComposite( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); - g2.drawImage(img2, 0, 0, null); - g2.dispose(); - } - - /** - * Utility to apply image scaling using the g2.drawImage() method. - */ - private static BufferedImage scaleImage(BufferedImage orig, - int type, - Object hint, - int w, int h) { - BufferedImage tmp = ImageUtility.createTranslucentCompatibleImage(w, h); - Graphics2D g2 = tmp.createGraphics(); - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint); - g2.drawImage(orig, 0, 0, w, h, null); - g2.dispose(); - return tmp; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/SoftMask.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/SoftMask.java deleted file mode 100644 index 27fdb73cb3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/SoftMask.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Form; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.functions.Function; -import org.icepdf.core.util.Library; - -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; - -/** - * Soft-mask Dictionary specifies the current soft mask in the graphics - * state. The mask values shall be derived from those of the transparency group, - * using one of the two methods in "11.5.2 Deriving a Soft Mask from Group Alpha", - * and "11.5.3 Deriving a Soft Mask from Group Luminosity". - *

      - * The S subtype entry shall specify which of the two derivation methods to use: - *

        - *
      • If the subtype is Alpha, the transparency group XObject G shall be - * evaluated to compute a group alpha only. The colours of the constituent - * objects shall be ignored and the colour compositing computations shall - * not be performed. The transfer function TR shall then be applied to the - * computed group alpha to produce the mask values. Outside the bounding box - * of the transparency group, the mask value shall be the result of applying - * the transfer function to the input value 0.0.
      • - *
      • If the subtype is Luminosity, the transparency group XObject G shall - * be composited with a fully opaque backdrop whose colour is everywhere - * defined by the soft-mask dictionary's BC entry. The computed result colour - * shall then be converted to a single-component luminosity value, and the - * transfer function TR shall be applied to this luminosity to produce the - * mask values. Outside the transparency group's bounding box, the mask value - * shall be derived by transforming the BC colour to luminosity and applying - * the transfer function to the result.
      • - *
      - */ -public class SoftMask extends Dictionary { - - private static final Logger logger = - Logger.getLogger(SoftMask.class.toString()); - - public static final Name S_KEY = new Name("S"); - public static final Name G_KEY = new Name("G"); - public static final Name BC_KEY = new Name("BC"); - public static final String SOFT_MASK_TYPE_ALPHA = "Alpha"; - public static final String SOFT_MASK_TYPE_LUMINOSITY = "Luminosity"; - - private Form softMask; - - public SoftMask(Library library, HashMap dictionary) { - super(library, dictionary); - } - - /** - * A subtype specifying the method to be used in deriving the mask values - * from the transparency group specified by the G entry: - *
        - *
      • Alpha - The group's computed alpha shall be used, disregarding - * its colour (see "Deriving a Soft Mask from Group Alpha").
      • - *
      • LuminosityThe group's computed colour shall be converted to a - * single-component luminosity value (see "Deriving a Soft Mask from - * Group Luminosity").
      • - *
      - * - * @return subtype of the soft-mask dictionary. - */ - public Name getS() { - return library.getName(entries, S_KEY); - } - - /** - * A transparency group XObject (see "Transparency Group XObjects") to be - * used as the source of alpha or colour values for deriving the mask. If - * the subtype S is Luminosity, the group attributes dictionary shall - * contain a CS entry defining the colour space in which the compositing - * computation is to be performed. - * - * @return Xobject associated with G, null otherwise. - */ - public Form getG() { - if (softMask != null) { - return softMask; - } - Object GKey = library.getObject(entries, G_KEY); - if (GKey != null && GKey instanceof Form) { - softMask = (Form) GKey; - softMask.init(); - return softMask; - } - return null; - } - - /** - * An array of component values specifying the colour to be used as the - * backdrop against which to composite the transparency group XObject G. - * This entry shall be consulted only if the subtype S is Luminosity. The - * array shall consist of n numbers, where n is the number of components in - * the colour space specified by the CS entry in the group attributes - * dictionary (see "Transparency Group XObjects"). - * Default value: the colour space's initial value, representing black. - * - * @return componet colours - */ - @SuppressWarnings("unchecked") - public List getBC() { - Object BCKey = library.getObject(entries, BC_KEY); - if (BCKey instanceof List) { - return (List) BCKey; - } - return null; - } - - // todo handle TR - /** - * (Optional) A function object (see "Functions") specifying the transfer - * function to be used in deriving the mask values. The function shall - * accept one input, the computed group alpha or luminosity (depending on - * the value of the subtype S), and shall return one output, the resulting - * mask value. The input shall be in the range 0.0 to 1.0. The computed - * output shall be in the range 0.0 to 1.0; if it falls outside this range, - * it shall be forced to the nearest valid value. The name Identitymay be - * specified in place of a function object to designate the identity - * function. Default value: Identity. - * - * Type: function or name. - */ - public Object getTR() { - Object object = library.getObject(entries, BC_KEY); - if (object != null) { - return Function.getFunction(library, object); - } - return null; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/TextSprite.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/TextSprite.java deleted file mode 100644 index 9df6002ade..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/TextSprite.java +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.fonts.FontFile; -import org.icepdf.core.pobjects.graphics.text.GlyphText; -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; - -/** - *

      This class represents text which will be rendered to the a graphics context. - * This class was created to act as a wrapper for painting text using the Phelphs - * font library as well as painting using java.awt.Font.

      - *

      - *

      Objects of this type are created by the content parser when "TJ" or "Tj" - * operands are encountered in a page's content stream. Each TextSprite object - * is comprised of a list of CharSprites which can be painted by the Shapes - * class at render time.

      - * - * @since 2.0 - */ -public class TextSprite { - - // ability to turn off optimized drawing for text. - private static boolean optimizedDrawingEnabled = - Defs.booleanProperty("org.icepdf.core.text.optimized", true); - - private final static boolean OPTIMIZED_DRAWING_TYPE_3_ENABLED = - Defs.booleanProperty("org.icepdf.core.text.optimized.type3", true); - - // child GlyphText objects - private ArrayList glyphTexts; - - // text bounds, including all child Glyph sprites, in glyph space - // this bound is used during painting to respect painting clip. - Rectangle2D.Float bounds; - - // space reference for where glyph - private AffineTransform graphicStateTransform; - private AffineTransform tmTransform; - - // stroke color - private Color strokeColor; - // the write - private int rmode; - // Font used to paint text - private FontFile font; - // font's resource name and size, used by PS writer. - private String fontName; - private int fontSize; - - private static final String TYPE_3 = "Type3"; - - /** - *

      Creates a new TextSprite object.

      - * - * @param font font used when painting glyphs. - * @param contentLength length of text content. - */ - public TextSprite(FontFile font, int contentLength, AffineTransform graphicStateTransform, AffineTransform tmTransform) { - glyphTexts = new ArrayList(contentLength); - // all glyphs in text share this ctm - this.graphicStateTransform = graphicStateTransform; - this.tmTransform = tmTransform; - this.font = font; - if (optimizedDrawingEnabled && !OPTIMIZED_DRAWING_TYPE_3_ENABLED) { - optimizedDrawingEnabled = !(font.getFormat() != null && font.getFormat().equals(TYPE_3)); - } - bounds = new Rectangle2D.Float(); - } - - /** - *

      Adds a new text char to the TextSprite which will pe painted at x, y under - * the current CTM

      - * - * @param cid cid to paint. - * @param unicode unicode representation of cid. - * @param x x-coordinate to paint. - * @param y y-coordinate to paint. - * @param width width of cid from font. - */ - public GlyphText addText(String cid, String unicode, float x, float y, float width) { - - // x,y must not chance as it will affect painting of the glyph, - // we can change the bounds of glyphBounds as this is what needs to be normalized - // to page space - // IMPORTANT: where working in Java Coordinates with any of the Font bounds - float w = width;//(float)stringBounds.getWidth(); - float h = (float) (font.getAscent() + font.getDescent()); - - double descent = font.getDescent(); - double ascent = font.getAscent(); - - if (h <= 0.0f) { - h = (float) (font.getMaxCharBounds().getHeight()); - } - if (w <= 0.0f) { - w = (float) font.getMaxCharBounds().getWidth(); - } - // zero height will not intersect with clip rectangle and maybe have visibility issues. - // we generally get here if the font.getAscent is zero and as a result must compensate. - if (h <= 0.0f) { - Rectangle2D bounds = font.getEstringBounds(cid, 0, 1); - if (bounds != null && bounds.getHeight() > 0) { - h = (float) bounds.getHeight(); - } else { - // match the width, as it will make text selection work a bit better. - h = font.getSize(); - } - if (ascent == 0) { - ascent = h; - } - } - - Rectangle2D.Float glyphBounds; - // irregular negative layout of text, need to create the bbox appropriately. - if (w < 0.0f || font.getSize() < 0) { - glyphBounds = new Rectangle2D.Float(x + width, y - (float) descent, -w, h); - }else{ - glyphBounds = new Rectangle2D.Float(x, y - (float) ascent, w, h); - } - - // add bounds to total text bounds. - bounds.add(glyphBounds); - - // create glyph and normalize bounds. - GlyphText glyphText = - new GlyphText(x, y, glyphBounds, cid, unicode); - glyphText.normalizeToUserSpace(graphicStateTransform, tmTransform); - glyphTexts.add(glyphText); - return glyphText; - } - - /** - * Gets the character bounds of each glyph found in the TextSprite. - * - * @return bounds in PDF coordinates of character bounds - */ - public ArrayList getGlyphSprites() { - return glyphTexts; - } - - public AffineTransform getGraphicStateTransform() { - return graphicStateTransform; - } - - /** - * Set the graphic state transform on all child sprites, This is used for - * xForm object parsing and text selection. There is no need to do this - * outside of the context parser. - * - * @param graphicStateTransform - */ - public void setGraphicStateTransform(AffineTransform graphicStateTransform) { - this.graphicStateTransform = graphicStateTransform; - for (GlyphText sprite : glyphTexts) { - sprite.normalizeToUserSpace(this.graphicStateTransform, tmTransform); - } - } - - /** - *

      Set the rmode for all the characters being in this object. Rmode can - * have the following values:

      - *
        - *
      • 0 - Fill text.
      • - *
      • 1 - Stroke text.
      • - *
      • 2 - fill, then stroke text.
      • - *
      • 3 - Neither fill nor stroke text (invisible).
      • - *
      • 4 - Fill text and add to path for clipping.
      • - *
      • 5 - Stroke text and add to path for clipping.
      • - *
      • 6 - Fill, then stroke text and add to path for clipping.
      • - *
      • 7 - Add text to path for clipping.
      • - *
      - * - * @param rmode valid rmode from 0-7 - */ - public void setRMode(int rmode) { - if (rmode >= 0) { - this.rmode = rmode; - } - } - - public String toString() { - StringBuilder text = new StringBuilder(glyphTexts.size()); - for (GlyphText glyphText : glyphTexts) { - text.append(glyphText.getUnicode()); - } - return text.toString(); - } - - public void setStrokeColor(Color color) { - strokeColor = color; - } - - /** - * Getst the bounds of the text that makes up this sprite. The bounds - * are defined PDF space and are relative to the current CTM. - * - * @return text sprites bounds. - */ - public Rectangle2D.Float getBounds() { - return bounds; - } - - /** - *

      Paints all the character elements in this TextSprite to the graphics - * context

      - * - * @param g graphics context to which the characters will be painted to. - */ - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - - // draw bounding box. -// drawBoundBox(g2d); - - for (GlyphText glyphText : glyphTexts) { - - // paint glyph - font.drawEstring(g2d, - glyphText.getCid(), - glyphText.getX(), glyphText.getY(), - FontFile.LAYOUT_NONE, rmode, strokeColor); - - // debug glyph box - // draw glyph box -// drawGyphBox(g2d, glyphText); - } - } - - /** - * Gets the glyph outline as an Area. This method is primarily used - * for processing text rendering modes 4 - 7. - * - * @return area representing the glyph outline. - */ - public Area getGlyphOutline() { - Area glyphOutline = null; - for (GlyphText glyphText : glyphTexts) { - if (glyphOutline != null) { - glyphOutline.add(new Area(font.getEstringOutline( - glyphText.getCid(), - glyphText.getX(), glyphText.getY()))); - } else { - glyphOutline = new Area(font.getEstringOutline( - glyphText.getCid(), - glyphText.getX(), glyphText.getY())); - } - } - return glyphOutline; - } - - public FontFile getFont() { - return font; - } - - public Color getStrokeColor() { - return strokeColor; - } - - public String getFontName() { - return fontName; - } - - public void setFontName(String fontName) { - this.fontName = fontName; - } - - public int getFontSize() { - return fontSize; - } - - public void setFontSize(int fontSize) { - this.fontSize = fontSize; - } - - /* - private void drawBoundBox(Graphics2D gg) { - - // draw the characters - GeneralPath charOutline; - - Color oldColor = gg.getColor(); - Stroke oldStroke = gg.getStroke(); - double scale = gg.getTransform().getScaleX(); - - scale = 1.0f / scale; - if (scale <= 0) { - scale = 1; - } - gg.setStroke(new BasicStroke((float) (scale))); - gg.setColor(Color.blue); - - charOutline = new GeneralPath(bounds); - gg.draw(charOutline); - - gg.setColor(oldColor); - gg.setStroke(oldStroke); - } - */ - - public void setFont(FontFile font) { - this.font = font; - } - /* - private void drawGyphBox(Graphics2D gg, GlyphText glyphSprite) { - - // draw the characters - GeneralPath charOutline; - - Color oldColor = gg.getColor(); - Stroke oldStroke = gg.getStroke(); - double scale = gg.getTransform().getScaleX(); - - scale = 1.0f / scale; - if (scale <= 0) { - scale = 1; - } - gg.setStroke(new BasicStroke((float) (scale))); - gg.setColor(Color.red); - - charOutline = new GeneralPath(glyphSprite.getBounds()); - gg.draw(charOutline); - - gg.setColor(oldColor); - gg.setStroke(oldStroke); - - } - - - */ - - /** - * Tests if the interior of the TextSprite bounds intersects the - * interior of a specified shape. - * - * @param shape shape to calculate intersection against - * @return true, if TextSprite bounds intersects shape; - * otherwise; false. - */ - public boolean intersects(Shape shape) { -// return shape.intersects(bounds.toJava2dCoordinates()); - return !(optimizedDrawingEnabled)|| - (shape != null && shape.intersects(bounds)); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/TextState.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/TextState.java deleted file mode 100644 index fa7c57772f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/TextState.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.PRectangle; -import org.icepdf.core.pobjects.fonts.Font; -import org.icepdf.core.pobjects.fonts.FontFile; - -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; - -/** - * The text state comprises those graphics state parameters that only affect text. - *

      - * Tc - Character spacing - * Tw - Word spacing - * Th - Horizontal scaling - * Tl - Leading Tf Text font - * Tfs - Text font size - * Tmode - Text rendering mode - * Trise - Text rise - * Tk - Text knockout - * - * @since 2.0 - */ -public class TextState { - - /** - * Fill text - */ - public static final int MODE_FILL = 0; - - /** - * Stroke text - */ - public static final int MODE_STROKE = 1; - /** - * Fill then stroke text. - */ - public static final int MODE_FILL_STROKE = 2; - /** - * Neither fill nor stroke text - */ - public static final int MODE_INVISIBLE = 3; - /** - * Fill text and add to path for clipping. - */ - public static final int MODE_FILL_ADD = 4; - /** - * Stroke text and add to path for clipping - */ - public static final int MODE_STROKE_ADD = 5; - /** - * Fill then stroke,text and add to path for clipping - */ - public static final int MODE_FILL_STROKE_ADD = 6; - - /** - * Add text to path for clipping - */ - public static final int MODE_ADD = 7; - - // type3 font text states for d1 token. - protected PRectangle type3BBox; - // type 3 font text state for d0 token. - protected Point2D.Float type3HorizontalDisplacement; - - /** - * Set the character spacing, Tc, to charSpace, which is a number expressed - * in unscaled text space units. Character spacing is used by the Tj, TJ, - * and ' operators. Initial value: 0. - */ - public float cspace; - /** - * Set the word spacing, Tw, to wordSpace, which is a number expressed in - * unscaled text space units. Word spacing is used by the Tj, TJ, and ' - * operators. Initial value: 0. - */ - public float wspace; - /** - * Set the horizontal scaling, Th, to (scale div 100). scale is a number - * specifying the percentage of the normal width. Initial value: 100 - * (normal width). - */ - public float hScalling; - /** - * Set the text leading, Tl, to leading, which is a number expressed in - * unscaled text space units. Text leading is used only by the T*, ', - * and " operators. Initial value: 0. - */ - public float leading; - /** - * Text Font size - */ - public float tsize; - - /** - * Font's named resource name. - */ - public Name fontName; - /** - * Set the text rendering mode, Tmode, to render, which is an integer. - * Initial value: 0. - */ - public int rmode; - /** - * Set the text rise, Trise, to rise, which is a number expressed in - * unscaled text space units. Initial value: 0. - */ - public float trise; - /** - * Transformation matrix defined by the Tm tag - */ - public AffineTransform tmatrix; - public AffineTransform tlmatrix; - /** - * Text Font - Associated ICEpdf font object - */ - public Font font; - /** - * Text Font - Associated awt font object for display purposes - */ - public FontFile currentfont; - - /** - * Create a new Instance of TextState - */ - public TextState() { - tmatrix = new AffineTransform(); - tlmatrix = new AffineTransform(); - hScalling = 1; - } - - /** - * Creat a new instance of TextState. All text state properties are copied - * from ts. - * - * @param ts text state to - */ - public TextState(TextState ts) { - // map properties - cspace = ts.cspace; - wspace = ts.wspace; - hScalling = ts.hScalling; - leading = ts.leading; - font = ts.font; - // create a new clone based on current font, cheap clone - currentfont = ts.currentfont != null ? - ts.currentfont.deriveFont(new AffineTransform()) : null; - tsize = ts.tsize; - tmatrix = new AffineTransform(ts.tmatrix); - tlmatrix = new AffineTransform(ts.tlmatrix); - rmode = ts.rmode; - trise = ts.trise; - } - - public PRectangle getType3BBox() { - return type3BBox; - } - - public void setType3BBox(PRectangle type3BBox) { - this.type3BBox = type3BBox; - } - - public Point2D.Float getType3HorizontalDisplacement() { - return type3HorizontalDisplacement; - } - - public void setType3HorizontalDisplacement(Point2D.Float type3HorizontalDisplacement) { - this.type3HorizontalDisplacement = type3HorizontalDisplacement; - } - -} - - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/TilingPattern.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/TilingPattern.java deleted file mode 100644 index a4470de369..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/TilingPattern.java +++ /dev/null @@ -1,629 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.io.SeekableInputConstrainedWrapper; -import org.icepdf.core.pobjects.ImageUtility; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.pobjects.Stream; -import org.icepdf.core.pobjects.graphics.commands.ColorDrawCmd; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.content.ContentParser; -import org.icepdf.core.util.content.ContentParserFactory; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      Tiling patterns consist of a small graphical figure (called a - * pattern cell) that is replicated at fixed horizontal and vertical - * intervals to fill the area to be painted. The graphics objects to - * use for tiling are described by a content stream. (PDF 1.2) - * - * @author ICEsoft Technologies Inc. - * @since 3.0 - */ -public class TilingPattern extends Stream implements Pattern { - - private static final Logger logger = - Logger.getLogger(TilingPattern.class.toString()); - - // max x or y dimension of an image tile. - public static final int MAX_BUFFER_SIZE = 9000; - - public static final Name PATTERNTYPE_KEY = new Name("PatternType"); - public static final Name PAINTTYPE_KEY = new Name("PaintType"); - public static final Name TILINGTYPE_KEY = new Name("TilingType"); - public static final Name BBOX_KEY = new Name("BBox"); - public static final Name XSTEP_KEY = new Name("XStep"); - public static final Name YSTEP_KEY = new Name("YStep"); - public static final Name MATRIX_KEY = new Name("Matrix"); - public static final Name RESOURCES_KEY = new Name("Resources"); - - // change the the interpolation and anti-aliasing settings. - private static RenderingHints renderingHints; - - static { - Object antiAliasing = RenderingHints.VALUE_ANTIALIAS_OFF; - Object interpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; - String property = Defs.sysProperty("org.icepdf.core.tiling.antiAliasing"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_ANTIALIAS_DEFAULT")) { - antiAliasing = RenderingHints.VALUE_ANTIALIAS_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_ANTIALIAS_ON")) { - antiAliasing = RenderingHints.VALUE_ANTIALIAS_ON; - } else if (property.equalsIgnoreCase("VALUE_ANTIALIAS_OFF")) { - antiAliasing = RenderingHints.VALUE_ANTIALIAS_OFF; - } - } - property = Defs.sysProperty("org.icepdf.core.tiling.interpolation"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_INTERPOLATION_BICUBIC")) { - interpolation = RenderingHints.VALUE_INTERPOLATION_BICUBIC; - } else if (property.equalsIgnoreCase("VALUE_INTERPOLATION_BILINEAR")) { - interpolation = RenderingHints.VALUE_INTERPOLATION_BILINEAR; - } else if (property.equalsIgnoreCase("VALUE_INTERPOLATION_NEAREST_NEIGHBOR")) { - interpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; - } - } - renderingHints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, - interpolation); - renderingHints.add(new RenderingHints(RenderingHints.KEY_ANTIALIASING, antiAliasing)); - } - - - // A code identifying the type of pattern that this dictionary describes - private int patternType; - // A code that determines how the color of the pattern cell is to be specified - private int paintType; - // uncolored tiling pattern colour, if specified. - private Color unColored; - - /** - * Colored tiling pattern. The pattern's content stream itself specifies the - * colors used to paint the pattern cell. When the content stream begins - * execution, the current color is the one that was initially in effect in - * the pattern's parent content stream. - */ - public static final int PAINTING_TYPE_COLORED_TILING_PATTERN = 1; - - /** - * Uncolored tiling pattern. The pattern's content stream does not specify - * any color information. Instead, the entire pattern cell is painted with a - * separately specified color each time the pattern is used. Essentially, - * the content stream describes a stencil through which the current color is - * to be poured. The content stream must not invoke operators that specify - * colors or other color-related parameters in the graphics state; - * otherwise, an error will occur - */ - public static final int PAINTING_TYPE_UNCOLORED_TILING_PATTERN = 2; - - // A code that controls adjustments to the spacing of tiles relative to the - // device pixel grid - private int tilingType; - // type of PObject, should always be "Pattern" - private Name type; - - /** - * Spacing of tiles relative to the device grid: Pattern cells are spaced - * consistently-that is, by a multiple of a device pixel. To achieve this, - * the viewer application may need to distort the pattern cell slightly by - * making small adjustments to XStep, YStep, and the transformation matrix. - * The amount of distortion does not exceed 1 device pixel. - */ - public static final int TILING_TYPE_CONSTANT_SPACING = 1; - - /** - * The pattern cell is not - * distorted, but the spacing between pattern cells may vary by as much as - * 1 device pixel, both horizontally and vertically, when the pattern is - * painted. This achieves the spacing requested by XStep and YStep on - * average, but not necessarily for each individual pattern cell. - */ - public static final int TILING_TYPE_NO_DISTORTION = 2; - - /** - * Pattern cells are spaced consistently as in tiling type 1, but with - * additional distortion permitted to enable a more efficient implementation. - */ - public static final int TILING_TYPE_CONSTANT_SPACING_FASTER = 3; - - // An array of four numbers in the pattern coordinate system giving the - // coordinates of the left, bottom, right, and top edges, respectively, of - // the pattern cell's bounding box. These boundaries are used to clip the - // pattern cell. - private Rectangle2D bBox; - private Rectangle2D bBoxMod; - // The desired horizontal spacing between pattern cells, measured in the - // pattern coordinate system. - private float xStep; - // The desired vertical spacing between pattern cells, measured in the - // pattern coordinate system. Note that XStep and YStep may differ from the - // dimensions of the pattern cell implied by the BBox entry. This allows - // tiling with irregularly shaped figures. XStep and YStep may be either - // positive or negative, but not zero. - private float yStep; - // A resource dictionary containing all of the named resources required by - // the pattern's content stream - private Resources resources; - // An array of six numbers specifying the pattern matrix. The default value - // is the identity matrix [1 0 0 1 0 0]. - private AffineTransform matrix; - private AffineTransform patternMatrix; - // Parsed resource data is stored here. - private Shapes shapes; - - // Fill colour - public Color fillColour; - - // initiated flag - private boolean inited; - - private GraphicsState parentGraphicState; - - public TilingPattern(Stream stream) { - super(stream.getLibrary(), stream.getEntries(), stream.getRawBytes()); - pObjectReference = stream.getPObjectReference(); - initiParams(); - } - - /** - * @param l - * @param h - * @param streamInputWrapper - */ - public TilingPattern(Library l, HashMap h, SeekableInputConstrainedWrapper streamInputWrapper) { - super(l, h, streamInputWrapper); - initiParams(); - } - - private void initiParams() { - type = library.getName(entries, TYPE_KEY); - - patternType = library.getInt(entries, PATTERNTYPE_KEY); - - paintType = library.getInt(entries, PAINTTYPE_KEY); - - tilingType = library.getInt(entries, TILINGTYPE_KEY); - - bBox = library.getRectangle(entries, BBOX_KEY); - - xStep = library.getFloat(entries, XSTEP_KEY); - - yStep = library.getFloat(entries, YSTEP_KEY); - - List v = (List) library.getObject(entries, MATRIX_KEY); - if (v != null) { - matrix = getAffineTransform(v); - } else { - // default is identity matrix - matrix = new AffineTransform(); - } - } - - public Name getType() { - return type; - } - - /** - * Utility method for parsing a vector of affine transform values to an - * affine transform. - * - * @param v vector containing affine transform values. - * @return affine tansform based on v - */ - private static AffineTransform getAffineTransform(List v) { - float f[] = new float[6]; - for (int i = 0; i < 6; i++) { - f[i] = ((Number) v.get(i)).floatValue(); - } - return new AffineTransform(f); - } - - /* - * Since tiling patterns are still not fully supported we need to make - * a best guess at which colour to use for stroking or non stroking - * operations - */ - - public Color getFirstColor() { - // find and cache first colour found in stack - if (shapes != null && unColored == null) { - for (int i = 0, max = shapes.shapes.size(); i < max; i++) { - if (shapes.shapes.get(i) instanceof ColorDrawCmd) { - ColorDrawCmd tmp = (ColorDrawCmd) shapes.shapes.get(i); - unColored = tmp.getColor(); - return unColored; - } - } - } - // if now shapes then we go with black. - if (unColored == null) { - unColored = Color.black; - return unColored; - } else { - return unColored; - } - } - - /** - * - */ - public synchronized void init(GraphicsState graphicsState) { - - if (inited) { - return; - } - inited = true; - - // try and find the form's resources dictionary. - Resources leafResources = library.getResources(entries, RESOURCES_KEY); - // apply resource for tiling if any, otherwise we use the default dictionary. - if (leafResources != null) { - resources = leafResources; - } - - if (paintType == PAINTING_TYPE_UNCOLORED_TILING_PATTERN) { - parentGraphicState.setFillColor(unColored); - parentGraphicState.setStrokeColor(unColored); - } - - // Build a new content parser for the content streams and apply the - // content stream of the calling content stream. - ContentParser cp = ContentParserFactory.getInstance() - .getContentParser(library, resources); - cp.setGraphicsState(parentGraphicState); - try { - shapes = cp.parse(new byte[][]{getDecodedStreamBytes()}, null).getShapes(); - } catch (Throwable e) { - logger.log(Level.FINE, "Error processing tiling pattern.", e); - } - - // some encoders set the step to 2^15 - if (xStep >= Short.MAX_VALUE) { - xStep = (float) bBox.getWidth(); - } - if (yStep >= Short.MAX_VALUE) { - yStep = (float) bBox.getHeight(); - } - // adjust the bBox so that xStep and yStep can be applied - // for tile spacing. - bBoxMod = new Rectangle2D.Double( - bBox.getX(), bBox.getY(), - bBox.getWidth() == xStep ? bBox.getWidth() : Math.round(xStep), - bBox.getHeight() == yStep ? bBox.getHeight() : Math.round(yStep)); - - // bbox is in the pattern coordinate system, so we'll convert it to the current user space. - // we start off with the base transform of the page or the xobject before any scaling or - // or other modifications takes place on the CTM. - patternMatrix = new AffineTransform(); - patternMatrix.concatenate(matrix); - GeneralPath tmp = new GeneralPath(bBoxMod); - bBoxMod = tmp.createTransformedShape(patternMatrix).getBounds2D(); - } - - /** - * Applies the pattern paint specified by this TilingPattern instance. - * Handles both uncoloured and coloured pattern types. - * - * @param g graphics context to apply textured paint too. - * @param base base transform before painting started, generally the page - * space transform of the page. - */ - public void paintPattern(Graphics2D g, final AffineTransform base) { - - // base represents the current page transform, zoom and rotation, - // the g.getTransform() will be the state of the current graphics - // state. The matrix however maps from the original page space to - // pattern space. As a result we need draw the tile pattern - // appropriately as to take into account the g.getTransform(), as - // we can't scale the pattern space easily. - - AffineTransform originalPageSpace; - AffineTransform context = new AffineTransform(); - try { - originalPageSpace = new AffineTransform(base); - context = g.getTransform().createInverse(); - originalPageSpace.concatenate(context); - } catch (NoninvertibleTransformException e) { - logger.warning("Error creating Tiling pattern transform. "); - originalPageSpace = new AffineTransform(); - } - - // scale to the current state of g2d. - Rectangle2D bBoxMod = originalPageSpace.createTransformedShape(this.bBoxMod).getBounds2D(); - - int width = (int) Math.round(bBoxMod.getWidth()); - int height = (int) Math.round(bBoxMod.getHeight()); - - double baseScale = 1.0f; - if ((width < 150 || height < 150) && base.getScaleX() >= 1) { - baseScale = base.getScaleX() * 2; - if (baseScale > 25) { - baseScale = 25; - } - } - - if (width < 1) { - width = 1; - } - if (height < 1) { - height = 1; - } - - // calculate the offset of the pattern so we paint it at the right coordinate, - // basically upside down revers. - double xOffset = (base.getTranslateX() - g.getTransform().getTranslateX()) * (1 / base.getScaleX()) - + matrix.getTranslateX(); - xOffset *= context.getScaleX() * base.getScaleX(); - if (Double.isNaN(xOffset)) xOffset = 0; - double yOffset = (base.getTranslateY() - g.getTransform().getTranslateY()) * (1 / -base.getScaleY()) - - matrix.getTranslateY(); - yOffset *= context.getScaleY() * -base.getScaleY(); - if (Double.isNaN(yOffset)) yOffset = 0; - // corner cases where some bBoxes don't have a dimension. - double imageWidth = width * baseScale; - double imageHeight = height * baseScale; - - // make sure we don't have too big an image. - if (imageWidth > MAX_BUFFER_SIZE){ - imageWidth = bBox.getWidth(); - } - if (imageHeight > MAX_BUFFER_SIZE){ - imageHeight = bBox.getHeight(); - } - - // create the new image to write too. - final BufferedImage bi = ImageUtility.createTranslucentCompatibleImage((int)Math.round(imageWidth), (int) Math.round(imageHeight)); - Graphics2D canvas = bi.createGraphics(); - - TexturePaint patternPaint = new TexturePaint(bi, new Rectangle2D.Double( - xOffset, yOffset, - width, height)); - g.setPaint(patternPaint); - - // apply current hints - canvas.setRenderingHints(renderingHints); - // copy over the rendering hints - // get shapes and paint them. - final Shapes tilingShapes = getShapes(); - - // add clip for bBoxMod, needed for some shapes painting. - canvas.setClip(0, 0, (int) imageWidth, (int) imageHeight); - - // paint the pattern - try { - paintPattern(canvas, tilingShapes, matrix, originalPageSpace, baseScale); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.log(Level.FINE, "Error painting tiling pattern.", e); - } - - // show it in a frame -// final JFrame f = new JFrame(this.toString()); -// final int w = (int) bBoxMod.getWidth(); -// final int h = (int) bBoxMod.getHeight(); -// final double scale = base.getScaleX(); -// final AffineTransform tmpPatternMatrix = originalPageSpace; -// f.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); -// f.getContentPane().add(new JComponent() { -// @Override -// public void paint(Graphics g_) { -// super.paint(g_); -// Graphics2D g2d = (Graphics2D) g_; -// g2d.scale(scale, scale); -// g2d.setPaint(patternPaint); -// g2d.fillRect(0, 0, 1000, 1000); -// } -// }); -// f.setSize(new Dimension(800, 800)); -// f.setVisible(true); - // post paint cleanup - canvas.dispose(); - bi.flush(); - } - - private void paintPattern(Graphics2D g2d, Shapes tilingShapes, AffineTransform matrix, AffineTransform base, - double scale) throws InterruptedException { - - // store previous state so we can draw bounds - AffineTransform preAf = g2d.getTransform(); - - // apply scale an shear but not translation - AffineTransform af = new AffineTransform(matrix); - AffineTransform af2 = new AffineTransform(base); - af2.concatenate(af); - af2 = new AffineTransform( - af2.getScaleX(), - af2.getShearY(), - af2.getShearX(), - af2.getScaleY(), - 0, - 0); - g2d.setTransform(af2); - g2d.scale(scale, scale); - // pain the key pattern - AffineTransform prePaint = g2d.getTransform(); - tilingShapes.paint(g2d); - g2d.setTransform(prePaint); - -// g2d.setStroke(new BasicStroke(1)); -// g2d.setColor(Color.GREEN); -// g2d.drawRect(1, 1, (int) bBox.getWidth() - 3, (int) bBox.getHeight() - 3); -// g2d.setColor(Color.RED); -// g2d.draw(bBox); -// g2d.drawRect(1, 1, 5, 5); - - // build the the tile - g2d.translate(xStep, 0); - prePaint = g2d.getTransform(); - tilingShapes.paint(g2d); - g2d.setTransform(prePaint); - - g2d.translate(0, -yStep); - prePaint = g2d.getTransform(); - tilingShapes.paint(g2d); - g2d.setTransform(prePaint); - - g2d.translate(-xStep, 0); - prePaint = g2d.getTransform(); - tilingShapes.paint(g2d); - g2d.setTransform(prePaint); - - g2d.translate(-xStep, 0); - prePaint = g2d.getTransform(); - tilingShapes.paint(g2d); - g2d.setTransform(prePaint); - - g2d.translate(0, yStep); - prePaint = g2d.getTransform(); - tilingShapes.paint(g2d); - g2d.setTransform(prePaint); - - g2d.translate(0, yStep); - prePaint = g2d.getTransform(); - tilingShapes.paint(g2d); - g2d.setTransform(prePaint); - - g2d.translate(xStep, 0); - prePaint = g2d.getTransform(); - tilingShapes.paint(g2d); - g2d.setTransform(prePaint); - - g2d.translate(xStep, 0); - tilingShapes.paint(g2d); - - g2d.setTransform(preAf); - } - - - public Paint getPaint() { - return null; - } - - public int getPatternType() { - return patternType; - } - - public void setPatternType(int patternType) { - this.patternType = patternType; - } - - public int getPaintType() { - return paintType; - } - - public void setPaintType(int paintType) { - this.paintType = paintType; - } - - public int getTilingType() { - return tilingType; - } - - public void setTilingType(int tilingType) { - this.tilingType = tilingType; - } - - public Rectangle2D getBBox() { - return bBox; - } - - /** - * Bbox converted to user space. - * - * @return bBox converted to user space. - */ - public Rectangle2D getbBoxMod() { - return bBoxMod; - } - - public float getXStep() { - return xStep; - } - - public float getYStep() { - return yStep; - } - - public AffineTransform getMatrix() { - return matrix; - } - - public AffineTransform getInvMatrix() { - try { - return matrix.createInverse(); - } catch (NoninvertibleTransformException e) { - - } - return null; - } - - public void setMatrix(AffineTransform matrix) { - this.matrix = matrix; - } - - public Shapes getShapes() { - return shapes; - } - - public void setShapes(Shapes shapes) { - this.shapes = shapes; - } - - - public void setParentGraphicState(GraphicsState graphicsState) { - this.parentGraphicState = graphicsState; - } - - public GraphicsState getParentGraphicState() { - return parentGraphicState; - } - - public Color getUnColored() { - return unColored; - } - - public void setUnColored(Color unColored) { - this.unColored = unColored; - } - - /** - * @return - */ - public String toString() { - return "Tiling Pattern: \n" + - " obj: " + this.getPObjectReference() + - "\n patternType: tilling" + - "\n paintType: " + (paintType == PAINTING_TYPE_COLORED_TILING_PATTERN ? "colored" : "uncoloured") + - "\n tilingType: " + tilingType + - "\n bbox: " + bBox + - "\n xStep: " + xStep + - "\n yStep: " + yStep + - "\n resource: " + resources + - "\n matrix: " + matrix; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/WatermarkCallback.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/WatermarkCallback.java deleted file mode 100644 index e2007a84a7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/WatermarkCallback.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics; - -import org.icepdf.core.pobjects.Page; - -import java.awt.*; - -/** - * WatermarkCallback allows a user to set a default watermark at the document - * level which will be applied at paint time for print and/or screen. The callback - * can be added to the Document class or on a page by page bases. - *

      - * The renderingHintType can be used to detect two different output modes; - * GraphicsRenderingHints.PRINT and GraphicsRenderingHints.SCREEN. - *

      - * Note: be careful not to hold a reference to the Page object as an - * an instance of the class as a memory leak may result. - * - * @since 5.1.0 - */ -public interface WatermarkCallback { - - /** - * Paints a watermark on top of the pages content. - * - * @param g graphics content used to paint the page content. - * @param page page that is being page. - * @param renderHintType rendering hints, SCREEN or PRINT - * @param boundary boundary box used to paint the page content. - * @param userRotation user rotation specified to paint page content - * @param userZoom user zoom specified to paint page content. - */ - void paintWatermark(Graphics g, Page page, int renderHintType, final int boundary, - float userRotation, float userZoom); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/LinearGradientPaint.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/LinearGradientPaint.java deleted file mode 100644 index 81bd34e368..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/LinearGradientPaint.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.graphics.batik.ext.awt; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.ColorModel; - -/** - * The LinearGradientPaint class provides a way to fill - * a {@link java.awt.Shape} with a linear color gradient pattern. The user may - * specify 2 or more gradient colors, and this paint will provide an - * interpolation between each color. The user also specifies start and end - * points which define where in user space the color gradient should begin - * and end. - *

      - * The user must provide an array of floats specifying how to distribute the - * colors along the gradient. These values should range from 0.0 to 1.0 and - * act like keyframes along the gradient (they mark where the gradient should - * be exactly a particular color). - *

      - * For example: - *
      - * - *

      - * Point2D start = new Point2D.Float(0, 0);
      - * Point2D end = new Point2D.Float(100,100);
      - * float[] dist = {0.0, 0.2, 1.0};
      - * Color[] colors = {Color.red, Color.white, Color.blue};
      - * LinearGradientPaint p = new LinearGradientPaint(start, end, dist, colors); - *
      - *

      - * This code will create a LinearGradientPaint which interpolates between - * red and white for the first 20% of the gradient and between white and blue - * for the remaining 80%. - *

      - *

      In the event that the user does not set the first keyframe value equal - * to 0 and the last keyframe value equal to 1, keyframes will be created at - * these positions and the first and last colors will be replicated there. - * So, if a user specifies the following arrays to construct a gradient:
      - * {Color.blue, Color.red}, {.3, .7}
      - * this will be converted to a gradient with the following keyframes: - * {Color.blue, Color.blue, Color.red, Color.red}, {0, .3, .7, 1} - *

      - *

      - * The user may also select what action the LinearGradientPaint should take - * when filling color outside the start and end points. If no cycle method is - * specified, NO_CYCLE will be chosen by default, so the endpoint colors - * will be used to fill the remaining area. - *

      - *

      The following image demonstrates the options NO_CYCLE and REFLECT. - *

      - *

      - * - *

      - *

      The colorSpace parameter allows the user to specify in which colorspace - * the interpolation should be performed, default sRGB or linearized RGB. - * - * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans - * @author Vincent Hardy - * @version $Id: LinearGradientPaint.java,v 1.1 2008/09/30 20:44:16 patrickc Exp $ - * @see java.awt.Paint - * @see java.awt.Graphics2D#setPaint - */ -public final class LinearGradientPaint extends MultipleGradientPaint { - - /** - * Gradient start and end points. - */ - private Point2D start, end; - - /** - * Constructs an LinearGradientPaint with the default - * NO_CYCLE repeating method and SRGB colorspace. - * - * @param startX the x coordinate of the gradient axis start point - * in user space - * @param startY the y coordinate of the gradient axis start point - * in user space - * @param endX the x coordinate of the gradient axis end point - * in user space - * @param endY the y coordinate of the gradient axis end point - * in user space - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors corresponding to each fractional value - * @throws IllegalArgumentException if start and end points are the - * same points, or if fractions.length != colors.length, or if colors - * is less than 2 in size. - */ - public LinearGradientPaint(float startX, float startY, - float endX, float endY, - float[] fractions, Color[] colors) { - - this(new Point2D.Float(startX, startY), - new Point2D.Float(endX, endY), - fractions, - colors, - NO_CYCLE, - SRGB); - } - - /** - * Constructs an LinearGradientPaint with default SRGB - * colorspace. - * - * @param startX the x coordinate of the gradient axis start point - * in user space - * @param startY the y coordinate of the gradient axis start point - * in user space - * @param endX the x coordinate of the gradient axis end point - * in user space - * @param endY the y coordinate of the gradient axis end point - * in user space - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors corresponding to each fractional value - * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT - * @throws IllegalArgumentException if start and end points are the - * same points, or if fractions.length != colors.length, or if colors - * is less than 2 in size. - */ - public LinearGradientPaint(float startX, float startY, - float endX, float endY, - float[] fractions, Color[] colors, - CycleMethodEnum cycleMethod) { - this(new Point2D.Float(startX, startY), - new Point2D.Float(endX, endY), - fractions, - colors, - cycleMethod, - SRGB); - } - - /** - * Constructs a LinearGradientPaint with the default - * NO_CYCLE repeating method and SRGB colorspace. - * - * @param start the gradient axis start Point in user space - * @param end the gradient axis end Point in user space - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors corresponding to each fractional value - * @throws NullPointerException if one of the points is null - * @throws IllegalArgumentException if start and end points are the - * same points, or if fractions.length != colors.length, or if colors - * is less than 2 in size. - */ - public LinearGradientPaint(Point2D start, Point2D end, float[] fractions, - Color[] colors) { - - this(start, end, fractions, colors, NO_CYCLE, SRGB); - } - - /** - * Constructs a LinearGradientPaint. - * - * @param start the gradient axis start Point in user space - * @param end the gradient axis end Point in user space - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors corresponding to each fractional value - * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT - * @param colorSpace which colorspace to use for interpolation, - * either SRGB or LINEAR_RGB - * @throws NullPointerException if one of the points is null - * @throws IllegalArgumentException if start and end points are the - * same points, or if fractions.length != colors.length, or if colors - * is less than 2 in size. - */ - public LinearGradientPaint(Point2D start, Point2D end, float[] fractions, - Color[] colors, - CycleMethodEnum cycleMethod, - ColorSpaceEnum colorSpace) { - - this(start, end, fractions, colors, cycleMethod, colorSpace, - new AffineTransform()); - - } - - /** - * Constructs a LinearGradientPaint. - * - * @param start the gradient axis start Point in user space - * @param end the gradient axis end Point in user space - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors corresponding to each fractional value - * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT - * @param colorSpace which colorspace to use for interpolation, - * either SRGB or LINEAR_RGB - * @param gradientTransform transform to apply to the gradient - * @throws NullPointerException if one of the points is null, - * or gradientTransform is null - * @throws IllegalArgumentException if start and end points are the - * same points, or if fractions.length != colors.length, or if colors - * is less than 2 in size. - */ - public LinearGradientPaint(Point2D start, Point2D end, float[] fractions, - Color[] colors, - CycleMethodEnum cycleMethod, - ColorSpaceEnum colorSpace, - AffineTransform gradientTransform) { - super(fractions, colors, cycleMethod, colorSpace, gradientTransform); - - // - // Check input parameters - // - if (start == null || end == null) { - throw new NullPointerException("Start and end points must be" + - "non-null"); - } - - if (start.equals(end)) { - throw new IllegalArgumentException("Start point cannot equal" + - "endpoint"); - } - - //copy the points... - this.start = (Point2D) start.clone(); - - this.end = (Point2D) end.clone(); - - } - - /** - * Creates and returns a PaintContext used to generate the color pattern, - * for use by the internal rendering engine. - * - * @param cm {@link ColorModel} that receives - * the Paint data. This is used only as a hint. - * @param deviceBounds the device space bounding box of the - * graphics primitive being rendered - * @param userBounds the user space bounding box of the - * graphics primitive being rendered - * @param transform the {@link AffineTransform} from user - * space into device space - * @param hints the hints that the context object uses to choose - * between rendering alternatives - * @return the {@link PaintContext} that generates color patterns. - * @see PaintContext - */ - public PaintContext createContext(ColorModel cm, - Rectangle deviceBounds, - Rectangle2D userBounds, - AffineTransform transform, - RenderingHints hints) { - - // Can't modify the transform passed in... - transform = new AffineTransform(transform); - //incorporate the gradient transform - transform.concatenate(gradientTransform); - - try { - return new LinearGradientPaintContext(cm, - deviceBounds, - userBounds, - transform, - hints, - start, - end, - fractions, - this.getColors(), - cycleMethod, - colorSpace); - } catch (NoninvertibleTransformException e) { - throw new IllegalArgumentException("transform should be" + - "invertible"); - } - } - - /** - * Returns a copy of the start point of the gradient axis - * - * @return a {@link Point2D} object that is a copy of the point - * that anchors the first color of this - * LinearGradientPaint. - */ - public Point2D getStartPoint() { - return new Point2D.Double(start.getX(), start.getY()); - } - - /** - * Returns a copy of the end point of the gradient axis - * - * @return a {@link Point2D} object that is a copy of the point - * that anchors the last color of this - * LinearGradientPaint. - */ - public Point2D getEndPoint() { - return new Point2D.Double(end.getX(), end.getY()); - } - -} - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/LinearGradientPaintContext.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/LinearGradientPaintContext.java deleted file mode 100644 index 489b67ffcb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/LinearGradientPaintContext.java +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.graphics.batik.ext.awt; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.ColorModel; - -/** - * Provides the actual implementation for the LinearGradientPaint - * This is where the pixel processing is done. - * - * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans - * @author Vincent Hardy - * @version $Id: LinearGradientPaintContext.java,v 1.1 2008/09/30 20:44:16 patrickc Exp $ - * @see java.awt.PaintContext - * @see java.awt.Paint - * @see java.awt.GradientPaint - */ -final class LinearGradientPaintContext extends MultipleGradientPaintContext { - - /** - * The following invariants are used to process the gradient value from - * a device space coordinate, (X, Y): - * g(X, Y) = dgdX*X + dgdY*Y + gc - */ - private float dgdX, dgdY, gc, pixSz; - - private static final int DEFAULT_IMPL = 1; - private static final int ANTI_ALIAS_IMPL = 3; - - private int fillMethod; - - /** - * Constructor for LinearGradientPaintContext. - * - * @param cm {@link ColorModel} that receives - * the Paint data. This is used only as a hint. - * @param deviceBounds the device space bounding box of the - * graphics primitive being rendered - * @param userBounds the user space bounding box of the - * graphics primitive being rendered - * @param t the {@link AffineTransform} from user - * space into device space (gradientTransform should be - * concatenated with this) - * @param hints the hints that the context object uses to choose - * between rendering alternatives - * @param dStart gradient start point, in user space - * @param dEnd gradient end point, in user space - * @param fractions the fractions specifying the gradient distribution - * @param colors the gradient colors - * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT - * @param colorSpace which colorspace to use for interpolation, - * either SRGB or LINEAR_RGB - */ - public LinearGradientPaintContext(ColorModel cm, - Rectangle deviceBounds, - Rectangle2D userBounds, - AffineTransform t, - RenderingHints hints, - Point2D dStart, - Point2D dEnd, - float[] fractions, - Color[] colors, - MultipleGradientPaint.CycleMethodEnum - cycleMethod, - MultipleGradientPaint.ColorSpaceEnum - colorSpace) - throws NoninvertibleTransformException { - super(cm, deviceBounds, userBounds, t, hints, fractions, - colors, cycleMethod, colorSpace); - - // Use single precision floating points - Point2D.Float start = new Point2D.Float((float) dStart.getX(), - (float) dStart.getY()); - Point2D.Float end = new Point2D.Float((float) dEnd.getX(), - (float) dEnd.getY()); - - // A given point in the raster should take on the same color as its - // projection onto the gradient vector. - // Thus, we want the projection of the current position vector - // onto the gradient vector, then normalized with respect to the - // length of the gradient vector, giving a value which can be mapped into - // the range 0-1. - // projection = currentVector dot gradientVector / length(gradientVector) - // normalized = projection / length(gradientVector) - - float dx = end.x - start.x; // change in x from start to end - float dy = end.y - start.y; // change in y from start to end - float dSq = dx * dx + dy * dy; // total distance squared - - //avoid repeated calculations by doing these divides once. - float constX = dx / dSq; - float constY = dy / dSq; - - //incremental change along gradient for +x - dgdX = a00 * constX + a10 * constY; - //incremental change along gradient for +y - dgdY = a01 * constX + a11 * constY; - - float dgdXAbs = Math.abs(dgdX); - float dgdYAbs = Math.abs(dgdY); - if (dgdXAbs > dgdYAbs) pixSz = dgdXAbs; - else pixSz = dgdYAbs; - - //constant, incorporates the translation components from the matrix - gc = (a02 - start.x) * constX + (a12 - start.y) * constY; - - Object colorRend = hints.get(RenderingHints.KEY_COLOR_RENDERING); - Object rend = hints.get(RenderingHints.KEY_RENDERING); - - fillMethod = DEFAULT_IMPL; - - if ((cycleMethod == MultipleGradientPaint.REPEAT) || - hasDiscontinuity) { - if (rend == RenderingHints.VALUE_RENDER_QUALITY) - fillMethod = ANTI_ALIAS_IMPL; - // ColorRend overrides rend. - if (colorRend == RenderingHints.VALUE_COLOR_RENDER_SPEED) - fillMethod = DEFAULT_IMPL; - else if (colorRend == RenderingHints.VALUE_COLOR_RENDER_QUALITY) - fillMethod = ANTI_ALIAS_IMPL; - } - } - - protected void fillHardNoCycle(int[] pixels, int off, int adjust, - int x, int y, int w, int h) { - - //constant which can be pulled out of the inner loop - final float initConst = (dgdX * x) + gc; - - for (int i = 0; i < h; i++) { //for every row - //initialize current value to be start. - float g = initConst + dgdY * (y + i); - final int rowLimit = off + w; // end of row iteration - - if (dgdX == 0) { - // System.out.println("In fillHard: " + g); - final int val; - if (g <= 0) - val = gradientUnderflow; - else if (g >= 1) - val = gradientOverflow; - else { - // Could be a binary search... - int gradIdx = 0; - while (gradIdx < gradientsLength - 1) { - if (g < fractions[gradIdx + 1]) - break; - gradIdx++; - } - float delta = (g - fractions[gradIdx]); - float idx = ((delta * GRADIENT_SIZE_INDEX) - / normalizedIntervals[gradIdx]) + 0.5f; - val = gradients[gradIdx][(int) idx]; - } - - while (off < rowLimit) { - pixels[off++] = val; - } - } else { - // System.out.println("In fillHard2: " + g); - int gradSteps; - int preGradSteps; - final int preVal, postVal; - - float gradStepsF; - float preGradStepsF; - if (dgdX >= 0) { - gradStepsF = ((1 - g) / dgdX); - preGradStepsF = (float) Math.ceil((0 - g) / dgdX); - preVal = gradientUnderflow; - postVal = gradientOverflow; - } else { // dgdX < 0 - gradStepsF = ((0 - g) / dgdX); - preGradStepsF = (float) Math.ceil((1 - g) / dgdX); - preVal = gradientOverflow; - postVal = gradientUnderflow; - } - - if (gradStepsF > w) gradSteps = w; - else gradSteps = (int) gradStepsF; - if (preGradStepsF > w) preGradSteps = w; - else preGradSteps = (int) preGradStepsF; - - final int gradLimit = off + gradSteps; - if (preGradSteps > 0) { - final int preGradLimit = off + preGradSteps; - - while (off < preGradLimit) { - pixels[off++] = preVal; - } - g += dgdX * preGradSteps; - } - - if (dgdX > 0) { - // Could be a binary search... - int gradIdx = 0; - while (gradIdx < gradientsLength - 1) { - if (g < fractions[gradIdx + 1]) - break; - gradIdx++; - } - - while (off < gradLimit) { - float delta = (g - fractions[gradIdx]); - final int[] grad = gradients[gradIdx]; - - double stepsD = Math.ceil - ((fractions[gradIdx + 1] - g) / dgdX); - int steps; - if (stepsD > w) steps = w; - else steps = (int) stepsD; - int subGradLimit = off + steps; - if (subGradLimit > gradLimit) - subGradLimit = gradLimit; - - int idx = (int) (((delta * GRADIENT_SIZE_INDEX) - / normalizedIntervals[gradIdx]) - * (1 << 16)) + (1 << 15); - int step = (int) (((dgdX * GRADIENT_SIZE_INDEX) - / normalizedIntervals[gradIdx]) - * (1 << 16)); - while (off < subGradLimit) { - pixels[off++] = grad[idx >> 16]; - idx += step; - } - g += dgdX * stepsD; - gradIdx++; - } - } else { - // Could be a binary search... - int gradIdx = gradientsLength - 1; - while (gradIdx > 0) { - if (g > fractions[gradIdx]) - break; - gradIdx--; - } - - while (off < gradLimit) { - float delta = (g - fractions[gradIdx]); - final int[] grad = gradients[gradIdx]; - - double stepsD = Math.ceil(delta / -dgdX); - int steps; - if (stepsD > w) steps = w; - else steps = (int) stepsD; - int subGradLimit = off + steps; - if (subGradLimit > gradLimit) - subGradLimit = gradLimit; - - int idx = (int) (((delta * GRADIENT_SIZE_INDEX) - / normalizedIntervals[gradIdx]) - * (1 << 16)) + (1 << 15); - int step = (int) (((dgdX * GRADIENT_SIZE_INDEX) - / normalizedIntervals[gradIdx]) - * (1 << 16)); - while (off < subGradLimit) { - pixels[off++] = grad[idx >> 16]; - idx += step; - } - g += dgdX * stepsD; - gradIdx--; - } - } - - while (off < rowLimit) { - pixels[off++] = postVal; - } - } - off += adjust; //change in off from row to row - } - } - - protected void fillSimpleNoCycle(int[] pixels, int off, int adjust, - int x, int y, int w, int h) { - //constant which can be pulled out of the inner loop - final float initConst = (dgdX * x) + gc; - final float step = dgdX * fastGradientArraySize; - final int fpStep = (int) (step * (1 << 16)); // fix point step - - final int[] grad = gradient; - - for (int i = 0; i < h; i++) { //for every row - //initialize current value to be start. - float g = initConst + dgdY * (y + i); - g *= fastGradientArraySize; - g += 0.5; // rounding factor... - - final int rowLimit = off + w; // end of row iteration - - float check = dgdX * fastGradientArraySize * w; - if (check < 0) check = -check; - if (check < .3) { - // System.out.println("In fillSimpleNC: " + g); - final int val; - if (g <= 0) - val = gradientUnderflow; - else if (g >= fastGradientArraySize) - val = gradientOverflow; - else - val = grad[(int) g]; - while (off < rowLimit) { - pixels[off++] = val; - } - } else { - // System.out.println("In fillSimpleNC2: " + g); - int gradSteps; - int preGradSteps; - final int preVal, postVal; - if (dgdX > 0) { - gradSteps = (int) ((fastGradientArraySize - g) / step); - preGradSteps = (int) Math.ceil(0 - g / step); - preVal = gradientUnderflow; - postVal = gradientOverflow; - - } else { // dgdX < 0 - gradSteps = (int) ((0 - g) / step); - preGradSteps = - (int) Math.ceil((fastGradientArraySize - g) / step); - preVal = gradientOverflow; - postVal = gradientUnderflow; - } - - if (gradSteps > w) - gradSteps = w; - final int gradLimit = off + gradSteps; - - if (preGradSteps > 0) { - if (preGradSteps > w) - preGradSteps = w; - final int preGradLimit = off + preGradSteps; - - while (off < preGradLimit) { - pixels[off++] = preVal; - } - g += step * preGradSteps; - } - - int fpG = (int) (g * (1 << 16)); - while (off < gradLimit) { - pixels[off++] = grad[fpG >> 16]; - fpG += fpStep; - } - - while (off < rowLimit) { - pixels[off++] = postVal; - } - } - off += adjust; //change in off from row to row - } - } - - protected void fillSimpleRepeat(int[] pixels, int off, int adjust, - int x, int y, int w, int h) { - - final float initConst = (dgdX * x) + gc; - - // Limit step to fractional part of - // fastGradientArraySize (the non fractional part has - // no affect anyways, and would mess up lots of stuff - // below). - float step = (dgdX - (int) dgdX) * fastGradientArraySize; - - // Make it a Positive step (a small negative step is - // the same as a positive step slightly less than - // fastGradientArraySize. - if (step < 0) - step += fastGradientArraySize; - - final int[] grad = gradient; - - for (int i = 0; i < h; i++) { //for every row - //initialize current value to be start. - float g = initConst + dgdY * (y + i); - - // now Limited between -1 and 1. - g = g - (int) g; - // put in the positive side. - if (g < 0) - g += 1; - - // scale for gradient array... - g *= fastGradientArraySize; - g += 0.5; // rounding factor - final int rowLimit = off + w; // end of row iteration - while (off < rowLimit) { - int idx = (int) g; - if (idx >= fastGradientArraySize) { - g -= fastGradientArraySize; - idx -= fastGradientArraySize; - } - pixels[off++] = grad[idx]; - g += step; - } - - off += adjust; //change in off from row to row - } - } - - protected void fillSimpleReflect(int[] pixels, int off, int adjust, - int x, int y, int w, int h) { - final float initConst = (dgdX * x) + gc; - - final int[] grad = gradient; - - for (int i = 0; i < h; i++) { //for every row - //initialize current value to be start. - float g = initConst + dgdY * (y + i); - - // now limited g to -2<->2 - g = g - 2 * ((int) (g / 2.0f)); - - float step = dgdX; - // Pull it into the positive half - if (g < 0) { - g = -g; //take absolute value - step = -step; // Change direction.. - } - - // Now do the same for dgdX. This is safe because - // any step that is a multiple of 2.0 has no - // affect, hence we can remove it which the first - // part does. The second part simply adds 2.0 - // (which has no affect due to the cylcle) to move - // all negative step values into the positive - // side. - step = step - 2 * ((int) step / 2.0f); - if (step < 0) - step += 2.0; - final int reflectMax = 2 * fastGradientArraySize; - - // Scale for gradient array. - g *= fastGradientArraySize; - g += 0.5; - step *= fastGradientArraySize; - final int rowLimit = off + w; // end of row iteration - while (off < rowLimit) { - int idx = (int) g; - if (idx >= reflectMax) { - g -= reflectMax; - idx -= reflectMax; - } - - if (idx <= fastGradientArraySize) - pixels[off++] = grad[idx]; - else - pixels[off++] = grad[reflectMax - idx]; - g += step; - } - - off += adjust; //change in off from row to row - } - } - - /** - * Return a Raster containing the colors generated for the graphics - * operation. This is where the area is filled with colors distributed - * linearly. - * - * @param x The x coordinate of the area in device space for which colors - * are generated. - * @param y The y coordinate of the area in device space for which colors - * are generated. - * @param w The width of the area in device space for which colors - * are generated. - * @param h The height of the area in device space for which colors - * are generated. - */ - protected void fillRaster(int[] pixels, int off, int adjust, - int x, int y, int w, int h) { - - //constant which can be pulled out of the inner loop - final float initConst = (dgdX * x) + gc; - - if (fillMethod == ANTI_ALIAS_IMPL) { - //initialize current value to be start. - for (int i = 0; i < h; i++) { //for every row - float g = initConst + dgdY * (y + i); - - final int rowLimit = off + w; // end of row iteration - while (off < rowLimit) { //for every pixel in this row. - //get the color - pixels[off++] = indexGradientAntiAlias(g, pixSz); - g += dgdX; //incremental change in g - } - off += adjust; //change in off from row to row - } - } else if (!isSimpleLookup) { - if (cycleMethod == MultipleGradientPaint.NO_CYCLE) { - fillHardNoCycle(pixels, off, adjust, x, y, w, h); - } else { - //initialize current value to be start. - for (int i = 0; i < h; i++) { //for every row - float g = initConst + dgdY * (y + i); - - final int rowLimit = off + w; // end of row iteration - while (off < rowLimit) { //for every pixel in this row. - //get the color - pixels[off++] = indexIntoGradientsArrays(g); - g += dgdX; //incremental change in g - } - off += adjust; //change in off from row to row - } - } - } else { - // Simple implementations: just scale index by array size - - if (cycleMethod == MultipleGradientPaint.NO_CYCLE) - fillSimpleNoCycle(pixels, off, adjust, x, y, w, h); - else if (cycleMethod == MultipleGradientPaint.REPEAT) - fillSimpleRepeat(pixels, off, adjust, x, y, w, h); - else //cycleMethod == MultipleGradientPaint.REFLECT - fillSimpleReflect(pixels, off, adjust, x, y, w, h); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/MultipleGradientPaint.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/MultipleGradientPaint.java deleted file mode 100644 index b079bdf243..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/MultipleGradientPaint.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.graphics.batik.ext.awt; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * This is the superclass for Paints which use a multiple color - * gradient to fill in their raster. It provides storage for variables and - * enumerated values common to LinearGradientPaint and RadialGradientPaint. - * - * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans - * @author Vincent Hardy - * @version $Id: MultipleGradientPaint.java,v 1.1 2008/09/30 20:44:16 patrickc Exp $ - */ -public abstract class MultipleGradientPaint implements Paint { - - /** - * Transparency. - */ - protected int transparency; - - /** - * Gradient keyframe values in the range 0 to 1. - */ - protected float[] fractions; - - /** - * Gradient colors. - */ - protected Color[] colors; - - /** - * Transform to apply to gradient. - */ - protected AffineTransform gradientTransform; - - /** - * The method to use when painting out of the gradient bounds. - */ - protected CycleMethodEnum cycleMethod; - - /** - * The colorSpace in which to perform the interpolation. - */ - protected ColorSpaceEnum colorSpace; - - /** - * Inner class to allow for typesafe enumerated ColorSpace values. - */ - public static class ColorSpaceEnum { - } - - /** - * Inner class to allow for typesafe enumerated CycleMethod values. - */ - public static class CycleMethodEnum { - } - - /** - * Indicates (if the gradient starts or ends inside the target region) - * to use the terminal colors to fill the remaining area. (default) - */ - public static final CycleMethodEnum NO_CYCLE = new CycleMethodEnum(); - - /** - * Indicates (if the gradient starts or ends inside the target region), - * to cycle the gradient colors start-to-end, end-to-start to fill the - * remaining area. - */ - public static final CycleMethodEnum REFLECT = new CycleMethodEnum(); - - /** - * Indicates (if the gradient starts or ends inside the target region), - * to cycle the gradient colors start-to-end, start-to-end to fill the - * remaining area. - */ - public static final CycleMethodEnum REPEAT = new CycleMethodEnum(); - - /** - * Indicates that the color interpolation should occur in sRGB space. - * (default) - */ - public static final ColorSpaceEnum SRGB = new ColorSpaceEnum(); - - /** - * Indicates that the color interpolation should occur in linearized - * RGB space. - */ - public static final ColorSpaceEnum LINEAR_RGB = new ColorSpaceEnum(); - - - /** - * Superclass constructor, typical user should never have to call this. - * - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors corresponding to each fractional value - * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT - * @param colorSpace which colorspace to use for interpolation, - * either SRGB or LINEAR_RGB - * @param gradientTransform transform to apply to the gradient - * @throws NullPointerException if arrays are null, or - * gradientTransform is null - * @throws IllegalArgumentException if fractions.length != colors.length, - * or if colors is less than 2 in size, or if an enumerated value is bad. - */ - public MultipleGradientPaint(float[] fractions, - Color[] colors, - CycleMethodEnum cycleMethod, - ColorSpaceEnum colorSpace, - AffineTransform gradientTransform) { - - if (fractions == null) { - throw new IllegalArgumentException("Fractions array cannot be " + - "null"); - } - - if (colors == null) { - throw new IllegalArgumentException("Colors array cannot be null"); - } - - if (fractions.length != colors.length) { - throw new IllegalArgumentException("Colors and fractions must " + - "have equal size"); - } - - if (colors.length < 2) { - throw new IllegalArgumentException("User must specify at least " + - "2 colors"); - } - - if ((colorSpace != LINEAR_RGB) && - (colorSpace != SRGB)) { - throw new IllegalArgumentException("Invalid colorspace for " + - "interpolation."); - } - - if ((cycleMethod != NO_CYCLE) && - (cycleMethod != REFLECT) && - (cycleMethod != REPEAT)) { - throw new IllegalArgumentException("Invalid cycle method."); - } - - if (gradientTransform == null) { - throw new IllegalArgumentException("Gradient transform cannot be " + - "null."); - } - - //copy the fractions array - this.fractions = new float[fractions.length]; - System.arraycopy(fractions, 0, this.fractions, 0, fractions.length); - - //copy the colors array - this.colors = new Color[colors.length]; - System.arraycopy(colors, 0, this.colors, 0, colors.length); - - //copy some flags - this.colorSpace = colorSpace; - this.cycleMethod = cycleMethod; - - //copy the gradient transform - this.gradientTransform = (AffineTransform) gradientTransform.clone(); - - // Process transparency - boolean opaque = true; - for (int i = 0; i < colors.length; i++) { - opaque = opaque && (colors[i].getAlpha() == 0xff); - } - - if (opaque) { - transparency = OPAQUE; - } else { - transparency = TRANSLUCENT; - } - } - - /** - * Returns a copy of the array of colors used by this gradient. - * - * @return a copy of the array of colors used by this gradient - */ - public Color[] getColors() { - Color[] colors = new Color[this.colors.length]; - System.arraycopy(this.colors, 0, colors, 0, this.colors.length); - return colors; - } - - /** - * Returns a copy of the array of floats used by this gradient - * to calculate color distribution. - * - * @return a copy of the array of floats used by this gradient to - * calculate color distribution - */ - public float[] getFractions() { - float[] fractions = new float[this.fractions.length]; - System.arraycopy(this.fractions, 0, fractions, 0, this.fractions.length); - return fractions; - } - - /** - * Returns the transparency mode for this LinearGradientPaint. - * - * @return an integer value representing this LinearGradientPaint object's - * transparency mode. - */ - public int getTransparency() { - return transparency; - } - - /** - * Returns the enumerated type which specifies cycling behavior. - * - * @return the enumerated type which specifies cycling behavior - */ - public CycleMethodEnum getCycleMethod() { - return cycleMethod; - } - - /** - * Returns the enumerated type which specifies color space for - * interpolation. - * - * @return the enumerated type which specifies color space for - * interpolation - */ - public ColorSpaceEnum getColorSpace() { - return colorSpace; - } - - /** - * Returns a copy of the transform applied to the gradient. - * - * @return a copy of the transform applied to the gradient. - */ - public AffineTransform getTransform() { - return (AffineTransform) gradientTransform.clone(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/MultipleGradientPaintContext.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/MultipleGradientPaintContext.java deleted file mode 100644 index f9519f690b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/MultipleGradientPaintContext.java +++ /dev/null @@ -1,1508 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.graphics.batik.ext.awt; - -import org.icepdf.core.pobjects.graphics.batik.ext.awt.image.GraphicsUtil; - -import java.awt.*; -import java.awt.color.ColorSpace; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Rectangle2D; -import java.awt.image.*; -import java.lang.ref.WeakReference; - - -/** - * This is the superclass for all PaintContexts which use a multiple color - * gradient to fill in their raster. It provides the actual color interpolation - * functionality. Subclasses only have to deal with using the gradient to fill - * pixels in a raster. - * - * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans - * @author Vincent Hardy - * @version $Id: MultipleGradientPaintContext.java,v 1.1 2008/09/30 20:44:16 patrickc Exp $ - */ -abstract class MultipleGradientPaintContext implements PaintContext { - - protected static final boolean DEBUG = false; - - /** - * The color model data is generated in (always un premult). - */ - protected ColorModel dataModel; - /** - * PaintContext's output ColorModel ARGB if colors are not all - * opaque, RGB otherwise. Linear and premult are matched to - * output ColorModel. - */ - protected ColorModel model; - - /** - * Color model used if gradient colors are all opaque - */ - private static ColorModel lrgbmodel_NA = new DirectColorModel - (ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), - 24, 0xff0000, 0xFF00, 0xFF, 0x0, - false, DataBuffer.TYPE_INT); - - private static ColorModel srgbmodel_NA = new DirectColorModel - (ColorSpace.getInstance(ColorSpace.CS_sRGB), - 24, 0xff0000, 0xFF00, 0xFF, 0x0, - false, DataBuffer.TYPE_INT); - - private static ColorModel graybmodel_NA = - new ComponentColorModel(ColorSpace.getInstance( - ColorSpace.CS_GRAY), new int[]{1}, false, false, - ColorModel.OPAQUE, DataBuffer.TYPE_INT); - - /** - * Color model used if some gradient colors are transparent - */ - private static ColorModel lrgbmodel_A = new DirectColorModel - (ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), - 32, 0xff0000, 0xFF00, 0xFF, 0xFF000000, - false, DataBuffer.TYPE_INT); - - private static ColorModel srgbmodel_A = new DirectColorModel - (ColorSpace.getInstance(ColorSpace.CS_sRGB), - 32, 0xff0000, 0xFF00, 0xFF, 0xFF000000, - false, DataBuffer.TYPE_INT); - - private static ColorModel graybmodel_A = - new ComponentColorModel(ColorSpace.getInstance( - ColorSpace.CS_GRAY), new int[]{1, 1}, true, false, - ColorModel.TRANSLUCENT, DataBuffer.TYPE_INT); - - /** - * The cached colorModel - */ - protected static ColorModel cachedModel; - - /** - * The cached raster, which is reusable among instances - */ - protected static WeakReference cached; - - /** - * Raster is reused whenever possible - */ - protected WritableRaster saved; - - /** - * The method to use when painting out of the gradient bounds. - */ - protected MultipleGradientPaint.CycleMethodEnum cycleMethod; - - /** - * The colorSpace in which to perform the interpolation - */ - protected MultipleGradientPaint.ColorSpaceEnum colorSpace; - - /** - * Elements of the inverse transform matrix. - */ - protected float a00, a01, a10, a11, a02, a12; - - /** - * This boolean specifies wether we are in simple lookup mode, where an - * input value between 0 and 1 may be used to directly index into a single - * array of gradient colors. If this boolean value is false, then we have - * to use a 2-step process where we have to determine which gradient array - * we fall into, then determine the index into that array. - */ - protected boolean isSimpleLookup = true; - - /** - * This boolean indicates if the gradient appears to have sudden - * discontinuities in it, this may be because of multiple stops - * at the same location or use of the REPEATE mode. - */ - protected boolean hasDiscontinuity = false; - - /** - * Size of gradients array for scaling the 0-1 index when looking up - * colors the fast way. - */ - protected int fastGradientArraySize; - - /** - * Array which contains the interpolated color values for each interval, - * used by calculateSingleArrayGradient(). It is protected for possible - * direct access by subclasses. - */ - protected int[] gradient; - - /** - * Array of gradient arrays, one array for each interval. Used by - * calculateMultipleArrayGradient(). - */ - protected int[][] gradients; - - /** - * This holds the blend of all colors in the gradient. - * we use this at extreamly low resolutions to ensure we - * get a decent blend of the colors. - */ - protected int gradientAverage; - - /** - * This holds the color to use when we are off the bottom of the - * gradient - */ - protected int gradientUnderflow; - - /** - * This holds the color to use when we are off the top of the - * gradient - */ - protected int gradientOverflow; - - /** - * Length of the 2D slow lookup gradients array. - */ - protected int gradientsLength; - - /** - * Normalized intervals array - */ - protected float[] normalizedIntervals; - - /** - * fractions array - */ - protected float[] fractions; - - /** - * Used to determine if gradient colors are all opaque - */ - private int transparencyTest; - - /** - * Colorspace conversion lookup tables - */ - private static final int[] SRGBtoLinearRGB = new int[256]; - private static final int[] LinearRGBtoSRGB = new int[256]; - - //build the tables - static { - for (int k = 0; k < 256; k++) { - SRGBtoLinearRGB[k] = convertSRGBtoLinearRGB(k); - LinearRGBtoSRGB[k] = convertLinearRGBtoSRGB(k); - } - } - - /** - * Constant number of max colors between any 2 arbitrary colors. - * Used for creating and indexing gradients arrays. - */ - protected static final int GRADIENT_SIZE = 256; - protected static final int GRADIENT_SIZE_INDEX = GRADIENT_SIZE - 1; - - /** - * Maximum length of the fast single-array. If the estimated array size - * is greater than this, switch over to the slow lookup method. - * No particular reason for choosing this number, but it seems to provide - * satisfactory performance for the common case (fast lookup). - */ - private static final int MAX_GRADIENT_ARRAY_SIZE = 5000; - - /** - * Constructor for superclass. Does some initialization, but leaves most - * of the heavy-duty math for calculateGradient(), so the subclass may do - * some other manipulation beforehand if necessary. This is not possible - * if this computation is done in the superclass constructor which always - * gets called first. - */ - protected MultipleGradientPaintContext(ColorModel cm, - Rectangle deviceBounds, - Rectangle2D userBounds, - AffineTransform t, - RenderingHints hints, - float[] fractions, - Color[] colors, - MultipleGradientPaint.CycleMethodEnum - cycleMethod, - MultipleGradientPaint.ColorSpaceEnum - colorSpace) - throws NoninvertibleTransformException { - //We have to deal with the cases where the 1st gradient stop is not - //equal to 0 and/or the last gradient stop is not equal to 1. - //In both cases, create a new point and replicate the previous - //extreme point's color. - - boolean fixFirst = false; - boolean fixLast = false; - int len = fractions.length; - - //if the first gradient stop is not equal to zero, fix this condition - if (fractions[0] != 0f) { - fixFirst = true; - len++; - } - - //if the last gradient stop is not equal to one, fix this condition - if (fractions[fractions.length - 1] != 1.0f) { - fixLast = true; - len++; - } - - for (int i = 0; i < fractions.length - 1; i++) - if (fractions[i] == fractions[i + 1]) - len--; - - this.fractions = new float[len]; - Color[] loColors = new Color[len - 1]; - Color[] hiColors = new Color[len - 1]; - normalizedIntervals = new float[len - 1]; - - gradientUnderflow = colors[0].getRGB(); - gradientOverflow = colors[colors.length - 1].getRGB(); - - int idx = 0; - if (fixFirst) { - this.fractions[0] = 0; - loColors[0] = colors[0]; - hiColors[0] = colors[0]; - normalizedIntervals[0] = fractions[0]; - idx++; - } - - for (int i = 0; i < fractions.length - 1; i++) { - if (fractions[i] == fractions[i + 1]) { - // System.out.println("EQ Fracts"); - if (!colors[i].equals(colors[i + 1])) { - hasDiscontinuity = true; - } - continue; - } - this.fractions[idx] = fractions[i]; - loColors[idx] = colors[i]; - hiColors[idx] = colors[i + 1]; - normalizedIntervals[idx] = fractions[i + 1] - fractions[i]; - idx++; - } - - this.fractions[idx] = fractions[fractions.length - 1]; - - if (fixLast) { - loColors[idx] = hiColors[idx] = colors[colors.length - 1]; - normalizedIntervals[idx] = 1 - fractions[fractions.length - 1]; - idx++; - this.fractions[idx] = 1; - } - - // The inverse transform is needed to from device to user space. - // Get all the components of the inverse transform matrix. - AffineTransform tInv = t.createInverse(); - - double[] m = new double[6]; - tInv.getMatrix(m); - a00 = (float) m[0]; - a10 = (float) m[1]; - a01 = (float) m[2]; - a11 = (float) m[3]; - a02 = (float) m[4]; - a12 = (float) m[5]; - - //copy some flags - this.cycleMethod = cycleMethod; - this.colorSpace = colorSpace; - - // Setup an example Model, we may refine it later. - if (cm.getColorSpace() == lrgbmodel_A.getColorSpace()) - dataModel = lrgbmodel_A; - else if (cm.getColorSpace() == srgbmodel_A.getColorSpace()) - dataModel = srgbmodel_A; - else if (cm.getColorSpace() == graybmodel_A.getColorSpace()) - dataModel = srgbmodel_A; - else - throw new IllegalArgumentException - ("Unsupported ColorSpace for interpolation"); - - calculateGradientFractions(loColors, hiColors); - - model = GraphicsUtil.coerceColorModel(dataModel, - cm.isAlphaPremultiplied()); - } - - - /** - * This function is the meat of this class. It calculates an array of - * gradient colors based on an array of fractions and color values at those - * fractions. - */ - protected final void calculateGradientFractions - (Color[] loColors, Color[] hiColors) { - - //if interpolation should occur in Linear RGB space, convert the - //colors using the lookup table - if (colorSpace == LinearGradientPaint.LINEAR_RGB) { - int[] workTbl = SRGBtoLinearRGB; // local is cheaper - - for (int i = 0; i < loColors.length; i++) { - - loColors[i] = interpolateColor(workTbl, loColors[i]); - - hiColors[i] = interpolateColor(workTbl, hiColors[i]); - - } - } - - //initialize to be fully opaque for ANDing with colors - transparencyTest = 0xff000000; - if (cycleMethod == MultipleGradientPaint.NO_CYCLE) { - // Include overflow and underflow colors in transparency - // test. - transparencyTest &= gradientUnderflow; - transparencyTest &= gradientOverflow; - } - - //array of interpolation arrays - gradients = new int[fractions.length - 1][]; - gradientsLength = gradients.length; - - // TODO ??? whats going on here - // ??? the following comments and the name Imin suggest, that we search for something small - // ??? but the for-loop actually looks for the LARGEST value - - // Find smallest interval - int n = normalizedIntervals.length; - - float Imin = 1; - float[] workTbl = normalizedIntervals; // local is cheaper - for (int i = 0; i < n; i++) { - // ??? find the LARGEST value in normalizedIntervals - Imin = (Imin > workTbl[i]) ? workTbl[i] : Imin; - } - - //estimate the size of the entire gradients array. - //This is to prevent a tiny interval from causing the size of array to - //explode. If the estimated size is too large, break to using - //seperate arrays for each interval, and using an indexing scheme at - //look-up time. - int estimatedSize = 0; - - if (Imin == 0) { - estimatedSize = Integer.MAX_VALUE; - hasDiscontinuity = true; - } else { - for (int i = 0; i < workTbl.length; i++) { - estimatedSize += (workTbl[i] / Imin) * GRADIENT_SIZE; - } - } - - - if (estimatedSize > MAX_GRADIENT_ARRAY_SIZE) { - //slow method - calculateMultipleArrayGradient(loColors, hiColors); - if ((cycleMethod == MultipleGradientPaint.REPEAT) && - (gradients[0][0] != - gradients[gradients.length - 1][GRADIENT_SIZE_INDEX])) - hasDiscontinuity = true; - } else { - //fast method - calculateSingleArrayGradient(loColors, hiColors, Imin); - if ((cycleMethod == MultipleGradientPaint.REPEAT) && - (gradient[0] != gradient[fastGradientArraySize])) - hasDiscontinuity = true; - } - - // Use the most 'economical' model (no alpha). - if ((transparencyTest >>> 24) == 0xff) { - if (dataModel.getColorSpace() == lrgbmodel_NA.getColorSpace()) - dataModel = lrgbmodel_NA; - else if (dataModel.getColorSpace() == srgbmodel_NA.getColorSpace()) - dataModel = srgbmodel_NA; - else if (dataModel.getColorSpace() == graybmodel_NA.getColorSpace()) - dataModel = graybmodel_NA; - model = dataModel; - } - } - - /** - * We assume, that we always generate valid colors. When this is valid, we can compose the - * color-value by ourselves and use the faster Color-ctor, which does not check the incoming values. - * - * @param workTbl typically SRGBtoLinearRGB - * @param inColor the color to interpolate - * @return the interpolated color - */ - private static Color interpolateColor(int[] workTbl, Color inColor) { - - int oldColor = inColor.getRGB(); - - int newColorValue = - ((workTbl[(oldColor >> 24) & 0xff] & 0xff) << 24) | - ((workTbl[(oldColor >> 16) & 0xff] & 0xff) << 16) | - ((workTbl[(oldColor >> 8) & 0xff] & 0xff) << 8) | - ((workTbl[(oldColor) & 0xff] & 0xff)); - - return new Color(newColorValue, true); - } - - /** - * FAST LOOKUP METHOD - *

      - * This method calculates the gradient color values and places them in a - * single int array, gradient[]. It does this by allocating space for - * each interval based on its size relative to the smallest interval in - * the array. The smallest interval is allocated 255 interpolated values - * (the maximum number of unique in-between colors in a 24 bit color - * system), and all other intervals are allocated - * size = (255 * the ratio of their size to the smallest interval). - *

      - * This scheme expedites a speedy retrieval because the colors are - * distributed along the array according to their user-specified - * distribution. All that is needed is a relative index from 0 to 1. - *

      - * The only problem with this method is that the possibility exists for - * the array size to balloon in the case where there is a - * disproportionately small gradient interval. In this case the other - * intervals will be allocated huge space, but much of that data is - * redundant. We thus need to use the space conserving scheme below. - * - * @param Imin the size of the smallest interval - */ - private void calculateSingleArrayGradient - (Color[] loColors, Color[] hiColors, float Imin) { - - //set the flag so we know later it is a non-simple lookup - isSimpleLookup = true; - - int gradientsTot = 1; //the eventual size of the single array - - // These are fixed point 8.16 (start with 0.5) - int aveA = 0x008000; - int aveR = 0x008000; - int aveG = 0x008000; - int aveB = 0x008000; - - //for every interval (transition between 2 colors) - for (int i = 0; i < gradients.length; i++) { - - //create an array whose size is based on the ratio to the - //smallest interval. - int nGradients = (int) ((normalizedIntervals[i] / Imin) * 255f); - gradientsTot += nGradients; - gradients[i] = new int[nGradients]; - - //the the 2 colors (keyframes) to interpolate between - int rgb1 = loColors[i].getRGB(); - int rgb2 = hiColors[i].getRGB(); - - //fill this array with the colors in between rgb1 and rgb2 - interpolate(rgb1, rgb2, gradients[i]); - - // Calculate Average of two colors... - int argb = gradients[i][GRADIENT_SIZE / 2]; - float norm = normalizedIntervals[i]; - aveA += (int) (((argb >> 8) & 0xFF0000) * norm); - aveR += (int) (((argb) & 0xFF0000) * norm); - aveG += (int) (((argb << 8) & 0xFF0000) * norm); - aveB += (int) (((argb << 16) & 0xFF0000) * norm); - - //if the colors are opaque, transparency should still be 0xff000000 - transparencyTest &= rgb1 & rgb2; - } - - gradientAverage = (((aveA & 0xFF0000) << 8) | - ((aveR & 0xFF0000)) | - ((aveG & 0xFF0000) >> 8) | - ((aveB & 0xFF0000) >> 16)); - - // Put all gradients in a single array - gradient = new int[gradientsTot]; - int curOffset = 0; - for (int i = 0; i < gradients.length; i++) { - System.arraycopy(gradients[i], 0, gradient, - curOffset, gradients[i].length); - curOffset += gradients[i].length; - } - gradient[gradient.length - 1] = hiColors[hiColors.length - 1].getRGB(); - - //if interpolation occurred in Linear RGB space, convert the - //gradients back to SRGB using the lookup table - if (colorSpace == LinearGradientPaint.LINEAR_RGB) { - if (dataModel.getColorSpace() == - ColorSpace.getInstance(ColorSpace.CS_sRGB)) { - for (int i = 0; i < gradient.length; i++) { - gradient[i] = - convertEntireColorLinearRGBtoSRGB(gradient[i]); - } - gradientAverage = - convertEntireColorLinearRGBtoSRGB(gradientAverage); - } - } else { - if (dataModel.getColorSpace() == - ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) { - for (int i = 0; i < gradient.length; i++) { - gradient[i] = - convertEntireColorSRGBtoLinearRGB(gradient[i]); - } - gradientAverage = - convertEntireColorSRGBtoLinearRGB(gradientAverage); - } - } - - fastGradientArraySize = gradient.length - 1; - } - - - /** - * SLOW LOOKUP METHOD - *

      - * This method calculates the gradient color values for each interval and - * places each into its own 255 size array. The arrays are stored in - * gradients[][]. (255 is used because this is the maximum number of - * unique colors between 2 arbitrary colors in a 24 bit color system) - *

      - * This method uses the minimum amount of space (only 255 * number of - * intervals), but it aggravates the lookup procedure, because now we - * have to find out which interval to select, then calculate the index - * within that interval. This causes a significant performance hit, - * because it requires this calculation be done for every point in - * the rendering loop. - *

      - * For those of you who are interested, this is a classic example of the - * time-space tradeoff. - */ - private void calculateMultipleArrayGradient - (Color[] loColors, Color[] hiColors) { - - //set the flag so we know later it is a non-simple lookup - isSimpleLookup = false; - - int rgb1; //2 colors to interpolate - int rgb2; - - // These are fixed point 8.16 (start with 0.5) - int aveA = 0x008000; - int aveR = 0x008000; - int aveG = 0x008000; - int aveB = 0x008000; - - //for every interval (transition between 2 colors) - for (int i = 0; i < gradients.length; i++) { - - // This interval will never actually be used (zero size) - if (normalizedIntervals[i] == 0) - continue; - - //create an array of the maximum theoretical size for each interval - gradients[i] = new int[GRADIENT_SIZE]; - - //get the the 2 colors - rgb1 = loColors[i].getRGB(); - rgb2 = hiColors[i].getRGB(); - - //fill this array with the colors in between rgb1 and rgb2 - interpolate(rgb1, rgb2, gradients[i]); - - // Calculate Average of two colors... - int argb = gradients[i][GRADIENT_SIZE / 2]; - float norm = normalizedIntervals[i]; - aveA += (int) (((argb >> 8) & 0xFF0000) * norm); - aveR += (int) (((argb) & 0xFF0000) * norm); - aveG += (int) (((argb << 8) & 0xFF0000) * norm); - aveB += (int) (((argb << 16) & 0xFF0000) * norm); - - //if the colors are opaque, transparency should still be 0xff000000 - transparencyTest &= rgb1; - transparencyTest &= rgb2; - } - - gradientAverage = (((aveA & 0xFF0000) << 8) | - ((aveR & 0xFF0000)) | - ((aveG & 0xFF0000) >> 8) | - ((aveB & 0xFF0000) >> 16)); - - //if interpolation occurred in Linear RGB space, convert the - //gradients back to SRGB using the lookup table - if (colorSpace == LinearGradientPaint.LINEAR_RGB) { - if (dataModel.getColorSpace() == - ColorSpace.getInstance(ColorSpace.CS_sRGB)) { - for (int j = 0; j < gradients.length; j++) { - for (int i = 0; i < gradients[j].length; i++) { - gradients[j][i] = - convertEntireColorLinearRGBtoSRGB(gradients[j][i]); - } - } - gradientAverage = - convertEntireColorLinearRGBtoSRGB(gradientAverage); - } - } else { - if (dataModel.getColorSpace() == - ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) { - for (int j = 0; j < gradients.length; j++) { - for (int i = 0; i < gradients[j].length; i++) { - gradients[j][i] = - convertEntireColorSRGBtoLinearRGB(gradients[j][i]); - } - } - gradientAverage = - convertEntireColorSRGBtoLinearRGB(gradientAverage); - } - } - } - - /** - * Yet another helper function. This one linearly interpolates between - * 2 colors, filling up the output array. - * - * @param rgb1 the start color - * @param rgb2 the end color - * @param output the output array of colors... assuming this is not null or length 0. - */ - private void interpolate(int rgb1, int rgb2, int[] output) { - - int nSteps = output.length; - - //step between interpolated values. - float stepSize = 1 / (float) nSteps; - - //extract color components from packed integer - int a1 = (rgb1 >> 24) & 0xff; - int r1 = (rgb1 >> 16) & 0xff; - int g1 = (rgb1 >> 8) & 0xff; - int b1 = (rgb1) & 0xff; - // calculate the total change in alpha, red, green, blue - // the deltas can be negative ! - int da = ((rgb2 >> 24) & 0xff) - a1; - int dr = ((rgb2 >> 16) & 0xff) - r1; - int dg = ((rgb2 >> 8) & 0xff) - g1; - int db = ((rgb2) & 0xff) - b1; - - // this method is a hotspot so we try to save some cycles - // pre-compute some intermediate values. - // the multiplication by 2 is used to help with rounding. - float tempA = 2.0f * da * stepSize; - float tempR = 2.0f * dr * stepSize; - float tempG = 2.0f * dg * stepSize; - float tempB = 2.0f * db * stepSize; - - //for each step in the interval calculate the in-between color by - //multiplying the normalized current position by the total color change - //(.5 is added to prevent truncation round-off error) - - // the previous implementation used a simple +0.5d to do some rounding. - // but that is just rounding towards +inifitity. This results in - // slightly different values (thus gradients) when you interpolate from - // color1 -> color2 - // versus - // color1 <- color2 - // - // this implementation uses an implied multiplication by 2 ( in tempX ) - // and then a signed right-shift to do signed rounding. - // this also spares a float-add per color-band. - // we could also save the shift when we use a different and-mask and a different left-shift, - // but that would obfuscate too much... - // - output[0] = rgb1; // the start-color is fixed - nSteps--; // upto, but not including the last slot - output[nSteps] = rgb2; // the last color is also fixed - for (int i = 1; i < nSteps; i++) { - output[i] = - ((a1 + ((((int) (i * tempA)) + 1) >> 1) & 0xff) << 24) | - ((r1 + ((((int) (i * tempR)) + 1) >> 1) & 0xff) << 16) | - ((g1 + ((((int) (i * tempG)) + 1) >> 1) & 0xff) << 8) | - ((b1 + ((((int) (i * tempB)) + 1) >> 1) & 0xff)); - } - - } - - - /** - * Yet another helper function. This one extracts the color components - * of an integer RGB triple, converts them from LinearRGB to SRGB, then - * recompacts them into an int. - */ - private static int convertEntireColorLinearRGBtoSRGB(int rgb) { - - //extract red, green, blue components - int a1 = (rgb >> 24) & 0xff; - int r1 = (rgb >> 16) & 0xff; - int g1 = (rgb >> 8) & 0xff; - int b1 = rgb & 0xff; - - //use the lookup table - int[] workTbl = LinearRGBtoSRGB; // local is cheaper - r1 = workTbl[r1]; - g1 = workTbl[g1]; - b1 = workTbl[b1]; - - //re-compact the components - return ((a1 << 24) | - (r1 << 16) | - (g1 << 8) | - b1); - } - - /** - * Yet another helper function. This one extracts the color components - * of an integer RGB triple, converts them from LinearRGB to SRGB, then - * recompacts them into an int. - */ - private static int convertEntireColorSRGBtoLinearRGB(int rgb) { - - //extract red, green, blue components - int a1 = (rgb >> 24) & 0xff; - int r1 = (rgb >> 16) & 0xff; - int g1 = (rgb >> 8) & 0xff; - int b1 = rgb & 0xff; - - //use the lookup table - int[] workTbl = SRGBtoLinearRGB; // local is cheaper - r1 = workTbl[r1]; - g1 = workTbl[g1]; - b1 = workTbl[b1]; - - //re-compact the components - return ((a1 << 24) | - (r1 << 16) | - (g1 << 8) | - b1); - } - - - /** - * Helper function to index into the gradients array. This is necessary - * because each interval has an array of colors with uniform size 255. - * However, the color intervals are not necessarily of uniform length, so - * a conversion is required. - * - * @param position the unmanipulated position. want to map this into the - * range 0 to 1 - * @return integer color to display - */ - protected final int indexIntoGradientsArrays(float position) { - - //first, manipulate position value depending on the cycle method. - - if (cycleMethod == MultipleGradientPaint.NO_CYCLE) { - - if (position >= 1) { //upper bound is 1 - return gradientOverflow; - } else if (position <= 0) { //lower bound is 0 - return gradientUnderflow; - } - } else if (cycleMethod == MultipleGradientPaint.REPEAT) { - //get the fractional part - //(modulo behavior discards integer component) - position = position - (int) position; - - //position now be between -1 and 1 - - if (position < 0) { - position = position + 1; //force it to be in the range 0-1 - } - - int w = 0, c1 = 0, c2 = 0; - if (isSimpleLookup) { - position *= gradient.length; - int idx1 = (int) (position); - if (idx1 + 1 < gradient.length) - return gradient[idx1]; - - w = (int) ((position - idx1) * (1 << 16)); - c1 = gradient[idx1]; - c2 = gradient[0]; - } else { - //for all the gradient interval arrays - for (int i = 0; i < gradientsLength; i++) { - - if (position < fractions[i + 1]) { //this is the array we want - - float delta = position - fractions[i]; - - delta = ((delta / normalizedIntervals[i]) * GRADIENT_SIZE); - //this is the interval we want. - int index = (int) delta; - if ((index + 1 < gradients[i].length) || - (i + 1 < gradientsLength)) - return gradients[i][index]; - - w = (int) ((delta - index) * (1 << 16)); - c1 = gradients[i][index]; - c2 = gradients[0][0]; - break; - } - } - } - - return - ((((((c1 >> 8) & 0xFF0000) + - ((((c2 >>> 24)) - ((c1 >>> 24))) * w)) & 0xFF0000) << 8) | - - (((((c1) & 0xFF0000) + - ((((c2 >> 16) & 0xFF) - ((c1 >> 16) & 0xFF)) * w)) & 0xFF0000)) | - - (((((c1 << 8) & 0xFF0000) + - ((((c2 >> 8) & 0xFF) - ((c1 >> 8) & 0xFF)) * w)) & 0xFF0000) >> 8) | - - (((((c1 << 16) & 0xFF0000) + - ((((c2) & 0xFF) - ((c1) & 0xFF)) * w)) & 0xFF0000) >> 16)); - - // return c1 + - // ((( ((((c2>>>24) )-((c1>>>24) ))*w)&0xFF0000)<< 8) | - // (( ((((c2>> 16)&0xFF)-((c1>> 16)&0xFF))*w)&0xFF0000) ) | - // (( ((((c2>> 8)&0xFF)-((c1>> 8)&0xFF))*w)&0xFF0000)>> 8) | - // (( ((((c2 )&0xFF)-((c1 )&0xFF))*w)&0xFF0000)>>16)); - } else { //cycleMethod == MultipleGradientPaint.REFLECT - - if (position < 0) { - position = -position; //take absolute value - } - - int part = (int) position; //take the integer part - - position = position - part; //get the fractional part - - if ((part & 0x00000001) == 1) { //if integer part is odd - position = 1 - position; //want the reflected color instead - } - } - - //now, get the color based on this 0-1 position: - - if (isSimpleLookup) { //easy to compute: just scale index by array size - return gradient[(int) (position * fastGradientArraySize)]; - } else { //more complicated computation, to save space - - //for all the gradient interval arrays - for (int i = 0; i < gradientsLength; i++) { - - if (position < fractions[i + 1]) { //this is the array we want - - float delta = position - fractions[i]; - - //this is the interval we want. - int index = (int) ((delta / normalizedIntervals[i]) - * (GRADIENT_SIZE_INDEX)); - - return gradients[i][index]; - } - } - - } - - return gradientOverflow; - } - - - /** - * Helper function to index into the gradients array. This is necessary - * because each interval has an array of colors with uniform size 255. - * However, the color intervals are not necessarily of uniform length, so - * a conversion is required. This version also does anti-aliasing by - * averaging the gradient over position+/-(sz/2). - * - * @param position the unmanipulated position. want to map this into the - * range 0 to 1 - * @param sz the size in gradient space to average. - * @return ARGB integer color to display - */ - protected final int indexGradientAntiAlias(float position, float sz) { - //first, manipulate position value depending on the cycle method. - if (cycleMethod == MultipleGradientPaint.NO_CYCLE) { - if (DEBUG) System.out.println("NO_CYCLE"); - float p1 = position - (sz / 2); - float p2 = position + (sz / 2); - - if (p1 >= 1) - return gradientOverflow; - - if (p2 <= 0) - return gradientUnderflow; - - int interior; - float top_weight = 0, bottom_weight = 0, frac; - if (p2 >= 1) { - top_weight = (p2 - 1) / sz; - if (p1 <= 0) { - bottom_weight = -p1 / sz; - frac = 1; - interior = gradientAverage; - } else { - frac = 1 - p1; - interior = getAntiAlias(p1, true, 1, false, 1 - p1, 1); - } - } else if (p1 <= 0) { - bottom_weight = -p1 / sz; - frac = p2; - interior = getAntiAlias(0, true, p2, false, p2, 1); - } else - return getAntiAlias(p1, true, p2, false, sz, 1); - - int norm = (int) ((1 << 16) * frac / sz); - int pA = (((interior >>> 20) & 0xFF0) * norm) >> 16; - int pR = (((interior >> 12) & 0xFF0) * norm) >> 16; - int pG = (((interior >> 4) & 0xFF0) * norm) >> 16; - int pB = (((interior << 4) & 0xFF0) * norm) >> 16; - - if (bottom_weight != 0) { - int bPix = gradientUnderflow; - // System.out.println("ave: " + gradientAverage); - norm = (int) ((1 << 16) * bottom_weight); - pA += (((bPix >>> 20) & 0xFF0) * norm) >> 16; - pR += (((bPix >> 12) & 0xFF0) * norm) >> 16; - pG += (((bPix >> 4) & 0xFF0) * norm) >> 16; - pB += (((bPix << 4) & 0xFF0) * norm) >> 16; - } - - if (top_weight != 0) { - int tPix = gradientOverflow; - - norm = (int) ((1 << 16) * top_weight); - pA += (((tPix >>> 20) & 0xFF0) * norm) >> 16; - pR += (((tPix >> 12) & 0xFF0) * norm) >> 16; - pG += (((tPix >> 4) & 0xFF0) * norm) >> 16; - pB += (((tPix << 4) & 0xFF0) * norm) >> 16; - } - - return (((pA & 0xFF0) << 20) | - ((pR & 0xFF0) << 12) | - ((pG & 0xFF0) << 4) | - ((pB & 0xFF0) >> 4)); - } - - // See how many times we are going to "wrap around" the gradient, - // array. - int intSz = (int) sz; - - float weight = 1.0f; - if (intSz != 0) { - // We need to make sure that sz is < 1.0 otherwise - // p1 and p2 my pass each other which will cause no end of - // trouble. - sz -= intSz; - weight = sz / (intSz + sz); - if (weight < 0.1) - // The part of the color from the location will be swamped - // by the averaged part of the gradient so just use the - // average color for the gradient. - return gradientAverage; - } - - // So close to full gradient just use the average value... - if (sz > 0.99) - return gradientAverage; - - // Go up and down from position by 1/2 sz. - float p1 = position - (sz / 2); - float p2 = position + (sz / 2); - if (DEBUG) System.out.println("P1: " + p1 + " P2: " + p2); - - // These indicate the direction to go from p1 and p2 when - // averaging... - boolean p1_up = true; - boolean p2_up = false; - - if (cycleMethod == MultipleGradientPaint.REPEAT) { - if (DEBUG) System.out.println("REPEAT"); - - // Get positions between -1 and 1 - p1 = p1 - (int) p1; - p2 = p2 - (int) p2; - - // force to be in rage 0-1. - if (p1 < 0) p1 += 1; - if (p2 < 0) p2 += 1; - } else { //cycleMethod == MultipleGradientPaint.REFLECT - if (DEBUG) System.out.println("REFLECT"); - - //take absolute values - // Note when we reflect we change sense of p1/2_up. - if (p2 < 0) { - p1 = -p1; - p1_up = !p1_up; - p2 = -p2; - p2_up = !p2_up; - } else if (p1 < 0) { - p1 = -p1; - p1_up = !p1_up; - } - - int part1, part2; - part1 = (int) p1; // take the integer part - p1 = p1 - part1; // get the fractional part - - part2 = (int) p2; // take the integer part - p2 = p2 - part2; // get the fractional part - - // if integer part is odd we want the reflected color instead. - // Note when we reflect we change sense of p1/2_up. - if ((part1 & 0x01) == 1) { - p1 = 1 - p1; - p1_up = !p1_up; - } - - if ((part2 & 0x01) == 1) { - p2 = 1 - p2; - p2_up = !p2_up; - } - - // Check if in the end they just got switched around. - // this commonly happens if they both end up negative. - if ((p1 > p2) && !p1_up && p2_up) { - float t = p1; - p1 = p2; - p2 = t; - p1_up = true; - p2_up = false; - } - } - - return getAntiAlias(p1, p1_up, p2, p2_up, sz, weight); - } - - - private int getAntiAlias(float p1, boolean p1_up, - float p2, boolean p2_up, - float sz, float weight) { - - // Until the last set of ops these are 28.4 fixed point values. - int ach = 0, rch = 0, gch = 0, bch = 0; - if (isSimpleLookup) { - p1 *= fastGradientArraySize; - p2 *= fastGradientArraySize; - - int idx1 = (int) p1; - int idx2 = (int) p2; - - int i, pix; - - if (p1_up && !p2_up && (idx1 <= idx2)) { - - if (idx1 == idx2) - return gradient[idx1]; - - // Sum between idx1 and idx2. - for (i = idx1 + 1; i < idx2; i++) { - pix = gradient[i]; - ach += ((pix >>> 20) & 0xFF0); - rch += ((pix >>> 12) & 0xFF0); - gch += ((pix >>> 4) & 0xFF0); - bch += ((pix << 4) & 0xFF0); - } - } else { - // Do the bulk of the work, all the whole gradient entries - // for idx1 and idx2. - int iStart; - int iEnd; - if (p1_up) { - iStart = idx1 + 1; - iEnd = fastGradientArraySize; - } else { - iStart = 0; - iEnd = idx1; - } - for (i = iStart; i < iEnd; i++) { - pix = gradient[i]; - ach += ((pix >>> 20) & 0xFF0); - rch += ((pix >>> 12) & 0xFF0); - gch += ((pix >>> 4) & 0xFF0); - bch += ((pix << 4) & 0xFF0); - } - - if (p2_up) { - iStart = idx2 + 1; - iEnd = fastGradientArraySize; - } else { - iStart = 0; - iEnd = idx2; - } - for (i = iStart; i < iEnd; i++) { - pix = gradient[i]; - ach += ((pix >>> 20) & 0xFF0); - rch += ((pix >>> 12) & 0xFF0); - gch += ((pix >>> 4) & 0xFF0); - bch += ((pix << 4) & 0xFF0); - } - } - - int norm, isz; - - // Normalize the summation so far... - isz = (int) ((1 << 16) / (sz * fastGradientArraySize)); - ach = (ach * isz) >> 16; - rch = (rch * isz) >> 16; - gch = (gch * isz) >> 16; - bch = (bch * isz) >> 16; - - // Clean up with the partial buckets at each end. - if (p1_up) norm = (int) ((1 - (p1 - idx1)) * isz); - else norm = (int) ((p1 - idx1) * isz); - pix = gradient[idx1]; - ach += (((pix >>> 20) & 0xFF0) * norm) >> 16; - rch += (((pix >>> 12) & 0xFF0) * norm) >> 16; - gch += (((pix >>> 4) & 0xFF0) * norm) >> 16; - bch += (((pix << 4) & 0xFF0) * norm) >> 16; - - if (p2_up) norm = (int) ((1 - (p2 - idx2)) * isz); - else norm = (int) ((p2 - idx2) * isz); - pix = gradient[idx2]; - ach += (((pix >>> 20) & 0xFF0) * norm) >> 16; - rch += (((pix >>> 12) & 0xFF0) * norm) >> 16; - gch += (((pix >>> 4) & 0xFF0) * norm) >> 16; - bch += (((pix << 4) & 0xFF0) * norm) >> 16; - - // Round and drop the 4bits frac. - ach = (ach + 0x08) >> 4; - rch = (rch + 0x08) >> 4; - gch = (gch + 0x08) >> 4; - bch = (bch + 0x08) >> 4; - - } else { - int idx1 = 0, idx2 = 0; - int i1 = -1, i2 = -1; - float f1 = 0, f2 = 0; - // Find which gradient interval our points fall into. - for (int i = 0; i < gradientsLength; i++) { - if ((p1 < fractions[i + 1]) && (i1 == -1)) { - //this is the array we want - i1 = i; - f1 = p1 - fractions[i]; - - f1 = ((f1 / normalizedIntervals[i]) - * GRADIENT_SIZE_INDEX); - //this is the interval we want. - idx1 = (int) f1; - if (i2 != -1) break; - } - if ((p2 < fractions[i + 1]) && (i2 == -1)) { - //this is the array we want - i2 = i; - f2 = p2 - fractions[i]; - - f2 = ((f2 / normalizedIntervals[i]) - * GRADIENT_SIZE_INDEX); - //this is the interval we want. - idx2 = (int) f2; - if (i1 != -1) break; - } - } - - if (i1 == -1) { - i1 = gradients.length - 1; - f1 = idx1 = GRADIENT_SIZE_INDEX; - } - - if (i2 == -1) { - i2 = gradients.length - 1; - f2 = idx2 = GRADIENT_SIZE_INDEX; - } - - if (DEBUG) System.out.println("I1: " + i1 + " Idx1: " + idx1 + - " I2: " + i2 + " Idx2: " + idx2); - - // Simple case within one gradient array (so the average - // of the two idx gives us the true average of colors). - if ((i1 == i2) && (idx1 <= idx2) && p1_up && !p2_up) - return gradients[i1][(idx1 + idx2 + 1) >> 1]; - - // i1 != i2 - - int pix, norm; - int base = (int) ((1 << 16) / sz); - if ((i1 < i2) && p1_up && !p2_up) { - norm = (int) ((base - * normalizedIntervals[i1] - * (GRADIENT_SIZE_INDEX - f1)) - / GRADIENT_SIZE_INDEX); - pix = gradients[i1][(idx1 + GRADIENT_SIZE) >> 1]; - ach += (((pix >>> 20) & 0xFF0) * norm) >> 16; - rch += (((pix >>> 12) & 0xFF0) * norm) >> 16; - gch += (((pix >>> 4) & 0xFF0) * norm) >> 16; - bch += (((pix << 4) & 0xFF0) * norm) >> 16; - - for (int i = i1 + 1; i < i2; i++) { - norm = (int) (base * normalizedIntervals[i]); - pix = gradients[i][GRADIENT_SIZE >> 1]; - - ach += (((pix >>> 20) & 0xFF0) * norm) >> 16; - rch += (((pix >>> 12) & 0xFF0) * norm) >> 16; - gch += (((pix >>> 4) & 0xFF0) * norm) >> 16; - bch += (((pix << 4) & 0xFF0) * norm) >> 16; - } - - norm = (int) ((base * normalizedIntervals[i2] * f2) - / GRADIENT_SIZE_INDEX); - pix = gradients[i2][(idx2 + 1) >> 1]; - ach += (((pix >>> 20) & 0xFF0) * norm) >> 16; - rch += (((pix >>> 12) & 0xFF0) * norm) >> 16; - gch += (((pix >>> 4) & 0xFF0) * norm) >> 16; - bch += (((pix << 4) & 0xFF0) * norm) >> 16; - } else { - if (p1_up) { - norm = (int) ((base - * normalizedIntervals[i1] - * (GRADIENT_SIZE_INDEX - f1)) - / GRADIENT_SIZE_INDEX); - pix = gradients[i1][(idx1 + GRADIENT_SIZE) >> 1]; - } else { - norm = (int) ((base * normalizedIntervals[i1] * f1) - / GRADIENT_SIZE_INDEX); - pix = gradients[i1][(idx1 + 1) >> 1]; - } - ach += (((pix >>> 20) & 0xFF0) * norm) >> 16; - rch += (((pix >>> 12) & 0xFF0) * norm) >> 16; - gch += (((pix >>> 4) & 0xFF0) * norm) >> 16; - bch += (((pix << 4) & 0xFF0) * norm) >> 16; - - if (p2_up) { - norm = (int) ((base - * normalizedIntervals[i2] - * (GRADIENT_SIZE_INDEX - f2)) - / GRADIENT_SIZE_INDEX); - pix = gradients[i2][(idx2 + GRADIENT_SIZE) >> 1]; - } else { - norm = (int) ((base * normalizedIntervals[i2] * f2) - / GRADIENT_SIZE_INDEX); - pix = gradients[i2][(idx2 + 1) >> 1]; - } - ach += (((pix >>> 20) & 0xFF0) * norm) >> 16; - rch += (((pix >>> 12) & 0xFF0) * norm) >> 16; - gch += (((pix >>> 4) & 0xFF0) * norm) >> 16; - bch += (((pix << 4) & 0xFF0) * norm) >> 16; - - // p1_up and p2_up are just used to set the loop-boundarys, - // then we loop from iStart to iEnd - int iStart; - int iEnd; - - if (p1_up) { - iStart = i1 + 1; - iEnd = gradientsLength; - } else { - iStart = 0; - iEnd = i1; - } - for (int i = iStart; i < iEnd; i++) { - norm = (int) (base * normalizedIntervals[i]); - pix = gradients[i][GRADIENT_SIZE >> 1]; - - ach += (((pix >>> 20) & 0xFF0) * norm) >> 16; - rch += (((pix >>> 12) & 0xFF0) * norm) >> 16; - gch += (((pix >>> 4) & 0xFF0) * norm) >> 16; - bch += (((pix << 4) & 0xFF0) * norm) >> 16; - } - - if (p2_up) { - iStart = i2 + 1; - iEnd = gradientsLength; - } else { - iStart = 0; - iEnd = i2; - } - for (int i = iStart; i < iEnd; i++) { - norm = (int) (base * normalizedIntervals[i]); - pix = gradients[i][GRADIENT_SIZE >> 1]; - - ach += (((pix >>> 20) & 0xFF0) * norm) >> 16; - rch += (((pix >>> 12) & 0xFF0) * norm) >> 16; - gch += (((pix >>> 4) & 0xFF0) * norm) >> 16; - bch += (((pix << 4) & 0xFF0) * norm) >> 16; - } - - - } - ach = (ach + 0x08) >> 4; - rch = (rch + 0x08) >> 4; - gch = (gch + 0x08) >> 4; - bch = (bch + 0x08) >> 4; - if (DEBUG) System.out.println("Pix: [" + ach + ", " + rch + - ", " + gch + ", " + bch + ']'); - } - - if (weight != 1) { - // System.out.println("ave: " + gradientAverage); - int aveW = (int) ((1 << 16) * (1 - weight)); - int aveA = ((gradientAverage >>> 24) & 0xFF) * aveW; - int aveR = ((gradientAverage >> 16) & 0xFF) * aveW; - int aveG = ((gradientAverage >> 8) & 0xFF) * aveW; - int aveB = ((gradientAverage) & 0xFF) * aveW; - - int iw = (int) (weight * (1 << 16)); - ach = ((ach * iw) + aveA) >> 16; - rch = ((rch * iw) + aveR) >> 16; - gch = ((gch * iw) + aveG) >> 16; - bch = ((bch * iw) + aveB) >> 16; - } - - return ((ach << 24) | (rch << 16) | (gch << 8) | bch); - } - - - /** - * Helper function to convert a color component in sRGB space to linear - * RGB space. Used to build a static lookup table. - */ - private static int convertSRGBtoLinearRGB(int color) { - - // use of float and double arithmetic gives exactly same results - float output; - - float input = color / 255.0f; - if (input <= 0.04045f) { - output = input / 12.92f; - } else { - output = (float) Math.pow((input + 0.055) / 1.055, 2.4); - } - return Math.round(output * 255.0f); - } - - /** - * Helper function to convert a color component in linear RGB space to - * SRGB space. Used to build a static lookup table. - */ - private static int convertLinearRGBtoSRGB(int color) { - - // use of float and double arithmetic gives exactly same results - float output; - - float input = color / 255.0f; - - if (input <= 0.0031308f) { - output = input * 12.92f; - } else { - output = (1.055f * ((float) Math.pow(input, (1.0 / 2.4)))) - 0.055f; - } - return Math.round(output * 255.0f); - } - - - /** - * Superclass getRaster... - */ - public final Raster getRaster(int x, int y, int w, int h) { - if (w == 0 || h == 0) { - return null; - } - - // - // If working raster is big enough, reuse it. Otherwise, - // build a large enough new one. - // - WritableRaster raster = saved; - if (raster == null || raster.getWidth() < w || raster.getHeight() < h) { - raster = getCachedRaster(dataModel, w, h); - saved = raster; - // NOTE:We would like to use 'x' & 'y' here instead of - // '0', '0' but this will fail on MacOSX. Since it - // doesn't have an effect on other JVMs. - raster = raster.createWritableChild - (raster.getMinX(), raster.getMinY(), w, h, 0, 0, null); - } - - // Access raster internal int array. Because we use a DirectColorModel, - // we know the DataBuffer is of type DataBufferInt and the SampleModel - // is SinglePixelPackedSampleModel. - // Adjust for initial offset in DataBuffer and also for the scanline - // stride. - // - DataBufferInt rasterDB = (DataBufferInt) raster.getDataBuffer(); - int[] pixels = rasterDB.getBankData()[0]; - int off = rasterDB.getOffset(); - int scanlineStride = ((SinglePixelPackedSampleModel) - raster.getSampleModel()).getScanlineStride(); - int adjust = scanlineStride - w; - - fillRaster(pixels, off, adjust, x, y, w, h); //delegate to subclass. - - GraphicsUtil.coerceData(raster, dataModel, - model.isAlphaPremultiplied()); - - - return raster; - } - - /** - * Subclasses should implement this. - */ - protected abstract void fillRaster(int[] pixels, int off, int adjust, - int x, int y, int w, int h); - - - /** - * Took this cacheRaster code from GradientPaint. It appears to recycle - * rasters for use by any other instance, as long as they are sufficiently - * large. - */ - protected static synchronized WritableRaster getCachedRaster - (ColorModel cm, int w, int h) { - if (cm == cachedModel) { - if (cached != null) { - WritableRaster ras = cached.get(); - if (ras != null && - ras.getWidth() >= w && - ras.getHeight() >= h) { - cached = null; - return ras; - } - } - } - // Don't create rediculously small rasters... - if (w < 32) w = 32; - if (h < 32) h = 32; - return cm.createCompatibleWritableRaster(w, h); - } - - /** - * Took this cacheRaster code from GradientPaint. It appears to recycle - * rasters for use by any other instance, as long as they are sufficiently - * large. - */ - protected static synchronized void putCachedRaster(ColorModel cm, - WritableRaster ras) { - if (cached != null) { - WritableRaster cras = cached.get(); - if (cras != null) { - int cw = cras.getWidth(); - int ch = cras.getHeight(); - int iw = ras.getWidth(); - int ih = ras.getHeight(); - if (cw >= iw && ch >= ih) { - return; - } - if (cw * ch >= iw * ih) { - return; - } - } - } - cachedModel = cm; - cached = new WeakReference(ras); - } - - /** - * Release the resources allocated for the operation. - */ - public final void dispose() { - if (saved != null) { - putCachedRaster(model, saved); - saved = null; - } - } - - /** - * Return the ColorModel of the output. - */ - public final ColorModel getColorModel() { - return model; - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/RadialGradientPaint.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/RadialGradientPaint.java deleted file mode 100644 index 7f66abfeea..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/RadialGradientPaint.java +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.graphics.batik.ext.awt; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.ColorModel; - -/** - *

      - * This class provides a way to fill a shape with a circular radial color - * gradient pattern. The user may specify 2 or more gradient colors, and this - * paint will provide an interpolation between each color. - *

      - *

      - * The user must provide an array of floats specifying how to distribute the - * colors along the gradient. These values should range from 0.0 to 1.0 and - * act like keyframes along the gradient (they mark where the gradient should - * be exactly a particular color). - *

      - *

      - * This paint will map the first color of the gradient to a focus point within - * the circle, and the last color to the perimeter of the circle, interpolating - * smoothly for any inbetween colors specified by the user. Any line drawn - * from the focus point to the circumference will span the all the gradient - * colors. By default the focus is set to be the center of the circle. - *

      - *

      - * Specifying a focus point outside of the circle's radius will result in the - * focus being set to the intersection point of the focus-center line and the - * perimenter of the circle. - *

      - *

      - * Specifying a cycle method allows the user to control the painting behavior - * outside of the bounds of the circle's radius. See LinearGradientPaint for - * more details. - *

      - *

      - * The following code demonstrates typical usage of RadialGradientPaint: - *

      - * - * Point2D center = new Point2D.Float(0, 0);
      - * float radius = 20; - * float[] dist = {0.0, 0.2, 1.0};
      - * Color[] colors = {Color.red, Color.white, Color.blue};
      - * RadialGradientPaint p = new RadialGradientPaint(center, radius, - * dist, colors); - *
      - *

      - *

      In the event that the user does not set the first keyframe value equal - * to 0 and the last keyframe value equal to 1, keyframes will be created at - * these positions and the first and last colors will be replicated there. - * So, if a user specifies the following arrays to construct a gradient:
      - * {Color.blue, Color.red}, {.3, .7}
      - * this will be converted to a gradient with the following keyframes: - * {Color.blue, Color.blue, Color.red, Color.red}, {0, .3, .7, 1} - *

      - *

      - *

      - * - *

      - * This image demonstrates a radial gradient with NO_CYCLE and default focus. - *

      - *

      - * - *

      - * This image demonstrates a radial gradient with NO_CYCLE and non-centered - * focus. - *

      - *

      - * - *

      - * This image demonstrates a radial gradient with REFLECT and non-centered - * focus. - * - * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans - * @author Vincent Hardy - * @version $Id: RadialGradientPaint.java,v 1.1 2008/09/30 20:44:16 patrickc Exp $ - */ -public final class RadialGradientPaint extends MultipleGradientPaint { - - /** - * Focus point which defines the 0% gradient stop x coordinate. - */ - private Point2D focus; - - /** - * Center of the circle defining the 100% gradient stop x coordinate. - */ - private Point2D center; - - /** - * Radius of the outermost circle defining the 100% gradient stop. - */ - private float radius; - - /** - *

      - *

      - * Constructs a RadialGradientPaint, using the center as the - * focus point. - * - * @param cx the x coordinate in user space of the center point of the - * circle defining the gradient. The last color of the gradient is mapped - * to the perimeter of this circle - * @param cy the y coordinate in user space of the center point of the - * circle defining the gradient. The last color of the gradient is mapped - * to the perimeter of this circle - * @param radius the radius of the circle defining the extents of the - * color gradient - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors to use in the gradient. The first color - * is used at the focus point, the last color around the perimeter of the - * circle. - * @throws IllegalArgumentException if fractions.length != colors.length, or if colors is less - * than 2 in size, or if radius < 0 - */ - public RadialGradientPaint(float cx, float cy, float radius, - float[] fractions, Color[] colors) { - this(cx, cy, - radius, - cx, cy, - fractions, - colors); - } - - /** - *

      - *

      - * Constructs a RadialGradientPaint, using the center as the - * focus point. - * - * @param center the center point, in user space, of the circle defining - * the gradient - * @param radius the radius of the circle defining the extents of the - * color gradient - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors to use in the gradient. The first color - * is used at the focus point, the last color around the perimeter of the - * circle. - * @throws NullPointerException if center point is null - * @throws IllegalArgumentException if fractions.length != colors.length, or if colors is less - * than 2 in size, or if radius < 0 - */ - public RadialGradientPaint(Point2D center, float radius, - float[] fractions, Color[] colors) { - this(center, - radius, - center, - fractions, - colors); - } - - /** - *

      - *

      - * Constructs a RadialGradientPaint. - * - * @param cx the x coordinate in user space of the center point of the - * circle defining the gradient. The last color of the gradient is mapped - * to the perimeter of this circle - * @param cy the y coordinate in user space of the center point of the - * circle defining the gradient. The last color of the gradient is mapped - * to the perimeter of this circle - * @param radius the radius of the circle defining the extents of the - * color gradient - * @param fx the x coordinate of the point in user space to which the - * first color is mapped - * @param fy the y coordinate of the point in user space to which the - * first color is mapped - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors to use in the gradient. The first color - * is used at the focus point, the last color around the perimeter of the - * circle. - * @throws IllegalArgumentException if fractions.length != colors.length, or if colors is less - * than 2 in size, or if radius < 0 - */ - public RadialGradientPaint(float cx, float cy, float radius, - float fx, float fy, - float[] fractions, Color[] colors) { - this(new Point2D.Float(cx, cy), - radius, - new Point2D.Float(fx, fy), - fractions, - colors, - NO_CYCLE, - SRGB); - } - - /** - *

      - *

      - * Constructs a RadialGradientPaint. - * - * @param center the center point, in user space, of the circle defining - * the gradient. The last color of the gradient is mapped to the perimeter - * of this circle - * @param radius the radius of the circle defining the extents of the color - * gradient - * @param focus the point, in user space, to which the first color is - * mapped - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors to use in the gradient. The first color - * is used at the focus point, the last color around the perimeter of the - * circle. - * @throws NullPointerException if one of the points is null - * @throws IllegalArgumentException if fractions.length != colors.length, or if colors is less - * than 2 in size, or if radius < 0 - */ - public RadialGradientPaint(Point2D center, float radius, - Point2D focus, - float[] fractions, Color[] colors) { - this(center, - radius, - focus, - fractions, - colors, - NO_CYCLE, - SRGB); - } - - /** - *

      - *

      - * Constructs a RadialGradientPaint. - * - * @param center the center point in user space of the circle defining the - * gradient. The last color of the gradient is mapped to the perimeter of - * this circle - * @param radius the radius of the circle defining the extents of the color - * gradient - * @param focus the point in user space to which the first color is mapped - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors to use in the gradient. The first color is - * used at the focus point, the last color around the perimeter of the - * circle. - * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT - * @param colorSpace which colorspace to use for interpolation, - * either SRGB or LINEAR_RGB - * @throws NullPointerException if one of the points is null - * @throws IllegalArgumentException if fractions.length != colors.length, or if colors is less - * than 2 in size, or if radius < 0 - */ - public RadialGradientPaint(Point2D center, float radius, - Point2D focus, - float[] fractions, Color[] colors, - CycleMethodEnum cycleMethod, - ColorSpaceEnum colorSpace) { - this(center, - radius, - focus, - fractions, - colors, - cycleMethod, - colorSpace, - new AffineTransform()); - } - - /** - *

      - *

      - * Constructs a RadialGradientPaint. - * - * @param center the center point in user space of the circle defining the - * gradient. The last color of the gradient is mapped to the perimeter of - * this circle - * @param radius the radius of the circle defining the extents of the color - * gradient. - * @param focus the point in user space to which the first color is mapped - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors to use in the gradient. The first color is - * used at the focus point, the last color around the perimeter of the - * circle. - * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT - * @param colorSpace which colorspace to use for interpolation, - * either SRGB or LINEAR_RGB - * @param gradientTransform transform to apply to the gradient - * @throws NullPointerException if one of the points is null, - * or gradientTransform is null - * @throws IllegalArgumentException if fractions.length != colors.length, or if colors is less - * than 2 in size, or if radius < 0 - */ - public RadialGradientPaint(Point2D center, - float radius, - Point2D focus, - float[] fractions, Color[] colors, - CycleMethodEnum cycleMethod, - ColorSpaceEnum colorSpace, - AffineTransform gradientTransform) { - super(fractions, colors, cycleMethod, colorSpace, gradientTransform); - - // Check input arguments - if (center == null) { - throw new NullPointerException("Center point should not be null."); - } - - if (focus == null) { - throw new NullPointerException("Focus point should not be null."); - } - - if (radius <= 0) { - throw new IllegalArgumentException("radius should be greater than zero"); - } - - //copy parameters - this.center = (Point2D) center.clone(); - this.focus = (Point2D) focus.clone(); - this.radius = radius; - } - - /** - *

      - *

      - * Constructs a RadialGradientPaint, the gradient circle is - * defined by a bounding box. - * - * @param gradientBounds the bounding box, in user space, of the circle - * defining outermost extent of the gradient. - * @param fractions numbers ranging from 0.0 to 1.0 specifying the - * distribution of colors along the gradient - * @param colors array of colors to use in the gradient. The first color - * is used at the focus point, the last color around the perimeter of the - * circle. - * @throws NullPointerException if the gradientBounds is null - * @throws IllegalArgumentException if fractions.length != colors.length, or if colors is less - * than 2 in size, or if radius < 0 - */ - public RadialGradientPaint(Rectangle2D gradientBounds, - float[] fractions, Color[] colors) { - - //calculate center point and radius based on bounding box coordinates. - this((float) gradientBounds.getX() + - ((float) gradientBounds.getWidth() / 2), - - (float) gradientBounds.getY() + - ((float) gradientBounds.getWidth() / 2), - - (float) gradientBounds.getWidth() / 2, - fractions, colors); - } - - - /** - * Creates and returns a PaintContext used to generate the color pattern, - * for use by the internal rendering engine. - * - * @param cm {@link ColorModel} that receives - * the Paint data. This is used only as a hint. - * @param deviceBounds the device space bounding box of the - * graphics primitive being rendered - * @param userBounds the user space bounding box of the - * graphics primitive being rendered - * @param transform the {@link AffineTransform} from user - * space into device space - * @param hints the hints that the context object uses to choose - * between rendering alternatives - * @return the {@link PaintContext} that generates color patterns. - * @throws IllegalArgumentException if the transform is not invertible - * @see PaintContext - */ - public PaintContext createContext(ColorModel cm, - Rectangle deviceBounds, - Rectangle2D userBounds, - AffineTransform transform, - RenderingHints hints) { - // Can't modify the transform passed in... - transform = new AffineTransform(transform); - // incorporate the gradient transform - transform.concatenate(gradientTransform); - - try { - return new RadialGradientPaintContext - (cm, deviceBounds, userBounds, transform, hints, - (float) center.getX(), (float) center.getY(), radius, - (float) focus.getX(), (float) focus.getY(), - fractions, colors, cycleMethod, colorSpace); - } catch (NoninvertibleTransformException e) { - throw new IllegalArgumentException("transform should be " + - "invertible"); - } - } - - /** - * Returns a copy of the center point of the radial gradient. - * - * @return a {@link Point2D} object that is a copy of the center point - */ - public Point2D getCenterPoint() { - return new Point2D.Double(center.getX(), center.getY()); - } - - /** - * Returns a copy of the end point of the gradient axis. - * - * @return a {@link Point2D} object that is a copy of the focus point - */ - public Point2D getFocusPoint() { - return new Point2D.Double(focus.getX(), focus.getY()); - } - - /** - * Returns the radius of the circle defining the radial gradient. - * - * @return the radius of the circle defining the radial gradient - */ - public float getRadius() { - return radius; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/RadialGradientPaintContext.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/RadialGradientPaintContext.java deleted file mode 100644 index 26c76ec1dd..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/RadialGradientPaintContext.java +++ /dev/null @@ -1,773 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.graphics.batik.ext.awt; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Rectangle2D; -import java.awt.image.ColorModel; - -/** - * Provides the actual implementation for the RadialGradientPaint. - * This is where the pixel processing is done. A RadialGradienPaint - * only supports circular gradients, but it should be possible to scale - * the circle to look approximately elliptical, by means of a - * gradient transform passed into the RadialGradientPaint constructor. - * - * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans - * @author Vincent Hardy - * @version $Id: RadialGradientPaintContext.java,v 1.1 2008/09/30 20:44:16 patrickc Exp $ - */ -final class RadialGradientPaintContext extends MultipleGradientPaintContext { - - /** - * True when (focus == center) - */ - private boolean isSimpleFocus = false; - /** - * True when (cycleMethod == NO_CYCLE) - */ - private boolean isNonCyclic = false; - /** - * Radius of the outermost circle defining the 100% gradient stop. - */ - private float radius; - /** - * Variables representing center and focus points. - */ - private float centerX, centerY, focusX, focusY; - /** - * Radius of the gradient circle squared. - */ - private float radiusSq; - /** - * Constant part of X, Y user space coordinates. - */ - private float constA, constB; - /** - * This value represents the solution when focusX == X. It is called - * trivial because it is easier to calculate than the general case. - */ - private float trivial; - - private static final int FIXED_POINT_IMPL = 1; - private static final int DEFAULT_IMPL = 2; - private static final int ANTI_ALIAS_IMPL = 3; - - private int fillMethod; - /** - * Amount for offset when clamping focus. - */ - private static final float SCALEBACK = 0.999f; - - /** - * Constructor for RadialGradientPaintContext. - * - * @param cm {@link ColorModel} that receives - * the Paint data. This is used only as a hint. - * @param deviceBounds the device space bounding box of the - * graphics primitive being rendered - * @param userBounds the user space bounding box of the - * graphics primitive being rendered - * @param t the {@link AffineTransform} from user - * space into device space (gradientTransform should be - * concatenated with this) - * @param hints the hints that the context object uses to choose - * between rendering alternatives - * @param cx the center point in user space of the circle defining - * the gradient. The last color of the gradient is mapped to the - * perimeter of this circle X coordinate - * @param cy the center point in user space of the circle defining - * the gradient. The last color of the gradient is mapped to the - * perimeter of this circle Y coordinate - * @param r the radius of the circle defining the extents of the - * color gradient - * @param fx the point in user space to which the first color is mapped - * X coordinate - * @param fy the point in user space to which the first color is mapped - * Y coordinate - * @param fractions the fractions specifying the gradient distribution - * @param colors the gradient colors - * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT - * @param colorSpace which colorspace to use for interpolation, - * either SRGB or LINEAR_RGB - */ - public RadialGradientPaintContext(ColorModel cm, - Rectangle deviceBounds, - Rectangle2D userBounds, - AffineTransform t, - RenderingHints hints, - float cx, float cy, - float r, - float fx, float fy, - float[] fractions, - Color[] colors, - MultipleGradientPaint.CycleMethodEnum - cycleMethod, - MultipleGradientPaint.ColorSpaceEnum - colorSpace) - throws NoninvertibleTransformException { - super(cm, deviceBounds, userBounds, t, hints, fractions, colors, - cycleMethod, colorSpace); - - //copy some parameters. - centerX = cx; - centerY = cy; - focusX = fx; - focusY = fy; - radius = r; - - this.isSimpleFocus = (focusX == centerX) && (focusY == centerY); - this.isNonCyclic = (cycleMethod == RadialGradientPaint.NO_CYCLE); - - //for use in the quadractic equation - radiusSq = radius * radius; - - float dX = focusX - centerX; - float dY = focusY - centerY; - - double dist = Math.sqrt((dX * dX) + (dY * dY)); - - //test if distance from focus to center is greater than the radius - if (dist > radius * SCALEBACK) { //clamp focus to radius - double angle = Math.atan2(dY, dX); - - //x = r cos theta, y = r sin theta - focusX = (float) (SCALEBACK * radius * Math.cos(angle)) + centerX; - - focusY = (float) (SCALEBACK * radius * Math.sin(angle)) + centerY; - } - - //calculate the solution to be used in the case where X == focusX - //in cyclicCircularGradientFillRaster - dX = focusX - centerX; - trivial = (float) Math.sqrt(radiusSq - (dX * dX)); - - // constant parts of X, Y user space coordinates - constA = a02 - centerX; - constB = a12 - centerY; - - Object colorRend = hints.get(RenderingHints.KEY_COLOR_RENDERING); - Object rend = hints.get(RenderingHints.KEY_RENDERING); - - fillMethod = 0; - - if ((rend == RenderingHints.VALUE_RENDER_QUALITY) || - (colorRend == RenderingHints.VALUE_COLOR_RENDER_QUALITY)) { - // System.out.println("AAHints set: " + rend + ", " + colorRend); - fillMethod = ANTI_ALIAS_IMPL; - } - - if ((rend == RenderingHints.VALUE_RENDER_SPEED) || - (colorRend == RenderingHints.VALUE_COLOR_RENDER_SPEED)) { - // System.out.println("SPHints set: " + rend + ", " + colorRend); - fillMethod = DEFAULT_IMPL; - } - - // We are in the 'default' case, no hint or hint set to - // DEFAULT values... - if (fillMethod == 0) { - // For now we will always use the 'default' impl if - // one is not specified. - fillMethod = DEFAULT_IMPL; - - if (false) { - // This could be used for a 'smart' choice in - // the default case, if the gradient has obvious - // discontinuites use AA, otherwise default - if (hasDiscontinuity) { - fillMethod = ANTI_ALIAS_IMPL; - } else { - fillMethod = DEFAULT_IMPL; - } - } - } - - if ((fillMethod == DEFAULT_IMPL) && - (isSimpleFocus && isNonCyclic && isSimpleLookup)) { - this.calculateFixedPointSqrtLookupTable(); - fillMethod = FIXED_POINT_IMPL; - } - } - - /** - * Return a Raster containing the colors generated for the graphics - * operation. - * - * @param x The x coordinate of the area in device space for which colors - * are generated. - * @param y The y coordinate of the area in device space for which colors - * are generated. - * @param w The width of the area in device space for which colors - * are generated. - * @param h The height of the area in device space for which colors - * are generated. - */ - protected void fillRaster(int[] pixels, int off, int adjust, - int x, int y, int w, int h) { - switch (fillMethod) { - case FIXED_POINT_IMPL: - // System.out.println("Calling FP"); - fixedPointSimplestCaseNonCyclicFillRaster(pixels, off, adjust, x, - y, w, h); - break; - case ANTI_ALIAS_IMPL: - // System.out.println("Calling AA"); - antiAliasFillRaster(pixels, off, adjust, x, y, w, h); - break; - case DEFAULT_IMPL: - default: - // System.out.println("Calling Default"); - cyclicCircularGradientFillRaster(pixels, off, adjust, x, y, w, h); - } - } - - /** - * This code works in the simplest of cases, where the focus == center - * point, the gradient is noncyclic, and the gradient lookup method is - * fast (single array index, no conversion necessary). - */ - private void fixedPointSimplestCaseNonCyclicFillRaster(int[] pixels, - int off, - int adjust, - int x, int y, - int w, int h) { - float iSq = 0; // Square distance index - final float indexFactor = fastGradientArraySize / radius; - - //constant part of X and Y coordinates for the entire raster - final float constX = (a00 * x) + (a01 * y) + constA; - final float constY = (a10 * x) + (a11 * y) + constB; - final float deltaX = indexFactor * a00; //incremental change in dX - final float deltaY = indexFactor * a10; //incremental change in dY - float dX, dY; //the current distance from center - final int fixedArraySizeSq = - (fastGradientArraySize * fastGradientArraySize); - float g, gDelta, gDeltaDelta, temp; //gradient square value - int gIndex; // integer number used to index gradient array - int iSqInt; // Square distance index - - int end, j; //indexing variables - int indexer = off;//used to index pixels array - - temp = ((deltaX * deltaX) + (deltaY * deltaY)); - gDeltaDelta = ((temp * 2)); - - if (temp > fixedArraySizeSq) { - // This combination of scale and circle radius means - // essentially no pixels will be anything but the end - // stop color. This also avoids math problems. - final int val = gradientOverflow; - for (j = 0; j < h; j++) { //for every row - //for every column (inner loop begins here) - for (end = indexer + w; indexer < end; indexer++) - pixels[indexer] = val; - indexer += adjust; - } - return; - } - - // For every point in the raster, calculate the color at that point - for (j = 0; j < h; j++) { //for every row - //x and y (in user space) of the first pixel of this row - dX = indexFactor * ((a01 * j) + constX); - dY = indexFactor * ((a11 * j) + constY); - - // these values below here allow for an incremental calculation - // of dX^2 + dY^2 - - //initialize to be equal to distance squared - g = (((dY * dY) + (dX * dX))); - gDelta = (deltaY * dY + deltaX * dX) * 2 + temp; - - //for every column (inner loop begins here) - for (end = indexer + w; indexer < end; indexer++) { - //determine the distance to the center - - //since this is a non cyclic fill raster, crop at "1" and 0 - if (g >= fixedArraySizeSq) { - pixels[indexer] = gradientOverflow; - } - - // This should not happen as gIndex is a square - // quantity. Code commented out on purpose, can't underflow. - // else if (g < 0) { - // gIndex = 0; - // } - - else { - iSq = (g * invSqStepFloat); - - iSqInt = (int) iSq; //chop off fractional part - iSq -= iSqInt; - gIndex = sqrtLutFixed[iSqInt]; - gIndex += (int) (iSq * (sqrtLutFixed[iSqInt + 1] - gIndex)); - pixels[indexer] = gradient[gIndex]; - } - - - //incremental calculation - g += gDelta; - gDelta += gDeltaDelta; - } - indexer += adjust; - } - } - - /** - * Length of a square distance intervale in the lookup table - */ - private float invSqStepFloat; - - /** - * Used to limit the size of the square root lookup table - */ - private static final int MAX_PRECISION = 256; - - /** - * Square root lookup table - */ - private int[] sqrtLutFixed = new int[MAX_PRECISION]; - - /** - * Build square root lookup table - */ - private void calculateFixedPointSqrtLookupTable() { - float sqStepFloat; - sqStepFloat = (fastGradientArraySize * fastGradientArraySize) - / (MAX_PRECISION - 2.0f); - - // The last two values are the same so that linear square root - // interpolation can happen on the maximum reachable element in the - // lookup table (precision-2) - int[] workTbl = sqrtLutFixed; // local is cheaper - int i; - for (i = 0; i < MAX_PRECISION - 1; i++) { - workTbl[i] = (int) Math.sqrt(i * sqStepFloat); - } - workTbl[i] = workTbl[i - 1]; - invSqStepFloat = 1.0f / sqStepFloat; - } - - /** - * Fill the raster, cycling the gradient colors when a point falls outside - * of the perimeter of the 100% stop circle. - *

      - * This calculation first computes the intersection point of the line - * from the focus through the current point in the raster, and the - * perimeter of the gradient circle. - *

      - * Then it determines the percentage distance of the current point along - * that line (focus is 0%, perimeter is 100%). - *

      - * Equation of a circle centered at (a,b) with radius r: - * (x-a)^2 + (y-b)^2 = r^2 - * Equation of a line with slope m and y-intercept b - * y = mx + b - * replacing y in the cirlce equation and solving using the quadratic - * formula produces the following set of equations. Constant factors have - * been extracted out of the inner loop. - */ - private void cyclicCircularGradientFillRaster(int[] pixels, int off, - int adjust, - int x, int y, - int w, int h) { - // Constant part of the C factor of the quadratic equation - final double constC = - -(radiusSq) + (centerX * centerX) + (centerY * centerY); - double A; //coefficient of the quadratic equation (Ax^2 + Bx + C = 0) - double B; //coefficient of the quadratic equation - double C; //coefficient of the quadratic equation - double slope; //slope of the focus-perimeter line - double yintcpt; //y-intercept of the focus-perimeter line - double solutionX;//intersection with circle X coordinate - double solutionY;//intersection with circle Y coordinate - final float constX = (a00 * x) + (a01 * y) + a02;//const part of X coord - final float constY = (a10 * x) + (a11 * y) + a12; //const part of Y coord - final float precalc2 = 2 * centerY;//const in inner loop quad. formula - final float precalc3 = -2 * centerX;//const in inner loop quad. formula - float X; // User space point X coordinate - float Y; // User space point Y coordinate - float g;//value between 0 and 1 specifying position in the gradient - float det; //determinant of quadratic formula (should always be >0) - float currentToFocusSq;//sq distance from the current pt. to focus - float intersectToFocusSq;//sq distance from the intersect pt. to focus - float deltaXSq; //temp variable for a change in X squared. - float deltaYSq; //temp variable for a change in Y squared. - int indexer = off; //index variable for pixels array - int i, j; //indexing variables for FOR loops - int pixInc = w + adjust;//incremental index change for pixels array - - for (j = 0; j < h; j++) { //for every row - - X = (a01 * j) + constX; //constants from column to column - Y = (a11 * j) + constY; - - //for every column (inner loop begins here) - for (i = 0; i < w; i++) { - - // special case to avoid divide by zero or very near zero - if (((X - focusX) > -0.000001f) && - ((X - focusX) < 0.000001f)) { - solutionX = focusX; - - solutionY = centerY; - - solutionY += (Y > focusY) ? trivial : -trivial; - } else { - - //slope of the focus-current line - slope = (Y - focusY) / (X - focusX); - - yintcpt = Y - (slope * X); //y-intercept of that same line - - //use the quadratic formula to calculate the intersection - //point - A = (slope * slope) + 1; - - B = precalc3 + (-2 * slope * (centerY - yintcpt)); - - C = constC + (yintcpt * (yintcpt - precalc2)); - - det = (float) Math.sqrt((B * B) - (4 * A * C)); - - solutionX = -B; - - //choose the positive or negative root depending - //on where the X coord lies with respect to the focus. - solutionX += (X < focusX) ? -det : det; - - solutionX = solutionX / (2 * A);//divisor - - solutionY = (slope * solutionX) + yintcpt; - } - - //calculate the square of the distance from the current point - //to the focus and the square of the distance from the - //intersection point to the focus. Want the squares so we can - //do 1 square root after division instead of 2 before. - - deltaXSq = (float) solutionX - focusX; - deltaXSq = deltaXSq * deltaXSq; - - deltaYSq = (float) solutionY - focusY; - deltaYSq = deltaYSq * deltaYSq; - - intersectToFocusSq = deltaXSq + deltaYSq; - - deltaXSq = X - focusX; - deltaXSq = deltaXSq * deltaXSq; - - deltaYSq = Y - focusY; - deltaYSq = deltaYSq * deltaYSq; - - currentToFocusSq = deltaXSq + deltaYSq; - - //want the percentage (0-1) of the current point along the - //focus-circumference line - g = (float) Math.sqrt(currentToFocusSq / intersectToFocusSq); - - //Get the color at this point - pixels[indexer + i] = indexIntoGradientsArrays(g); - - X += a00; //incremental change in X, Y - Y += a10; - } //end inner loop - indexer += pixInc; - } //end outer loop - } - - - /** - * Fill the raster, cycling the gradient colors when a point - * falls outside of the perimeter of the 100% stop circle. Use - * the anti-aliased gradient lookup. - *

      - * This calculation first computes the intersection point of the line - * from the focus through the current point in the raster, and the - * perimeter of the gradient circle. - *

      - * Then it determines the percentage distance of the current point along - * that line (focus is 0%, perimeter is 100%). - *

      - * Equation of a circle centered at (a,b) with radius r: - * (x-a)^2 + (y-b)^2 = r^2 - * Equation of a line with slope m and y-intercept b - * y = mx + b - * replacing y in the cirlce equation and solving using the quadratic - * formula produces the following set of equations. Constant factors have - * been extracted out of the inner loop. - */ - private void antiAliasFillRaster(int[] pixels, int off, - int adjust, - int x, int y, - int w, int h) { - // Constant part of the C factor of the quadratic equation - final double constC = - -(radiusSq) + (centerX * centerX) + (centerY * centerY); - //coefficients of the quadratic equation (Ax^2 + Bx + C = 0) - final float precalc2 = 2 * centerY;//const in inner loop quad. formula - final float precalc3 = -2 * centerX;//const in inner loop quad. formula - - //const part of X,Y coord (shifted to bottom left corner of pixel. - final float constX = (a00 * (x - .5f)) + (a01 * (y + .5f)) + a02; - final float constY = (a10 * (x - .5f)) + (a11 * (y + .5f)) + a12; - float X; // User space point X coordinate - float Y; // User space point Y coordinate - int i, j; //indexing variables for FOR loops - int indexer = off - 1; //index variable for pixels array - - double[] prevGs = new double[w + 1]; - double deltaXSq, deltaYSq; - double solutionX, solutionY; - double slope, yintcpt, A, B, C, det; - double intersectToFocusSq, currentToFocusSq; - double g00, g01, g10, g11; - - // Set X,Y to top left corner of first pixel of first row. - X = constX - a01; - Y = constY - a11; - - // Calc top row of g's. - for (i = 0; i <= w; i++) { - final float dx = X - focusX; - - // special case to avoid divide by zero or very near zero - if ((dx > -0.000001f) && - (dx < 0.000001f)) { - solutionX = focusX; - solutionY = centerY; - solutionY += (Y > focusY) ? trivial : -trivial; - } else { - // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0 - // Formula line: Y = Slope*x + Y0; - // - // So you substitue line into Circle and apply - // Quadradic formula. - - - //slope of the focus-current line - slope = (Y - focusY) / (X - focusX); - - yintcpt = Y - (slope * X); //y-intercept of that same line - - //use the quadratic formula to calculate the intersection - //point - A = (slope * slope) + 1; - - B = precalc3 + (-2 * slope * (centerY - yintcpt)); - - C = constC + (yintcpt * (yintcpt - precalc2)); - - det = Math.sqrt((B * B) - (4 * A * C)); - - solutionX = -B; - - //choose the positive or negative root depending - //on where the X coord lies with respect to the focus. - solutionX += (X < focusX) ? -det : det; - - solutionX = solutionX / (2 * A);//divisor - - solutionY = (slope * solutionX) + yintcpt; - } - - //calculate the square of the distance from the current point - //to the focus and the square of the distance from the - //intersection point to the focus. Want the squares so we can - //do 1 square root after division instead of 2 before. - deltaXSq = solutionX - focusX; - deltaXSq = deltaXSq * deltaXSq; - - deltaYSq = solutionY - focusY; - deltaYSq = deltaYSq * deltaYSq; - - intersectToFocusSq = deltaXSq + deltaYSq; - - deltaXSq = X - focusX; - deltaXSq = deltaXSq * deltaXSq; - - deltaYSq = Y - focusY; - deltaYSq = deltaYSq * deltaYSq; - - currentToFocusSq = deltaXSq + deltaYSq; - - //want the percentage (0-1) of the current point along the - //focus-circumference line - prevGs[i] = Math.sqrt(currentToFocusSq / intersectToFocusSq); - - X += a00; //incremental change in X, Y - Y += a10; - } - - for (j = 0; j < h; j++) { //for every row - - // Set X,Y to bottom edge of pixel row. - X = (a01 * j) + constX; //constants from row to row - Y = (a11 * j) + constY; - - g10 = prevGs[0]; - - float dx = X - focusX; - // special case to avoid divide by zero or very near zero - if ((dx > -0.000001f) && - (dx < 0.000001f)) { - solutionX = focusX; - solutionY = centerY; - solutionY += (Y > focusY) ? trivial : -trivial; - } else { - // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0 - // Formula line: Y = Slope*x + Y0; - // - // So you substitue line into Circle and apply - // Quadradic formula. - - - //slope of the focus-current line - slope = (Y - focusY) / (X - focusX); - - yintcpt = Y - (slope * X); //y-intercept of that same line - - //use the quadratic formula to calculate the intersection - //point - A = (slope * slope) + 1; - - B = precalc3 + (-2 * slope * (centerY - yintcpt)); - - C = constC + (yintcpt * (yintcpt - precalc2)); - - det = Math.sqrt((B * B) - (4 * A * C)); - - solutionX = -B; - - //choose the positive or negative root depending - //on where the X coord lies with respect to the focus. - solutionX += (X < focusX) ? -det : det; - - solutionX = solutionX / (2 * A);//divisor - - solutionY = (slope * solutionX) + yintcpt; - } - - //calculate the square of the distance from the current point - //to the focus and the square of the distance from the - //intersection point to the focus. Want the squares so we can - //do 1 square root after division instead of 2 before. - deltaXSq = solutionX - focusX; - deltaXSq = deltaXSq * deltaXSq; - - deltaYSq = solutionY - focusY; - deltaYSq = deltaYSq * deltaYSq; - - intersectToFocusSq = deltaXSq + deltaYSq; - - deltaXSq = X - focusX; - deltaXSq = deltaXSq * deltaXSq; - - deltaYSq = Y - focusY; - deltaYSq = deltaYSq * deltaYSq; - - currentToFocusSq = deltaXSq + deltaYSq; - g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq); - prevGs[0] = g11; - - X += a00; //incremental change in X, Y - Y += a10; - - //for every column (inner loop begins here) - for (i = 1; i <= w; i++) { - g00 = g10; - g01 = g11; - g10 = prevGs[i]; - - dx = X - focusX; - // special case to avoid divide by zero or very near zero - if ((dx > -0.000001f) && - (dx < 0.000001f)) { - solutionX = focusX; - solutionY = centerY; - solutionY += (Y > focusY) ? trivial : -trivial; - } else { - // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0 - // Formula line: Y = Slope*x + Y0; - // - // So you substitue line into Circle and apply - // Quadradic formula. - - - //slope of the focus-current line - slope = (Y - focusY) / (X - focusX); - - yintcpt = Y - (slope * X); //y-intercept of that same line - - //use the quadratic formula to calculate the intersection - //point - A = (slope * slope) + 1; - - B = precalc3 + (-2 * slope * (centerY - yintcpt)); - - C = constC + (yintcpt * (yintcpt - precalc2)); - - det = Math.sqrt((B * B) - (4 * A * C)); - - solutionX = -B; - - //choose the positive or negative root depending - //on where the X coord lies with respect to the focus. - solutionX += (X < focusX) ? -det : det; - - solutionX = solutionX / (2 * A);//divisor - - solutionY = (slope * solutionX) + yintcpt; - } - - //calculate the square of the distance from the current point - //to the focus and the square of the distance from the - //intersection point to the focus. Want the squares so we can - //do 1 square root after division instead of 2 before. - deltaXSq = solutionX - focusX; - deltaXSq = deltaXSq * deltaXSq; - - deltaYSq = solutionY - focusY; - deltaYSq = deltaYSq * deltaYSq; - - intersectToFocusSq = deltaXSq + deltaYSq; - - deltaXSq = X - focusX; - deltaXSq = deltaXSq * deltaXSq; - - deltaYSq = Y - focusY; - deltaYSq = deltaYSq * deltaYSq; - - currentToFocusSq = deltaXSq + deltaYSq; - g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq); - prevGs[i] = g11; - - //Get the color at this point - pixels[indexer + i] = indexGradientAntiAlias - ((float) ((g00 + g01 + g10 + g11) / 4), - (float) Math.max(Math.abs(g11 - g00), - Math.abs(g10 - g01))); - - X += a00; //incremental change in X, Y - Y += a10; - } //end inner loop - indexer += (w + adjust); - } //end outer loop - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/image/GraphicsUtil.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/image/GraphicsUtil.java deleted file mode 100644 index 0519ada71f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/batik/ext/awt/image/GraphicsUtil.java +++ /dev/null @@ -1,1012 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.graphics.batik.ext.awt.image; - -import java.awt.*; -import java.awt.color.ColorSpace; -import java.awt.geom.AffineTransform; -import java.awt.image.*; - - -/** - * Set of utility methods for Graphics. - * These generally bypass broken methods in Java2D or provide tweaked - * implementations. - * - * @author Thomas DeWeese - * @version $Id: GraphicsUtil.java,v 1.1 2008/09/30 20:44:16 patrickc Exp $ - */ -public class GraphicsUtil { - - public static AffineTransform IDENTITY = new AffineTransform(); - - /** - * Standard prebuilt Linear_sRGB color model with no alpha - */ - public static final ColorModel Linear_sRGB = - new DirectColorModel(ColorSpace.getInstance - (ColorSpace.CS_LINEAR_RGB), 24, - 0x00FF0000, 0x0000FF00, - 0x000000FF, 0x0, false, - DataBuffer.TYPE_INT); - /** - * Standard prebuilt Linear_sRGB color model with premultiplied alpha. - */ - public static final ColorModel Linear_sRGB_Pre = - new DirectColorModel(ColorSpace.getInstance - (ColorSpace.CS_LINEAR_RGB), 32, - 0x00FF0000, 0x0000FF00, - 0x000000FF, 0xFF000000, true, - DataBuffer.TYPE_INT); - /** - * Standard prebuilt Linear_sRGB color model with unpremultiplied alpha. - */ - public static final ColorModel Linear_sRGB_Unpre = - new DirectColorModel(ColorSpace.getInstance - (ColorSpace.CS_LINEAR_RGB), 32, - 0x00FF0000, 0x0000FF00, - 0x000000FF, 0xFF000000, false, - DataBuffer.TYPE_INT); - /** - * Standard prebuilt sRGB color model with no alpha. - */ - public static final ColorModel sRGB = - new DirectColorModel(ColorSpace.getInstance - (ColorSpace.CS_sRGB), 24, - 0x00FF0000, 0x0000FF00, - 0x000000FF, 0x0, false, - DataBuffer.TYPE_INT); - /** - * Standard prebuilt sRGB color model with premultiplied alpha. - */ - public static final ColorModel sRGB_Pre = - new DirectColorModel(ColorSpace.getInstance - (ColorSpace.CS_sRGB), 32, - 0x00FF0000, 0x0000FF00, - 0x000000FF, 0xFF000000, true, - DataBuffer.TYPE_INT); - /** - * Standard prebuilt sRGB color model with unpremultiplied alpha. - */ - public static final ColorModel sRGB_Unpre = - new DirectColorModel(ColorSpace.getInstance - (ColorSpace.CS_sRGB), 32, - 0x00FF0000, 0x0000FF00, - 0x000000FF, 0xFF000000, false, - DataBuffer.TYPE_INT); - - /** - * Method that returns either Linear_sRGB_Pre or Linear_sRGB_UnPre - * based on premult flag. - * - * @param premult True if the ColorModel should have premultiplied alpha. - * @return a ColorMdoel with Linear sRGB colorSpace and - * the alpha channel set in accordance with - * premult - */ - public static ColorModel makeLinear_sRGBCM(boolean premult) { - - return premult ? Linear_sRGB_Pre : Linear_sRGB_Unpre; - } - - /** - * Constructs a BufferedImage with a linear sRGB colorModel, and alpha. - * - * @param width The desired width of the BufferedImage - * @param height The desired height of the BufferedImage - * @param premult The desired state of alpha premultiplied - * @return The requested BufferedImage. - */ - public static BufferedImage makeLinearBufferedImage(int width, - int height, - boolean premult) { - ColorModel cm = makeLinear_sRGBCM(premult); - WritableRaster wr = cm.createCompatibleWritableRaster(width, height); - return new BufferedImage(cm, wr, premult, null); - } - - /** - * An internal optimized version of copyData designed to work on - * Integer packed data with a SinglePixelPackedSampleModel. Only - * the region of overlap between src and dst is copied. - *

      - * Calls to this should be preflighted with is_INT_PACK_Data - * on both src and dest (requireAlpha can be false). - * - * @param src The source of the data - * @param dst The destination for the data. - */ - public static void copyData_INT_PACK(Raster src, WritableRaster dst) { - // System.out.println("Fast copyData"); - int x0 = dst.getMinX(); - if (x0 < src.getMinX()) x0 = src.getMinX(); - - int y0 = dst.getMinY(); - if (y0 < src.getMinY()) y0 = src.getMinY(); - - int x1 = dst.getMinX() + dst.getWidth() - 1; - if (x1 > src.getMinX() + src.getWidth() - 1) - x1 = src.getMinX() + src.getWidth() - 1; - - int y1 = dst.getMinY() + dst.getHeight() - 1; - if (y1 > src.getMinY() + src.getHeight() - 1) - y1 = src.getMinY() + src.getHeight() - 1; - - int width = x1 - x0 + 1; - int height = y1 - y0 + 1; - - SinglePixelPackedSampleModel srcSPPSM; - srcSPPSM = (SinglePixelPackedSampleModel) src.getSampleModel(); - - final int srcScanStride = srcSPPSM.getScanlineStride(); - DataBufferInt srcDB = (DataBufferInt) src.getDataBuffer(); - final int[] srcPixels = srcDB.getBankData()[0]; - final int srcBase = - (srcDB.getOffset() + - srcSPPSM.getOffset(x0 - src.getSampleModelTranslateX(), - y0 - src.getSampleModelTranslateY())); - - - SinglePixelPackedSampleModel dstSPPSM; - dstSPPSM = (SinglePixelPackedSampleModel) dst.getSampleModel(); - - final int dstScanStride = dstSPPSM.getScanlineStride(); - DataBufferInt dstDB = (DataBufferInt) dst.getDataBuffer(); - final int[] dstPixels = dstDB.getBankData()[0]; - final int dstBase = - (dstDB.getOffset() + - dstSPPSM.getOffset(x0 - dst.getSampleModelTranslateX(), - y0 - dst.getSampleModelTranslateY())); - - if ((srcScanStride == dstScanStride) && - (srcScanStride == width)) { - // System.out.println("VERY Fast copyData"); - - System.arraycopy(srcPixels, srcBase, dstPixels, dstBase, - width * height); - } else if (width > 128) { - int srcSP = srcBase; - int dstSP = dstBase; - for (int y = 0; y < height; y++) { - System.arraycopy(srcPixels, srcSP, dstPixels, dstSP, width); - srcSP += srcScanStride; - dstSP += dstScanStride; - } - } else { - for (int y = 0; y < height; y++) { - int srcSP = srcBase + y * srcScanStride; - int dstSP = dstBase + y * dstScanStride; - for (int x = 0; x < width; x++) - dstPixels[dstSP++] = srcPixels[srcSP++]; - } - } - } - - public static void copyData_FALLBACK(Raster src, WritableRaster dst) { - // System.out.println("Fallback copyData"); - - int x0 = dst.getMinX(); - if (x0 < src.getMinX()) x0 = src.getMinX(); - - int y0 = dst.getMinY(); - if (y0 < src.getMinY()) y0 = src.getMinY(); - - int x1 = dst.getMinX() + dst.getWidth() - 1; - if (x1 > src.getMinX() + src.getWidth() - 1) - x1 = src.getMinX() + src.getWidth() - 1; - - int y1 = dst.getMinY() + dst.getHeight() - 1; - if (y1 > src.getMinY() + src.getHeight() - 1) - y1 = src.getMinY() + src.getHeight() - 1; - - int width = x1 - x0 + 1; - int[] data = null; - - for (int y = y0; y <= y1; y++) { - data = src.getPixels(x0, y, width, 1, data); - dst.setPixels(x0, y, width, 1, data); - } - } - - /** - * Copies data from one raster to another. Only the region of - * overlap between src and dst is copied. Src and - * Dst must have compatible SampleModels. - * - * @param src The source of the data - * @param dst The destination for the data. - */ - public static void copyData(Raster src, WritableRaster dst) { - if (is_INT_PACK_Data(src.getSampleModel(), false) && - is_INT_PACK_Data(dst.getSampleModel(), false)) { - copyData_INT_PACK(src, dst); - return; - } - - copyData_FALLBACK(src, dst); - } - - /** - * Creates a new raster that has a copy of the data in - * ras. This is highly optimized for speed. There is - * no provision for changing any aspect of the SampleModel. - *

      - * This method should be used when you need to change the contents - * of a Raster that you do not "own" (ie the result of a - * getData call). - * - * @param ras The Raster to copy. - * @return A writable copy of ras - */ - public static WritableRaster copyRaster(Raster ras) { - return copyRaster(ras, ras.getMinX(), ras.getMinY()); - } - - - /** - * Creates a new raster that has a copy of the data in - * ras. This is highly optimized for speed. There is - * no provision for changing any aspect of the SampleModel. - * However you can specify a new location for the returned raster. - *

      - * This method should be used when you need to change the contents - * of a Raster that you do not "own" (ie the result of a - * getData call). - * - * @param ras The Raster to copy. - * @param minX The x location for the upper left corner of the - * returned WritableRaster. - * @param minY The y location for the upper left corner of the - * returned WritableRaster. - * @return A writable copy of ras - */ - public static WritableRaster copyRaster(Raster ras, int minX, int minY) { - WritableRaster ret = Raster.createWritableRaster - (ras.getSampleModel(), - new Point(0, 0)); - ret = ret.createWritableChild - (ras.getMinX() - ras.getSampleModelTranslateX(), - ras.getMinY() - ras.getSampleModelTranslateY(), - ras.getWidth(), ras.getHeight(), - minX, minY, null); - - // Use System.arraycopy to copy the data between the two... - DataBuffer srcDB = ras.getDataBuffer(); - DataBuffer retDB = ret.getDataBuffer(); - if (srcDB.getDataType() != retDB.getDataType()) { - throw new IllegalArgumentException - ("New DataBuffer doesn't match original"); - } - int len = srcDB.getSize(); - int banks = srcDB.getNumBanks(); - int[] offsets = srcDB.getOffsets(); - for (int b = 0; b < banks; b++) { - switch (srcDB.getDataType()) { - case DataBuffer.TYPE_BYTE: { - DataBufferByte srcDBT = (DataBufferByte) srcDB; - DataBufferByte retDBT = (DataBufferByte) retDB; - System.arraycopy(srcDBT.getData(b), offsets[b], - retDBT.getData(b), offsets[b], len); - break; - } - case DataBuffer.TYPE_INT: { - DataBufferInt srcDBT = (DataBufferInt) srcDB; - DataBufferInt retDBT = (DataBufferInt) retDB; - System.arraycopy(srcDBT.getData(b), offsets[b], - retDBT.getData(b), offsets[b], len); - break; - } - case DataBuffer.TYPE_SHORT: { - DataBufferShort srcDBT = (DataBufferShort) srcDB; - DataBufferShort retDBT = (DataBufferShort) retDB; - System.arraycopy(srcDBT.getData(b), offsets[b], - retDBT.getData(b), offsets[b], len); - break; - } - case DataBuffer.TYPE_USHORT: { - DataBufferUShort srcDBT = (DataBufferUShort) srcDB; - DataBufferUShort retDBT = (DataBufferUShort) retDB; - System.arraycopy(srcDBT.getData(b), offsets[b], - retDBT.getData(b), offsets[b], len); - break; - } - } - } - - return ret; - } - - /** - * Coerces ras to be writable. The returned Raster continues to - * reference the DataBuffer from ras, so modifications to the returned - * WritableRaster will be seen in ras.

      - *

      - * This method should only be used if you need a WritableRaster due to - * an interface (such as to construct a BufferedImage), but have no - * intention of modifying the contents of the returned Raster. If - * you have any doubt about other users of the data in ras, - * use copyRaster (above). - * - * @param ras The raster to make writable. - * @return A Writable version of ras (shares DataBuffer with - * ras). - */ - public static WritableRaster makeRasterWritable(Raster ras) { - return makeRasterWritable(ras, ras.getMinX(), ras.getMinY()); - } - - /** - * Coerces ras to be writable. The returned Raster continues to - * reference the DataBuffer from ras, so modifications to the returned - * WritableRaster will be seen in ras.

      - *

      - * You can specify a new location for the returned WritableRaster, this - * is especially useful for constructing BufferedImages which require - * the Raster to be at (0,0). - *

      - * This method should only be used if you need a WritableRaster due to - * an interface (such as to construct a BufferedImage), but have no - * intention of modifying the contents of the returned Raster. If - * you have any doubt about other users of the data in ras, - * use copyRaster (above). - * - * @param ras The raster to make writable. - * @param minX The x location for the upper left corner of the - * returned WritableRaster. - * @param minY The y location for the upper left corner of the - * returned WritableRaster. - * @return A Writable version of ras with it's upper left - * hand coordinate set to minX, minY (shares it's DataBuffer - * with ras). - */ - public static WritableRaster makeRasterWritable(Raster ras, - int minX, int minY) { - WritableRaster ret = Raster.createWritableRaster - (ras.getSampleModel(), - ras.getDataBuffer(), - new Point(0, 0)); - ret = ret.createWritableChild - (ras.getMinX() - ras.getSampleModelTranslateX(), - ras.getMinY() - ras.getSampleModelTranslateY(), - ras.getWidth(), ras.getHeight(), - minX, minY, null); - return ret; - } - - /** - * Create a new ColorModel with it's alpha premultiplied state matching - * newAlphaPreMult. - * - * @param cm The ColorModel to change the alpha premult state of. - * @param newAlphaPreMult The new state of alpha premult. - * @return A new colorModel that has isAlphaPremultiplied() - * equal to newAlphaPreMult. - */ - public static ColorModel - coerceColorModel(ColorModel cm, boolean newAlphaPreMult) { - if (cm.isAlphaPremultiplied() == newAlphaPreMult) - return cm; - - // Easiest way to build proper colormodel for new Alpha state... - // Eventually this should switch on known ColorModel types and - // only fall back on this hack when the CM type is unknown. - WritableRaster wr = cm.createCompatibleWritableRaster(1, 1); - return cm.coerceData(wr, newAlphaPreMult); - } - - /** - * Coerces data within a bufferedImage to match newAlphaPreMult, - * Note that this can not change the colormodel of bi so you - * - * @param wr The raster to change the state of. - * @param cm The colormodel currently associated with data in wr. - * @param newAlphaPreMult The desired state of alpha Premult for raster. - * @return A new colormodel that matches newAlphaPreMult. - */ - public static ColorModel - coerceData(WritableRaster wr, ColorModel cm, boolean newAlphaPreMult) { - - // System.out.println("CoerceData: " + cm.isAlphaPremultiplied() + - // " Out: " + newAlphaPreMult); - if (!cm.hasAlpha()) - // Nothing to do no alpha channel - return cm; - - if (cm.isAlphaPremultiplied() == newAlphaPreMult) - // nothing to do alpha state matches... - return cm; - - // System.out.println("CoerceData: " + wr.getSampleModel()); - - if (newAlphaPreMult) { - multiplyAlpha(wr); - } else { - divideAlpha(wr); - } - - return coerceColorModel(cm, newAlphaPreMult); - } - - public static void multiplyAlpha(WritableRaster wr) { - if (is_BYTE_COMP_Data(wr.getSampleModel())) - mult_BYTE_COMP_Data(wr); - else if (is_INT_PACK_Data(wr.getSampleModel(), true)) - mult_INT_PACK_Data(wr); - else { - int[] pixel = null; - int bands = wr.getNumBands(); - float norm = 1.0f / 255f; - int x0, x1, y0, y1, a, b; - float alpha; - x0 = wr.getMinX(); - x1 = x0 + wr.getWidth(); - y0 = wr.getMinY(); - y1 = y0 + wr.getHeight(); - for (int y = y0; y < y1; y++) - for (int x = x0; x < x1; x++) { - pixel = wr.getPixel(x, y, pixel); - a = pixel[bands - 1]; - if ((a >= 0) && (a < 255)) { - alpha = a * norm; - for (b = 0; b < bands - 1; b++) - pixel[b] = (int) (pixel[b] * alpha + 0.5f); - wr.setPixel(x, y, pixel); - } - } - } - } - - public static void divideAlpha(WritableRaster wr) { - if (is_BYTE_COMP_Data(wr.getSampleModel())) - divide_BYTE_COMP_Data(wr); - else if (is_INT_PACK_Data(wr.getSampleModel(), true)) - divide_INT_PACK_Data(wr); - else { - int x0, x1, y0, y1, a, b; - float ialpha; - int bands = wr.getNumBands(); - int[] pixel = null; - - x0 = wr.getMinX(); - x1 = x0 + wr.getWidth(); - y0 = wr.getMinY(); - y1 = y0 + wr.getHeight(); - for (int y = y0; y < y1; y++) - for (int x = x0; x < x1; x++) { - pixel = wr.getPixel(x, y, pixel); - a = pixel[bands - 1]; - if ((a > 0) && (a < 255)) { - ialpha = 255 / (float) a; - for (b = 0; b < bands - 1; b++) - pixel[b] = (int) (pixel[b] * ialpha + 0.5f); - wr.setPixel(x, y, pixel); - } - } - } - } - - /** - * Copies data from one bufferedImage to another paying attention - * to the state of AlphaPreMultiplied. - * - * @param src The source - * @param dst The destination - */ - public static void - copyData(BufferedImage src, BufferedImage dst) { - Rectangle srcRect = new Rectangle(0, 0, - src.getWidth(), src.getHeight()); - copyData(src, srcRect, dst, new Point(0, 0)); - } - - - /** - * Copies data from one bufferedImage to another paying attention - * to the state of AlphaPreMultiplied. - * - * @param src The source - * @param srcRect The Rectangle of source data to be copied - * @param dst The destination - * @param destP The Place for the upper left corner of srcRect in dst. - */ - public static void - copyData(BufferedImage src, Rectangle srcRect, - BufferedImage dst, Point destP) { - - /* - if (srcCS != dstCS) - throw new IllegalArgumentException - ("Images must be in the same ColorSpace in order "+ - "to copy Data between them"); - */ - boolean srcAlpha = src.getColorModel().hasAlpha(); - boolean dstAlpha = dst.getColorModel().hasAlpha(); - - // System.out.println("Src has: " + srcAlpha + - // " is: " + src.isAlphaPremultiplied()); - // - // System.out.println("Dst has: " + dstAlpha + - // " is: " + dst.isAlphaPremultiplied()); - - if (srcAlpha == dstAlpha) - if ((!srcAlpha) || - (src.isAlphaPremultiplied() == dst.isAlphaPremultiplied())) { - // They match one another so just copy everything... - copyData(src.getRaster(), dst.getRaster()); - return; - } - - // System.out.println("Using Slow CopyData"); - - int[] pixel = null; - Raster srcR = src.getRaster(); - WritableRaster dstR = dst.getRaster(); - int bands = dstR.getNumBands(); - - int dx = destP.x - srcRect.x; - int dy = destP.y - srcRect.y; - - int w = srcRect.width; - int x0 = srcRect.x; - int y0 = srcRect.y; - int y1 = y0 + srcRect.height - 1; - - if (!srcAlpha) { - // Src has no alpha dest does so set alpha to 1.0 everywhere. - // System.out.println("Add Alpha"); - int[] oPix = new int[bands * w]; - int out = (w * bands) - 1; // The 2 skips alpha channel - while (out >= 0) { - // Fill alpha channel with 255's - oPix[out] = 255; - out -= bands; - } - - int b, in; - for (int y = y0; y <= y1; y++) { - pixel = srcR.getPixels(x0, y, w, 1, pixel); - in = w * (bands - 1) - 1; - out = (w * bands) - 2; // The 2 skips alpha channel on last pix - switch (bands) { - case 4: - while (in >= 0) { - oPix[out--] = pixel[in--]; - oPix[out--] = pixel[in--]; - oPix[out--] = pixel[in--]; - out--; - } - break; - default: - while (in >= 0) { - for (b = 0; b < bands - 1; b++) - oPix[out--] = pixel[in--]; - out--; - } - } - dstR.setPixels(x0 + dx, y + dy, w, 1, oPix); - } - } else if (dstAlpha && dst.isAlphaPremultiplied()) { - // Src and dest have Alpha but we need to multiply it for dst. - // System.out.println("Mult Case"); - int a, b, alpha, in, fpNorm = (1 << 24) / 255, pt5 = 1 << 23; - for (int y = y0; y <= y1; y++) { - pixel = srcR.getPixels(x0, y, w, 1, pixel); - in = bands * w - 1; - switch (bands) { - case 4: - while (in >= 0) { - a = pixel[in]; - if (a == 255) - in -= 4; - else { - in--; - alpha = fpNorm * a; - pixel[in] = (pixel[in] * alpha + pt5) >>> 24; - in--; - pixel[in] = (pixel[in] * alpha + pt5) >>> 24; - in--; - pixel[in] = (pixel[in] * alpha + pt5) >>> 24; - in--; - } - } - break; - default: - while (in >= 0) { - a = pixel[in]; - if (a == 255) - in -= bands; - else { - in--; - alpha = fpNorm * a; - for (b = 0; b < bands - 1; b++) { - pixel[in] = (pixel[in] * alpha + pt5) >>> 24; - in--; - } - } - } - } - dstR.setPixels(x0 + dx, y + dy, w, 1, pixel); - } - } else if (dstAlpha && !dst.isAlphaPremultiplied()) { - // Src and dest have Alpha but we need to divide it out for dst. - // System.out.println("Div Case"); - int a, b, ialpha, in, fpNorm = 0x00FF0000, pt5 = 1 << 15; - for (int y = y0; y <= y1; y++) { - pixel = srcR.getPixels(x0, y, w, 1, pixel); - in = (bands * w) - 1; - switch (bands) { - case 4: - while (in >= 0) { - a = pixel[in]; - if ((a <= 0) || (a >= 255)) - in -= 4; - else { - in--; - ialpha = fpNorm / a; - pixel[in] = (pixel[in] * ialpha + pt5) >>> 16; - in--; - pixel[in] = (pixel[in] * ialpha + pt5) >>> 16; - in--; - pixel[in] = (pixel[in] * ialpha + pt5) >>> 16; - in--; - } - } - break; - default: - while (in >= 0) { - a = pixel[in]; - if ((a <= 0) || (a >= 255)) - in -= bands; - else { - in--; - ialpha = fpNorm / a; - for (b = 0; b < bands - 1; b++) { - pixel[in] = (pixel[in] * ialpha + pt5) >>> 16; - in--; - } - } - } - } - dstR.setPixels(x0 + dx, y + dy, w, 1, pixel); - } - } else if (src.isAlphaPremultiplied()) { - int[] oPix = new int[bands * w]; - // Src has alpha dest does not so unpremult and store... - // System.out.println("Remove Alpha, Div Case"); - int a, b, ialpha, in, out, fpNorm = 0x00FF0000, pt5 = 1 << 15; - for (int y = y0; y <= y1; y++) { - pixel = srcR.getPixels(x0, y, w, 1, pixel); - in = (bands + 1) * w - 1; - out = (bands * w) - 1; - while (in >= 0) { - a = pixel[in]; - in--; - if (a > 0) { - if (a < 255) { - ialpha = fpNorm / a; - for (b = 0; b < bands; b++) - oPix[out--] = (pixel[in--] * ialpha + pt5) >>> 16; - } else - for (b = 0; b < bands; b++) - oPix[out--] = pixel[in--]; - } else { - in -= bands; - for (b = 0; b < bands; b++) - oPix[out--] = 255; - } - } - dstR.setPixels(x0 + dx, y + dy, w, 1, oPix); - } - } else { - // Src has unpremult alpha, dest does not have alpha, - // just copy the color channels over. - Rectangle dstRect = new Rectangle(destP.x, destP.y, - srcRect.width, srcRect.height); - for (int b = 0; b < bands; b++) - copyBand(srcR, srcRect, b, - dstR, dstRect, b); - } - } - - public static void copyBand(Raster src, int srcBand, - WritableRaster dst, int dstBand) { - - Rectangle sR = src.getBounds(); - Rectangle dR = dst.getBounds(); - Rectangle cpR = sR.intersection(dR); - - copyBand(src, cpR, srcBand, dst, cpR, dstBand); - } - - public static void copyBand(Raster src, Rectangle sR, int sBand, - WritableRaster dst, Rectangle dR, int dBand) { - int dy = dR.y - sR.y; - int dx = dR.x - sR.x; - sR = sR.intersection(src.getBounds()); - dR = dR.intersection(dst.getBounds()); - int width, height; - if (dR.width < sR.width) width = dR.width; - else width = sR.width; - if (dR.height < sR.height) height = dR.height; - else height = sR.height; - - int x = sR.x + dx; - int[] samples = null; - for (int y = sR.y; y < sR.y + height; y++) { - samples = src.getSamples(sR.x, y, width, 1, sBand, samples); - dst.setSamples(x, y + dy, width, 1, dBand, samples); - } - } - - public static boolean is_INT_PACK_Data(SampleModel sm, - boolean requireAlpha) { - // Check ColorModel is of type DirectColorModel - if (!(sm instanceof SinglePixelPackedSampleModel)) return false; - - // Check transfer type - if (sm.getDataType() != DataBuffer.TYPE_INT) return false; - - SinglePixelPackedSampleModel sppsm; - sppsm = (SinglePixelPackedSampleModel) sm; - - int[] masks = sppsm.getBitMasks(); - if (masks.length == 3) { - if (requireAlpha) return false; - } else if (masks.length != 4) - return false; - - if (masks[0] != 0x00ff0000) return false; - if (masks[1] != 0x0000ff00) return false; - if (masks[2] != 0x000000ff) return false; - if ((masks.length == 4) && - (masks[3] != 0xff000000)) return false; - - return true; - } - - public static boolean is_BYTE_COMP_Data(SampleModel sm) { - // Check ColorModel is of type DirectColorModel - if (!(sm instanceof ComponentSampleModel)) return false; - - // Check transfer type - if (sm.getDataType() != DataBuffer.TYPE_BYTE) return false; - - return true; - } - - protected static void divide_INT_PACK_Data(WritableRaster wr) { - // System.out.println("Divide Int"); - - SinglePixelPackedSampleModel sppsm; - sppsm = (SinglePixelPackedSampleModel) wr.getSampleModel(); - - final int width = wr.getWidth(); - - final int scanStride = sppsm.getScanlineStride(); - DataBufferInt db = (DataBufferInt) wr.getDataBuffer(); - final int base - = (db.getOffset() + - sppsm.getOffset(wr.getMinX() - wr.getSampleModelTranslateX(), - wr.getMinY() - wr.getSampleModelTranslateY())); - - // Access the pixel data array - final int[] pixels = db.getBankData()[0]; - for (int y = 0; y < wr.getHeight(); y++) { - int sp = base + y * scanStride; - final int end = sp + width; - while (sp < end) { - int pixel = pixels[sp]; - int a = pixel >>> 24; - if (a <= 0) { - pixels[sp] = 0x00FFFFFF; - } else if (a < 255) { - int aFP = (0x00FF0000 / a); - pixels[sp] = - ((a << 24) | - (((((pixel & 0xFF0000) >> 16) * aFP) & 0xFF0000)) | - (((((pixel & 0x00FF00) >> 8) * aFP) & 0xFF0000) >> 8) | - (((((pixel & 0x0000FF)) * aFP) & 0xFF0000) >> 16)); - } - sp++; - } - } - } - - protected static void mult_INT_PACK_Data(WritableRaster wr) { - // System.out.println("Multiply Int: " + wr); - - SinglePixelPackedSampleModel sppsm; - sppsm = (SinglePixelPackedSampleModel) wr.getSampleModel(); - - final int width = wr.getWidth(); - - final int scanStride = sppsm.getScanlineStride(); - DataBufferInt db = (DataBufferInt) wr.getDataBuffer(); - final int base - = (db.getOffset() + - sppsm.getOffset(wr.getMinX() - wr.getSampleModelTranslateX(), - wr.getMinY() - wr.getSampleModelTranslateY())); - // Access the pixel data array - final int[] pixels = db.getBankData()[0]; - for (int y = 0; y < wr.getHeight(); y++) { - int sp = base + y * scanStride; - final int end = sp + width; - while (sp < end) { - int pixel = pixels[sp]; - int a = pixel >>> 24; - if ((a >= 0) && (a < 255)) { // this does NOT include a == 255 (0xff) ! - pixels[sp] = ((a << 24) | - ((((pixel & 0xFF0000) * a) >> 8) & 0xFF0000) | - ((((pixel & 0x00FF00) * a) >> 8) & 0x00FF00) | - ((((pixel & 0x0000FF) * a) >> 8) & 0x0000FF)); - } - sp++; - } - } - } - - - protected static void divide_BYTE_COMP_Data(WritableRaster wr) { - // System.out.println("Multiply Int: " + wr); - - ComponentSampleModel csm; - csm = (ComponentSampleModel) wr.getSampleModel(); - - final int width = wr.getWidth(); - - final int scanStride = csm.getScanlineStride(); - final int pixStride = csm.getPixelStride(); - final int[] bandOff = csm.getBandOffsets(); - - DataBufferByte db = (DataBufferByte) wr.getDataBuffer(); - final int base - = (db.getOffset() + - csm.getOffset(wr.getMinX() - wr.getSampleModelTranslateX(), - wr.getMinY() - wr.getSampleModelTranslateY())); - - int aOff = bandOff[bandOff.length - 1]; - int bands = bandOff.length - 1; - - // Access the pixel data array - final byte[] pixels = db.getBankData()[0]; - for (int y = 0; y < wr.getHeight(); y++) { - int sp = base + y * scanStride; - final int end = sp + width * pixStride; - while (sp < end) { - int a = pixels[sp + aOff] & 0xFF; - if (a == 0) { - for (int b = 0; b < bands; b++) - pixels[sp + bandOff[b]] = (byte) 0xFF; - } else if (a < 255) { // this does NOT include a == 255 (0xff) ! - int aFP = (0x00FF0000 / a); - for (int b = 0; b < bands; b++) { - int i = sp + bandOff[b]; - pixels[i] = (byte) (((pixels[i] & 0xFF) * aFP) >>> 16); - } - } - sp += pixStride; - } - } - } - - protected static void mult_BYTE_COMP_Data(WritableRaster wr) { - // System.out.println("Multiply Int: " + wr); - - ComponentSampleModel csm; - csm = (ComponentSampleModel) wr.getSampleModel(); - - final int width = wr.getWidth(); - - final int scanStride = csm.getScanlineStride(); - final int pixStride = csm.getPixelStride(); - final int[] bandOff = csm.getBandOffsets(); - - DataBufferByte db = (DataBufferByte) wr.getDataBuffer(); - final int base - = (db.getOffset() + - csm.getOffset(wr.getMinX() - wr.getSampleModelTranslateX(), - wr.getMinY() - wr.getSampleModelTranslateY())); - - - int aOff = bandOff[bandOff.length - 1]; - int bands = bandOff.length - 1; - - // Access the pixel data array - final byte[] pixels = db.getBankData()[0]; - for (int y = 0; y < wr.getHeight(); y++) { - int sp = base + y * scanStride; - final int end = sp + width * pixStride; - while (sp < end) { - int a = pixels[sp + aOff] & 0xFF; - if (a != 0xFF) - for (int b = 0; b < bands; b++) { - int i = sp + bandOff[b]; - pixels[i] = (byte) (((pixels[i] & 0xFF) * a) >> 8); - } - sp += pixStride; - } - } - } - -/* - This is skanky debugging code that might be useful in the future: - - if (count == 33) { - String label = "sub [" + x + ", " + y + "]: "; - org.ImageDisplay.showImage - (label, subBI); - org.ImageDisplay.printImage - (label, subBI, - new Rectangle(75-iR.x, 90-iR.y, 32, 32)); - - } - - - // if ((count++ % 50) == 10) - // org.ImageDisplay.showImage("foo: ", subBI); - - - Graphics2D realG2D = g2d; - while (realG2D instanceof sun.java2d.ProxyGraphics2D) { - realG2D = ((sun.java2d.ProxyGraphics2D)realG2D).getDelegate(); - } - if (realG2D instanceof sun.awt.image.BufferedImageGraphics2D) { - count++; - if (count == 34) { - RenderedImage ri; - ri = ((sun.awt.image.BufferedImageGraphics2D)realG2D).bufImg; - // g2d.setComposite(SVGComposite.OVER); - // org.ImageDisplay.showImage("Bar: " + count, cr); - org.ImageDisplay.printImage("Bar: " + count, cr, - new Rectangle(75, 90, 32, 32)); - - org.ImageDisplay.showImage ("Foo: " + count, ri); - org.ImageDisplay.printImage("Foo: " + count, ri, - new Rectangle(75, 90, 32, 32)); - - System.out.println("BI: " + ri); - System.out.println("BISM: " + ri.getSampleModel()); - System.out.println("BICM: " + ri.getColorModel()); - System.out.println("BICM class: " + ri.getColorModel().getClass()); - System.out.println("BICS: " + ri.getColorModel().getColorSpace()); - System.out.println - ("sRGB CS: " + - ColorSpace.getInstance(ColorSpace.CS_sRGB)); - System.out.println("G2D info"); - System.out.println("\tComposite: " + g2d.getComposite()); - System.out.println("\tTransform" + g2d.getTransform()); - java.awt.RenderingHints rh = g2d.getRenderingHints(); - java.util.Set keys = rh.keySet(); - java.util.Iterator iter = keys.iterator(); - while (iter.hasNext()) { - Object o = iter.next(); - - System.out.println("\t" + o.toString() + " -> " + - rh.get(o).toString()); - } - - ri = cr; - System.out.println("RI: " + ri); - System.out.println("RISM: " + ri.getSampleModel()); - System.out.println("RICM: " + ri.getColorModel()); - System.out.println("RICM class: " + ri.getColorModel().getClass()); - System.out.println("RICS: " + ri.getColorModel().getColorSpace()); - } - } -*/ - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/AbstractDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/AbstractDrawCmd.java deleted file mode 100644 index c34ce02316..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/AbstractDrawCmd.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.util.logging.Logger; - -/** - * AbstractDrawCmd provide common implementation details of any DrawCmd - * implementation. Draw/paint specific system properties are currently handled - * by this class. - *

        - *
      • org.icepdf.core.paint.disableClipping - disable clipping draw commands.
      • - *
      • org.icepdf.core.paint.disableAlpha - disable alpha draw commands.
      • - *
      - * - * @since 5.0 - */ -public abstract class AbstractDrawCmd implements DrawCmd { - - protected static final Logger logger = - Logger.getLogger(AbstractDrawCmd.class.toString()); - - protected static boolean disableClipping; - - static { - - // disable clipping, helps with printing issues on windows where the - // clip can sometimes blank a whole page. This should only be used as - // a lost resort. Buffering to an image is another way to avoid the clip - // problem. - disableClipping = - Defs.sysPropertyBoolean("org.icepdf.core.paint.disableClipping", - false); - } - - public abstract Shape paintOperand(Graphics2D g, Page parentPage, - Shape currentShape, Shape clip, - AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) throws InterruptedException; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/AlphaDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/AlphaDrawCmd.java deleted file mode 100644 index c32ed69356..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/AlphaDrawCmd.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * Stores an AlphaComposite value for differed painting to a Graphics2D object. - * - * @since 5.0 - */ -public class AlphaDrawCmd extends AbstractDrawCmd { - - private AlphaComposite alphaComposite; - - public AlphaDrawCmd(AlphaComposite alphaComposite) { - this.alphaComposite = alphaComposite; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - - if (paintAlpha) { - g.setComposite(alphaComposite); - } - - return currentShape; - } - - /** - * Gets the alpha value that is applied to the graphics context. - * - * @return alpha context which will be applied by this command. - */ - public AlphaComposite getAlphaComposite() { - return alphaComposite; - } - - /** - * Sets the alpha composite to be executed by this command. Care should be taken as this - * will have direct impact on the PDF shapes stack on the next paint call. - * - * @param alphaComposite alphaComposite object to be executed by this command. - */ - public void setAlphaComposite(AlphaComposite alphaComposite) { - this.alphaComposite = alphaComposite; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/BlendCompositeDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/BlendCompositeDrawCmd.java deleted file mode 100644 index ed7d517454..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/BlendCompositeDrawCmd.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.BlendComposite; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * Applies BlendingComposite draw operations. - * - * @since 6.0.2 - */ -public class BlendCompositeDrawCmd extends AbstractDrawCmd { - - private Composite blendComposite; - - public BlendCompositeDrawCmd(Name blendComposite, float alpha) { - // check for -1, value not set and default should be used. - if (alpha == -1) { - alpha = 1; - } - this.blendComposite = BlendComposite.getInstance(blendComposite, alpha); - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - - if (paintAlpha && blendComposite != null) { - g.setComposite(blendComposite); - } - - return currentShape; - } - - /** - * Gets the alpha value that is applied to the graphics context. - * - * @return alpha context which will be applied by this command. - */ - public Composite getBlendComposite() { - return blendComposite; - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ClipDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ClipDrawCmd.java deleted file mode 100644 index 54b00ef4eb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ClipDrawCmd.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * Applies a clipping command to the Graphics2D context which makes the clip - * match the currentShape or at least the intersection of the currentShape - * with the previous clip. - * - * @since 5.0 - */ -public class ClipDrawCmd extends AbstractDrawCmd { - -// private int rule = AlphaComposite.SRC_OVER; -// private float alpha = .5f; - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - - // Capture the current af for the - // page - AffineTransform af = new AffineTransform(g.getTransform()); - // Set the transform to the base, which is fact where the page - // lies in the viewport, very dynamic. - g.setTransform(base); -// if (!g.getClip().getBounds().equals(clip.getBounds())) {// apply the clip, which is always the initial paper size, - g.setClip(clip); -// } - // apply the af, which places the clip in the correct location - g.setTransform(af); - if (currentShape != null && !disableClipping) { - // clip outline -// Color tmp = g.getColor(); -// g.setColor(Color.red); -// g.draw(currentShape); -// g.setColor(tmp); -// g.setComposite(AlphaComposite.getInstance(rule, alpha)); - // apply the new clip -// if (!g.getClip().getBounds().equals(currentShape.getBounds())) { - g.clip(currentShape); -// } - } - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ColorDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ColorDrawCmd.java deleted file mode 100644 index 96d33ade23..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ColorDrawCmd.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * Stores an Color value that will be applied to the Graphics2D object when the - * command is executed. - * - * @since 5.0 - */ -public class ColorDrawCmd extends AbstractDrawCmd { - - private Color color; - - public ColorDrawCmd(Color color) { - this.color = color; - } - - public Color getColor() { - return color; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - g.setColor(color); - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/DrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/DrawCmd.java deleted file mode 100644 index aae776bdbf..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/DrawCmd.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * Common command pattern for painting PDF draw commands to a Java2D graphics - * context. Any object that is Shapes shapes array list must implement this - * interface. - *

      - * Implementing methods should execute as quickly as possible to avoid slowing - * down render times. - * - * @since 5.0 - */ -public interface DrawCmd { - - /** - * Called by the Shapes class to paint all DrawCmd implementations. - * - * @param g graphics context to paint this paint command to. - * @param parentPage parentPage reference used to notify page painters. - * @param currentShape current shape to draw. - * @param clip clip of parent which is the generally the page size. - * @param base base transform of the page. - * @param optionalContentState state of optional content visibility. - * @param paintAlpha enable/disable the alpha painting. - * @param paintTimer painTimer keeps track when a repaint should occur. - * @return resulting shape if currentShape has been altered, otherwise - * returns the currentShape. Current Shape is generally altered - * clip shape. - */ - public Shape paintOperand(Graphics2D g, - Page parentPage, - Shape currentShape, - Shape clip, - AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, - PaintTimer paintTimer) throws InterruptedException; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/DrawDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/DrawDrawCmd.java deleted file mode 100644 index 0b6fad1f1c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/DrawDrawCmd.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * The DrawDrawCmd (no didn't stutter) will call draw and the Graphics2D context - * for the currentShape. The execute method will not draw the currentShape - * if the shape does not interest the current graphics clip. - * - * @since 5.0 - */ -public class DrawDrawCmd extends AbstractDrawCmd { - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - Rectangle currentShapeBounds = currentShape.getBounds(); - if (g.getClip() != null && optionalContentState.isVisible() && - currentShape.intersects(g.getClip().getBounds()) || - (currentShapeBounds.getWidth() < 1.0 || - currentShapeBounds.getHeight() < 1.0)) { - g.draw(currentShape); - // Send a PaintPage Event to listeners - if (parentPage != null && paintTimer.shouldTriggerRepaint()) { - parentPage.notifyPaintPageListeners(); - } - } - // couple corner cases where we want to paint the shape when we don't have a clip. - else if (g.getClip() == null) { - g.draw(currentShape); - // Send a PaintPage Event to listeners - if (parentPage != null && paintTimer.shouldTriggerRepaint()) { - parentPage.notifyPaintPageListeners(); - } - } - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/FillDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/FillDrawCmd.java deleted file mode 100644 index e951021e72..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/FillDrawCmd.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * FillDrawCmd will execute the Graphics2D fill command on the currentShape. - * The execute method will not fill the currentShape if the shape does not - * interest the current graphics clip. - * - * @since 5.0 - */ -public class FillDrawCmd extends AbstractDrawCmd { - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - if (optionalContentState.isVisible() && currentShape != null && - currentShape.intersects(g.getClip().getBounds())) { - g.fill(currentShape); - // Send a PaintPage Event to listeners -// if (parentPage != null && paintTimer.shouldTriggerRepaint()) { -// parentPage.notifyPaintPageListeners(); -// } - } - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/FormDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/FormDrawCmd.java deleted file mode 100644 index 61d9729442..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/FormDrawCmd.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Form; -import org.icepdf.core.pobjects.ImageUtility; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.*; -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; -import java.util.HashMap; - - -/** - * The FormDrawCmd when executed will draw an xForm's shapes to a raster and - * then paint the raster. This procedure is only executed if the xForm - * is part of transparency group that has a alpha value < 1.0f. - * - * @since 5.0 - */ -public class FormDrawCmd extends AbstractDrawCmd { - - private Form xForm; - - private BufferedImage xFormBuffer; - private int x, y; - - private static boolean disableXObjectSMask; - - // Used to use Max_value but we have a few corner cases where the dimension is +-5 of Short.MAX_VALUE, but - // realistically we seldom have enough memory to load anything bigger then 8000px. 4k+ image are big! - public static int MAX_IMAGE_SIZE = 2000; // Short.MAX_VALUE - - static { - // decide if large images will be scaled - disableXObjectSMask = - Defs.sysPropertyBoolean("org.icepdf.core.disableXObjectSMask", - false); - - MAX_IMAGE_SIZE = Defs.sysPropertyInt("org.icepdf.core.maxSmaskImageSize", MAX_IMAGE_SIZE); - } - - public FormDrawCmd(Form xForm) { - this.xForm = xForm; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - if (optionalContentState.isVisible() && xFormBuffer == null) { - RenderingHints renderingHints = g.getRenderingHints(); - Rectangle2D bBox = xForm.getBBox(); - x = (int) bBox.getX(); - y = (int) bBox.getY(); - boolean hasMask = ((xForm.getGraphicsState().getExtGState() != null && - xForm.getGraphicsState().getExtGState().getSMask() != null) || - (xForm.getExtGState() != null && xForm.getExtGState().getSMask() != null)); - boolean isExtendGraphicState = xForm.getGraphicsState().getExtGState() != null && - xForm.getExtGState() != null; - boolean normalBM = false; - if (isExtendGraphicState && xForm.getExtGState().getBlendingMode() != null) { - normalBM = xForm.getExtGState().getBlendingMode().equals(new Name("Normal")) && - xForm.getGraphicsState().getExtGState().getBlendingMode().equals(new Name("Normal")) && - (xForm.getExtGState() != null && - (!xForm.getExtGState().isAlphaAShape() || xForm.getExtGState().getOverprintMode() == 0)); - } - - SoftMask formSoftMask = null; - SoftMask softMask = null; - - if (xForm.getGraphicsState().getExtGState().getSMask() != null) { - softMask = xForm.getGraphicsState().getExtGState().getSMask(); - boolean isShading = softMask.getG().getResources().isShading(); - if (isShading) { - isShading = checkForShaddingFill(softMask.getG()); - softMask.getG().setShading(isShading); - } - if (!isShading) { - x = (int) softMask.getG().getBBox().getX(); - y = (int) softMask.getG().getBBox().getY(); - } - } - if (xForm.getExtGState().getSMask() != null) { - formSoftMask = xForm.getExtGState().getSMask(); - boolean isShading = formSoftMask.getG().getResources().isShading(); - if (isShading) { - isShading = checkForShaddingFill(formSoftMask.getG()); - formSoftMask.getG().setShading(isShading); - } - if (!isShading) { - x = (int) formSoftMask.getG().getBBox().getX(); - y = (int) formSoftMask.getG().getBBox().getY(); - } - } - // check if we have the same xobject. - if (softMask != null && formSoftMask != null) { - if (softMask.getPObjectReference() != null && formSoftMask.getPObjectReference() != null && - softMask.getPObjectReference().equals(formSoftMask.getPObjectReference())) { - softMask = null; - } else if (softMask.getG().getPObjectReference() != null && - formSoftMask.getG().getPObjectReference() != null && - softMask.getG().getPObjectReference().equals(formSoftMask.getG().getPObjectReference())) { - softMask = null; - } - } - // need to check if we really have a shading pattern, as the resources check can be false positive. - if (xForm.getResources().isShading()) { - boolean isFormShading = checkForShaddingFill(xForm); - xForm.setShading(isFormShading); - } - - // create the form and we'll paint it at the very least - xFormBuffer = createBufferXObject(parentPage, xForm, null, renderingHints, normalBM); - if (!disableXObjectSMask && hasMask) { - - // apply the mask and paint. - if (!xForm.isShading()) { - if (softMask != null && softMask.getS().equals(SoftMask.SOFT_MASK_TYPE_ALPHA)) { - logger.warning("Smask alpha example, currently not supported."); - } else if (softMask != null && softMask.getS().equals(SoftMask.SOFT_MASK_TYPE_LUMINOSITY)) { - xFormBuffer = applyMask(parentPage, xFormBuffer, softMask, formSoftMask, g.getRenderingHints()); - } - } else if (softMask != null) { - // still not property aligning the form or mask space to correctly apply a shading pattern. - // experimental as it fixes some, breaks others, but regardless we don't support it well. - logger.warning("Smask pattern paint example, currently not supported."); - xFormBuffer.flush(); - xFormBuffer = createBufferXObject(parentPage, softMask.getG(), null, renderingHints, true); - return currentShape; - } - // apply the form mask to current form content that has been rasterized to xFormBuffer - if (formSoftMask != null) { - BufferedImage formSMaskBuffer = applyMask(parentPage, xFormBuffer, formSoftMask, softMask, - g.getRenderingHints()); - // compost all the images. - if (softMask != null) { - BufferedImage formBuffer = ImageUtility.createTranslucentCompatibleImage( - xFormBuffer.getWidth(), xFormBuffer.getHeight()); - Graphics2D g2d = (Graphics2D) formBuffer.getGraphics(); -// java.util.List compRaw = formSoftMask.getBC(); -// if (compRaw != null) { -// g2d.setColor(Color.BLACK); -// g2d.fillRect(0, 0, xFormBuffer.getWidth(), xFormBuffer.getHeight()); -// } - g2d.drawImage(formSMaskBuffer, 0, 0, null); -// g2d.drawImage(xFormBuffer, 0, 0, null); - xFormBuffer.flush(); - xFormBuffer = formBuffer; - } else { - xFormBuffer = formSMaskBuffer; - } - } - } else if (isExtendGraphicState) { - BufferedImage shape = createBufferXObject(parentPage, xForm, null, renderingHints, true); - xFormBuffer = ImageUtility.applyExplicitOutline(xFormBuffer, shape); - } -// ImageUtility.displayImage(xFormBuffer, "final" + xForm.getGroup() + " " + xForm.getPObjectReference() + -// xFormBuffer.getHeight() + "x" + xFormBuffer.getHeight()); - } - g.drawImage(xFormBuffer, null, x, y); - return currentShape; - } - - private BufferedImage applyMask(Page parentPage, BufferedImage xFormBuffer, SoftMask softMask, SoftMask gsSoftMask, - RenderingHints renderingHints) { - if (softMask != null && softMask.getS().equals(SoftMask.SOFT_MASK_TYPE_ALPHA)) { - logger.warning("Smask alpha example, currently not supported."); - } else if (softMask != null && softMask.getS().equals(SoftMask.SOFT_MASK_TYPE_LUMINOSITY)) { - BufferedImage sMaskBuffer = createBufferXObject(parentPage, softMask.getG(), softMask, renderingHints, true); -// ImageUtility.displayImage(xFormBuffer, "base " + xForm.getPObjectReference() + " " + xFormBuffer.getHeight() + " x " + xFormBuffer.getHeight()); -// ImageUtility.displayImage(sMaskBuffer, "smask " + softMask.getG().getPObjectReference() + " " + useLuminosity); - if (!(gsSoftMask != null)) { - xFormBuffer = ImageUtility.applyExplicitSMask(xFormBuffer, sMaskBuffer); - } else { - // todo try and figure out how to apply an AIS=false alpha to an xobject. -// xFormBuffer = ImageUtility.applyExplicitLuminosity(xFormBuffer, sMaskBuffer); - xFormBuffer = ImageUtility.applyExplicitOutline(xFormBuffer, sMaskBuffer); - } - // test for TR function - if (softMask.getTR() != null) { - logger.warning("Smask Transfer Function example, currently not supported."); - } - // todo need to look at matte too which is on the xobject. - } -// ImageUtility.displayImage(xFormBuffer, "final " + softMask.getG().getPObjectReference()); - return xFormBuffer; - } - - /** - * Paint the form content to a BufferedImage so that the forms content can be - * used to apply the sMask data. Further work is needed to fully support this - * section of transparency groups. - * - * @param parentPage parent page object - * @param xForm form being drawn to buffer. - * @param renderingHints graphic state rendering hinds of parent. - * @return buffered image of xObject content. - */ - private BufferedImage createBufferXObject(Page parentPage, Form xForm, SoftMask softMask, - RenderingHints renderingHints, boolean isMask) { - Rectangle2D bBox = xForm.getBBox(); - int width = (int) bBox.getWidth(); - int height = (int) bBox.getHeight(); - // corner cases where some bBoxes don't have a dimension. - if (width == 0) { - width = 1; - } else if (width >= MAX_IMAGE_SIZE) { - width = xFormBuffer.getWidth(); - } - if (height == 0) { - height = 1; - } else if (height >= MAX_IMAGE_SIZE) { - height = xFormBuffer.getHeight(); - } - // create the new image to write too. - BufferedImage bi = ImageUtility.createTranslucentCompatibleImage(width, height); - Graphics2D canvas = bi.createGraphics(); - if (!isMask && xForm.getExtGState() != null && xForm.getExtGState().getBlendingMode() != null - && !new Name("Normal").equals(xForm.getExtGState().getBlendingMode()) - ) { - if (xForm.getGroup() != null) { - HashMap tmp = xForm.getGroup(); - Object cs = xForm.getLibrary().getObject(tmp, new Name("CS")); - // looking for additive colour spaces, if so we paint an background. - if (cs == null || cs instanceof ICCBased || cs instanceof Name && - (((Name) cs).equals(DeviceRGB.DEVICERGB_KEY) - || ((Name) cs).equals(DeviceCMYK.DEVICECMYK_KEY))) { - canvas.setColor(Color.WHITE); - canvas.fillRect(0, 0, width, height); - } - } - } - // copy over the rendering hints - canvas.setRenderingHints(renderingHints); - // get shapes and paint them. - try { - Shapes xFormShapes = xForm.getShapes(); - if (xFormShapes != null) { - xFormShapes.setPageParent(parentPage); - // translate the coordinate system as we'll paint the g - // graphic at the correctly location later. - if (!xForm.isShading()) { - canvas.translate(-(int) bBox.getX(), -(int) bBox.getY()); - canvas.setClip(bBox); - xFormShapes.paint(canvas); - xFormShapes.setPageParent(null); - } - // basic support for gradient fills, still have a few corners cases to work on. - else { - for (DrawCmd cmd : xFormShapes.getShapes()) { - if (cmd instanceof ShapeDrawCmd && ((ShapeDrawCmd) cmd).getShape() == null) { - Rectangle2D bounds = bBox.getBounds2D(); - ((ShapeDrawCmd) cmd).setShape(bounds); - } - } - canvas.translate(-x, -y); - canvas.setClip(bBox.getBounds2D()); - xFormShapes.paint(canvas); - xFormShapes.setPageParent(null); - } - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Form draw thread interrupted."); - } - canvas.dispose(); - return bi; - } - - private boolean checkForShaddingFill(Form xform) { - boolean found = false; - for (DrawCmd cmd : xform.getShapes().getShapes()) { - if (cmd instanceof ShapeDrawCmd && ((ShapeDrawCmd) cmd).getShape() == null) { - found = true; - } - } - return found; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/GlyphOutlineDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/GlyphOutlineDrawCmd.java deleted file mode 100644 index 1756fa713e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/GlyphOutlineDrawCmd.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.GlyphOutlineClip; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * The GlyphOutlineDrawCmd applies the clip defined by a locally stored - * glyphOutlineClip object. - * - * @since 5.0 - */ -public class GlyphOutlineDrawCmd extends AbstractDrawCmd { - - private GlyphOutlineClip glyphOutlineClip; - - public GlyphOutlineDrawCmd(GlyphOutlineClip glyphOutlineClip) { - this.glyphOutlineClip = glyphOutlineClip; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, Shape clip, - AffineTransform base, OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - if (optionalContentState.isVisible()) { - // save and revert the af for the page so that we can - // paint the converted clip glyph outline. - AffineTransform preTrans = new AffineTransform(g.getTransform()); - g.setTransform(base); - // set clip directly but it should be the intersection with the current. - Shape glyphClip = glyphOutlineClip.getGlyphOutlineClip(); - g.setClip(glyphClip); - g.setTransform(preTrans); - } - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/GraphicsStateCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/GraphicsStateCmd.java deleted file mode 100644 index e2b14da805..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/GraphicsStateCmd.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * GraphicsStateCmd currently doesn't paint anything but rather acts as a - * queue for the PostScriptEncoder to write out a named graphics context. - * This command would not normally be used in - * - * @since 5.0 - */ -public class GraphicsStateCmd extends AbstractDrawCmd { - - private Name graphicStateName; - - public GraphicsStateCmd(Name graphicStateName) { - this.graphicStateName = graphicStateName; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, boolean paintAlpha, PaintTimer paintTimer) { - return currentShape; - } - - public Name getGraphicStateName() { - return graphicStateName; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ImageDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ImageDrawCmd.java deleted file mode 100644 index 8c8aaddf7c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ImageDrawCmd.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.ImageReference; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * The ImageDrawCmd class when executed will draw the image associated - * with this DrawCmd. - * - * @since 5.0 - */ -public class ImageDrawCmd extends AbstractDrawCmd { - - // enable disable scaled paint. - private static boolean isScaledPaint; - - // narrow image scaling max dimension size to kick of the use of the lookup - // table - public static int MIN_DIMENSION; - - static { - isScaledPaint = Defs.booleanProperty("org.icepdf.core.imageDrawCmd.scale.enabled", false); - MIN_DIMENSION = Defs.intProperty("org.icepdf.core.imageDrawCmd.maxDimension", 5); - } - - private ImageReference image; - // paint scale factor of original image. - private int xScale = 1; - private int yScale = 1; - private boolean xIsScale = false; - private boolean yIsScale = false; - - // narrow image scaling lookup table for 1xh or wx1 images. Soft values - // but keeps the images from not painting a low zoom levels. - // first column is the zoom level and the second is the total number of - // pixels that must be present for the image to be painted. - private static final double[][] SCALE_LOOKUP = { - {1.50, 2}, - {0.70, 3}, - {0.40, 4}, - {0.30, 6}, - {0.20, 8}, - {0.10, 10}, - {0.05, 12} - }; - - public ImageDrawCmd(ImageReference image) { - this.image = image; - // check image dimensions to see if we should do some work for - // Xxh or wxX images sizes, as they tend not to be painted by Java2d - // at zoom levels < 144%. - if (isScaledPaint) { - if (image.getHeight() <= MIN_DIMENSION) { - yIsScale = true; - } - if (image.getWidth() <= MIN_DIMENSION) { - xIsScale = true; - } - } - } - - public Image getImage() { - return image.getImage(); - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - if (optionalContentState.isVisible()) { - if (isScaledPaint && (xIsScale || yIsScale)) { - calculateThinScale(base.getScaleX()); - } - image.drawImage(g, 0, 0, xScale, yScale); - if (parentPage != null && paintTimer.shouldTriggerRepaint()) { - parentPage.notifyPaintPageListeners(); - } - } - return currentShape; - } - - /** - * Alter the width or height value of 1px or less then MIN_DIMENSION. - * - * @param scale scale factor of current view. - */ - private void calculateThinScale(double scale) { - if (xIsScale) { - xScale = commonScaling(scale, image.getWidth()); - } - // horizon scale needs to be applied for an Wx1px image. - if (yIsScale) { - yScale = commonScaling(scale, image.getHeight()); - } - } - - /** - * Fetches a scale value from lookup table and returns the appropriate - * scale so the image will be visible. - * - * @param scale page level scale being applied to page. - * @param size original size, width or height of the image to sale. - * @return scale value applied to g.drawImage(). - */ - private int commonScaling(double scale, int size) { - // find the appropriate range and final minimal - for (int i = SCALE_LOOKUP.length - 1; i >= 0; i--) { - if (scale < SCALE_LOOKUP[i][0]) { - double neededSize = SCALE_LOOKUP[i][1]; - double scaleFactor = neededSize / size; - return (int) Math.ceil(scaleFactor); - } - } - return 1; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/NoClipDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/NoClipDrawCmd.java deleted file mode 100644 index ae5fffd523..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/NoClipDrawCmd.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * NoClipDrawCmd when execute will apply a no clip operation to the Graphics2D - * context. A no clips operation will restore the graphics clip back to the - * original clip which is the page size but the base Affine transform must - * be first applied and then backed out after the clip has been removed. - * - * @since 5.0 - */ -public class NoClipDrawCmd extends AbstractDrawCmd { - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, boolean paintAlpha, PaintTimer paintTimer) { - - AffineTransform af = new AffineTransform(g.getTransform()); - - g.setTransform(base); -// if (!g.getClip().getBounds().equals(clip.getBounds())) { - g.setClip(clip); -// } - g.setTransform(af); - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/OCGEndDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/OCGEndDrawCmd.java deleted file mode 100644 index e2a3ed6a0c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/OCGEndDrawCmd.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * Marks the end of an optional content group on the shapes stack. When - * encountered the OptionalContentState is updated to the previous state - * if any exists. - * - * @author 5.0 - */ -public class OCGEndDrawCmd extends AbstractDrawCmd { - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - - optionalContentState.remove(); - - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/OCGStartDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/OCGStartDrawCmd.java deleted file mode 100644 index f93706f0be..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/OCGStartDrawCmd.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.OptionalContents; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * Marks the start of an optional content group on the shapes stack. When - * encountered the OptionalContentState is updated with the state of this - * optional content. - * - * @author 5.0 - */ -public class OCGStartDrawCmd extends AbstractDrawCmd { - - private OptionalContents optionalContents; - - public OCGStartDrawCmd(OptionalContents optionalContents) { - this.optionalContents = optionalContents; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - optionalContentState.add(optionalContents); - return currentShape; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/PaintDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/PaintDrawCmd.java deleted file mode 100644 index d1d4fbb64c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/PaintDrawCmd.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * The PaintDrawCmd stores a Paint object and when executed will apply the - * Paint to the specified graphics context. - * - * @since 5.0 - */ -public class PaintDrawCmd extends AbstractDrawCmd { - - private Paint paint; - - public PaintDrawCmd(Paint paint) { - this.paint = paint; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - g.setPaint(paint); - - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/PostScriptEncoder.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/PostScriptEncoder.java deleted file mode 100644 index c79394219c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/PostScriptEncoder.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.LiteralStringObject; -import org.icepdf.core.pobjects.graphics.TextSprite; -import org.icepdf.core.pobjects.graphics.text.GlyphText; -import org.icepdf.core.util.PdfOps; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.PathIterator; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * The PostScriptEncoder is responsible for converting an ArrayList - * into postscript operands. Basically the reverse of what the content - * parser does. - *

      - * NOTE: this is currently a partial implementation to vac - * - * @since 5.0 - */ -public class PostScriptEncoder { - - private static final Logger logger = - Logger.getLogger(PostScriptEncoder.class.toString()); - - private static final String SPACE = " "; - private static final String NEWLINE = "\r\n"; - private static final String TRUE = "true"; - private static final String FALSE = "false"; - private static final String NAME = "/"; - private static final String BEGIN_ARRAY = "["; - private static final String END_ARRAY = "]"; - private static final String BEGIN_STRING = "("; - private static final String END_STRING = ")"; - - private PostScriptEncoder() { - - } - - /** - * Processes the given DrawCmd objects and generates the PostScript to - * draw simple shapes and text. - * - * @param drawCmds commands to convert to postscript. - * @return byte[] of PostScript notation. - */ - public static byte[] generatePostScript(ArrayList drawCmds) { - StringBuilder postScript = new StringBuilder(); - Color color = null; - Shape currentShape = null; - if (logger.isLoggable(Level.FINEST)) { - if (drawCmds != null) { - logger.finest("PostScriptEncoder processing: " + - drawCmds.size() + " commands."); - } else { - logger.finest("PostScriptEncoder does not have any shapes to process. "); - } - } - - try { - for (DrawCmd drawCmd : drawCmds) { - // setup an affine transform - if (drawCmd instanceof TransformDrawCmd) { - AffineTransform af = ((TransformDrawCmd) drawCmd).getAffineTransform(); - postScript.append(af.getScaleX()).append(SPACE) - .append(af.getShearX()).append(SPACE) - .append(af.getShearY()).append(SPACE) - .append(af.getScaleY()).append(SPACE) - .append(af.getTranslateX()).append(SPACE) - .append(af.getTranslateY()).append(SPACE) - .append(PdfOps.cm_TOKEN).append(NEWLINE); - } else if (drawCmd instanceof TextTransformDrawCmd) { - AffineTransform af = ((TransformDrawCmd) drawCmd).getAffineTransform(); - postScript.append(af.getScaleX()).append(SPACE) - .append(af.getShearX()).append(SPACE) - .append(af.getShearY()).append(SPACE) - .append(af.getScaleY()).append(SPACE) - .append(af.getTranslateX()).append(SPACE) - .append(af.getTranslateY()).append(SPACE) - .append(PdfOps.Tm_TOKEN).append(NEWLINE); - } - // reference the colour, we'll decide later if its fill or stroke. - else if (drawCmd instanceof ColorDrawCmd) { - color = ((ColorDrawCmd) drawCmd).getColor(); - } - // stroke the shape. - else if (drawCmd instanceof DrawDrawCmd) { - if (color != null) { - float[] colors = color.getRGBColorComponents(null); - // set the stroke color - postScript.append(colors[0]).append(SPACE) - .append(colors[1]).append(SPACE) - .append(colors[2]).append(SPACE) - .append(PdfOps.RG_TOKEN).append(NEWLINE); - // generate the draw operands for current shape. - generateShapePostScript(currentShape, postScript); - // add the fill - postScript.append(PdfOps.S_TOKEN).append(NEWLINE); - } - } - // fill the shape. - else if (drawCmd instanceof FillDrawCmd) { - if (color != null) { - float[] colors = color.getRGBColorComponents(null); - // set fill color - postScript.append(colors[0]).append(SPACE) - .append(colors[1]).append(SPACE) - .append(colors[2]).append(SPACE) - .append(PdfOps.rg_TOKEN).append(NEWLINE); - // generate the draw operands for the current shape. - generateShapePostScript(currentShape, postScript); - // add the fill - postScript.append(PdfOps.f_TOKEN).append(SPACE); - } - } - // current shape. - else if (drawCmd instanceof ShapeDrawCmd) { - currentShape = ((ShapeDrawCmd) drawCmd).getShape(); - } - // Sets the stroke. - else if (drawCmd instanceof StrokeDrawCmd) { - BasicStroke stroke = (BasicStroke) ((StrokeDrawCmd) drawCmd).getStroke(); - postScript.append( - // line width - stroke.getLineWidth()).append(SPACE) - .append(PdfOps.w_TOKEN).append(SPACE); - // dash phase - float[] dashes = stroke.getDashArray(); - postScript.append(BEGIN_ARRAY); - if (dashes != null) { - for (int i = 0, max = dashes.length; i < max; i++) { - postScript.append(dashes[i]); - if (i < max - 1) { - postScript.append(SPACE); - } - } - } - postScript.append(END_ARRAY).append(SPACE); - postScript.append(stroke.getDashPhase()).append(SPACE) - .append(PdfOps.d_TOKEN).append(SPACE); - // cap butt - if (stroke.getEndCap() == BasicStroke.CAP_BUTT) { - postScript.append(0).append(SPACE) - .append(PdfOps.J_TOKEN).append(SPACE); - } else if (stroke.getEndCap() == BasicStroke.CAP_ROUND) { - postScript.append(1).append(SPACE) - .append(PdfOps.J_TOKEN).append(SPACE); - } else if (stroke.getEndCap() == BasicStroke.CAP_SQUARE) { - postScript.append(2).append(SPACE) - .append(PdfOps.J_TOKEN).append(SPACE); - } - // miter join. - if (stroke.getMiterLimit() == BasicStroke.JOIN_MITER) { - postScript.append(0).append(SPACE) - .append(PdfOps.j_TOKEN).append(SPACE); - } else if (stroke.getMiterLimit() == BasicStroke.JOIN_ROUND) { - postScript.append(1).append(SPACE) - .append(PdfOps.j_TOKEN).append(SPACE); - } else if (stroke.getMiterLimit() == BasicStroke.JOIN_BEVEL) { - postScript.append(2).append(SPACE) - .append(PdfOps.j_TOKEN).append(SPACE); - } - postScript.append(NEWLINE); - } - // graphics state setup - else if (drawCmd instanceof GraphicsStateCmd) { - postScript.append('/') - .append(((GraphicsStateCmd) drawCmd).getGraphicStateName()).append(SPACE) - .append(PdfOps.gs_TOKEN).append(SPACE); - } - // break out a text block and child paint operands. - else if (drawCmd instanceof TextSpriteDrawCmd) { - postScript.append(PdfOps.BT_TOKEN).append(NEWLINE); - TextSpriteDrawCmd textSpriteDrawCmd = (TextSpriteDrawCmd) drawCmd; - TextSprite textSprite = textSpriteDrawCmd.getTextSprite(); - - ArrayList glyphTexts = textSprite.getGlyphSprites(); - if (glyphTexts.size() > 0) { - // write out stat of text paint - postScript.append("1 0 0 -1 ") - .append(glyphTexts.get(0).getX()).append(SPACE) - .append(glyphTexts.get(0).getY()).append(SPACE).append(PdfOps.Tm_TOKEN).append(NEWLINE); - - // write out font - postScript.append("/").append(textSprite.getFontName()).append(SPACE) - .append(textSprite.getFontSize()).append(SPACE).append(PdfOps.Tf_TOKEN).append(NEWLINE); - - // set the colour - float[] colors = textSprite.getStrokeColor().getRGBColorComponents(null); - // set fill color - postScript.append(colors[0]).append(SPACE) - .append(colors[1]).append(SPACE) - .append(colors[2]).append(SPACE) - .append(PdfOps.rg_TOKEN).append(NEWLINE); - float y = glyphTexts.get(0).getY(); - StringBuilder line = new StringBuilder(); - GlyphText glyphText; - for (int i = 0, max = glyphTexts.size(); i < max; i++) { - glyphText = glyphTexts.get(i); - - // write out the line - if (y != glyphText.getY() || i == max - 1) { - // make sure we write out the last character. - if (i == max - 1) { - line.append(glyphText.getUnicode()); - } - postScript.append(BEGIN_ARRAY).append(BEGIN_STRING) - // use literal string to make sure string is escaped correctly - .append(new LiteralStringObject(line.toString()).toString()) - .append(END_STRING) - .append(END_ARRAY).append(SPACE) - .append(PdfOps.TJ_TOKEN).append(NEWLINE); - // add shift if newline - postScript.append(0).append(SPACE).append(y - glyphText.getY()) - .append(SPACE).append(PdfOps.Td_TOKEN).append(NEWLINE); - // update the current. - y = glyphText.getY(); - line = new StringBuilder(); - } - line.append(glyphText.getUnicode()); - } - postScript.append(PdfOps.ET_TOKEN).append(NEWLINE); - } - } - } - } catch (Throwable e) { - logger.log(Level.WARNING, "Error encoding PostScript notation ", e); - } - if (logger.isLoggable(Level.FINER)) { - logger.finer("PostEncoding: " + postScript.toString()); - } - return postScript.toString().getBytes(); - } - - /** - * Utility to create postscript draw operations from a shapes path - * iterator. - * - * @param currentShape shape to build out draw commands. - * @param postScript string to append draw operands to. - */ - private static void generateShapePostScript(Shape currentShape, StringBuilder postScript) { - PathIterator pathIterator = currentShape.getPathIterator(null); - float[] segment = new float[6]; - int segmentType; - while (!pathIterator.isDone()) { - segmentType = pathIterator.currentSegment(segment); - switch (segmentType) { - case PathIterator.SEG_MOVETO: - postScript.append(segment[0]).append(SPACE) - .append(segment[1]).append(SPACE) - .append(PdfOps.m_TOKEN).append(NEWLINE); - break; - case PathIterator.SEG_LINETO: - postScript.append(segment[0]).append(SPACE) - .append(segment[1]).append(SPACE) - .append(PdfOps.l_TOKEN).append(NEWLINE); - break; - case PathIterator.SEG_QUADTO: - postScript.append(segment[0]).append(SPACE) - .append(segment[1]).append(SPACE) - .append(segment[2]).append(SPACE) - .append(segment[3]).append(SPACE) - .append(PdfOps.v_TOKEN).append(NEWLINE); - break; - case PathIterator.SEG_CUBICTO: - postScript.append(segment[0]).append(SPACE) - .append(segment[1]).append(SPACE) - .append(segment[2]).append(SPACE) - .append(segment[3]).append(SPACE) - .append(segment[4]).append(SPACE) - .append(segment[5]).append(SPACE) - .append(PdfOps.c_TOKEN).append(NEWLINE); - break; - case PathIterator.SEG_CLOSE: - postScript.append(PdfOps.h_TOKEN).append(SPACE); - break; - } - pathIterator.next(); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ShapeDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ShapeDrawCmd.java deleted file mode 100644 index 4f991faaca..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ShapeDrawCmd.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * ShapeDrawCmd actually doesn't paint anything, just returns the shapes - * object for further processing. - * - * @since 5.0 - */ -public class ShapeDrawCmd implements DrawCmd { - - private Shape shape; - - public ShapeDrawCmd(Shape shape) { - this.shape = shape; - } - - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, - PaintTimer paintTimer) { - return shape; - } - - public void setShape(Shape shape) { - this.shape = shape; - } - - public Shape getShape() { - return shape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ShapesDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ShapesDrawCmd.java deleted file mode 100644 index 2549dd8321..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/ShapesDrawCmd.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; -import org.icepdf.core.pobjects.graphics.Shapes; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * The ShapesDrawCmd stores a Shapes object, usually the result of a processing - * a xObjects content stream. When executed the stores Shapes object is - * painted using the specified graphics context. - * - * @since 5.0 - */ -public class ShapesDrawCmd extends AbstractDrawCmd { - - private Shapes shapes; - - public ShapesDrawCmd(Shapes shapes) { - this.shapes = shapes; - } - - public Shapes getShapes() { - return shapes; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) throws InterruptedException { - if (optionalContentState.isVisible() && - shapes != null) { - shapes.setPageParent(parentPage); - shapes.setPaintAlpha(paintAlpha); - shapes.paint(g); - shapes.setPageParent(null); - } - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/StrokeDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/StrokeDrawCmd.java deleted file mode 100644 index cf31c5bbfe..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/StrokeDrawCmd.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * The StrokeDrawCmd stores a Stroke object and when executed the stroke - * is applied to the graphics context. - * - * @since 5.0 - */ -public class StrokeDrawCmd extends AbstractDrawCmd { - - private Stroke stroke; - - public StrokeDrawCmd(Stroke stroke) { - this.stroke = stroke; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - g.setStroke(stroke); - return currentShape; - } - - public Stroke getStroke() { - return stroke; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TextSpriteDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TextSpriteDrawCmd.java deleted file mode 100644 index 970eab595d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TextSpriteDrawCmd.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; -import org.icepdf.core.pobjects.graphics.TextSprite; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * The TextSpriteDrawCmd stores an TextSprite instance and when executed the - * the TextSprite paint method is called the the respective glyphs are painted - * the graphics context. - * - * @since 5.0 - */ -public class TextSpriteDrawCmd extends AbstractDrawCmd { - - private TextSprite textSprite; - - public TextSpriteDrawCmd(TextSprite textSprite) { - this.textSprite = textSprite; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer lastPaintTime) { - - if (optionalContentState.isVisible() && - textSprite.intersects(g.getClip())) { - textSprite.paint(g); - } - - return currentShape; - } - - public TextSprite getTextSprite() { - return textSprite; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TextTransformDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TextTransformDrawCmd.java deleted file mode 100644 index 15116bb0c9..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TextTransformDrawCmd.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * - */ -public class TextTransformDrawCmd extends AbstractDrawCmd { - - private AffineTransform affineTransform; - - public TextTransformDrawCmd(AffineTransform affineTransform) { - this.affineTransform = affineTransform; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - AffineTransform af = new AffineTransform(base); - af.concatenate(affineTransform); - g.setTransform(af); - return currentShape; - } - - public AffineTransform getAffineTransform() { - return affineTransform; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TilingPatternDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TilingPatternDrawCmd.java deleted file mode 100644 index b16a7baf9d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TilingPatternDrawCmd.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; -import org.icepdf.core.pobjects.graphics.TilingPattern; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * TilingPatternDrawCmd stores a tilingPattern and applies the TilingPattern - * Paint when when the command is executed. - * - * @since 5.0 - */ -public class TilingPatternDrawCmd extends AbstractDrawCmd { - - private TilingPattern tilingPattern; - - public TilingPatternDrawCmd(TilingPattern tilingPattern) { - this.tilingPattern = tilingPattern; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - tilingPattern.paintPattern(g, base); - return currentShape; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TransformDrawCmd.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TransformDrawCmd.java deleted file mode 100644 index 26e5f2423c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/commands/TransformDrawCmd.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.commands; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.OptionalContentState; -import org.icepdf.core.pobjects.graphics.PaintTimer; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * TransformDrawCmd stores a affineTransform that is applied to the graphics - * context when the command is executed. - * - * @since 5.0 - */ -public class TransformDrawCmd extends AbstractDrawCmd { - - private AffineTransform affineTransform; - - public TransformDrawCmd(AffineTransform affineTransform) { - this.affineTransform = affineTransform; - } - - @Override - public Shape paintOperand(Graphics2D g, Page parentPage, Shape currentShape, - Shape clip, AffineTransform base, - OptionalContentState optionalContentState, - boolean paintAlpha, PaintTimer paintTimer) { - AffineTransform af = new AffineTransform(base); - af.concatenate(affineTransform); - g.setTransform(af); - return currentShape; - } - - public AffineTransform getAffineTransform() { - return affineTransform; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/AbstractText.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/AbstractText.java deleted file mode 100644 index 422380cf18..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/AbstractText.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -import java.awt.geom.GeneralPath; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; - -/** - * Abstract text is the base class for all Text extraction data. Its main - * purpose to is hold common data for GeneralPath and Bounds and common - * contains and intersect calculations. - *

      - * Some paintable properties are also defined here, such as selected, has selected - * highlight and hasHighlight which are used as queues to painting selected - * or highlighted text. - * - * @since 4.0 - */ -public abstract class AbstractText implements Text { - - // Bounds of text converted to page space. - protected Rectangle2D.Float bounds; - - // original bounds as plotted by the PDF, can be used for space and - // line break detection. Once normalized to page space (bounds instance var) - // it may not be possible to make the formatting detection. However normalized - // bounds are used for text selection. - protected Rectangle2D.Float textExtractionBounds; - - // selected states - protected boolean selected; - // highlight state - protected boolean highlight; - - // highlight hint for quicker painting - protected boolean hasSelected; - // highlight hint for quicker painting - protected boolean hasHighlight; - - /** - * Gets the bounds of the respective text object normalized to page - * space. This is mainly used for text selection calculations. - * - * @return bounds of text object. - */ - public abstract Rectangle2D.Float getBounds(); - - public void clearBounds() { - bounds = null; - } - - /** - * Creates a new instance of GeneralPath for this AbstractText object and - * applies the current pageTransformation to it. The containment - * calculation is then applied the newly transformed path for the given - * rectangle. - *

      - * This method is usually used for text selection via a selection box. - * - * @param rect rectangle to check intersection of in page. - * @return true if the point is contained with in this Text instance. - */ - public boolean intersects(Rectangle2D rect) { - // bounds is lazy loaded so getBounds is need to get the value correctly. - GeneralPath shapePath = new GeneralPath(getBounds()); - return shapePath.intersects(rect); - } - - /** - * Tests if the point intersects the text bounds. - * - * @param point point to test for intersection. - * @return true if the point intersects the text bounds, otherwise false. - */ - public boolean intersects(Point2D.Float point) { - // bounds is lazy loaded so getBounds is need to get the value correctly. - GeneralPath shapePath = new GeneralPath(getBounds()); - return shapePath.contains(point); - } - - /** - * Is the AbstractText selected, all of its children must also be selected. - * - * @return true if selected false otherwise. - */ - public boolean isSelected() { - return selected; - } - - /** - * Sets the AbstractText as selected, if it child AbstractText object they - * must also be selected. - * - * @param selected selected state. - */ - public void setSelected(boolean selected) { - this.selected = selected; - } - - /** - * Is the AbstractText highlighted, all of its children must also be - * highlighted. - * - * @return true if highlighted false otherwise. - */ - public boolean isHighlighted() { - return highlight; - } - - /** - * Sets the AbstractText as highlighted, if it child AbstractText object they - * must also be highlighted. - * - * @param highlight selected state. - */ - public void setHighlighted(boolean highlight) { - this.highlight = highlight; - } - - /** - * Indicates that at least this or one of the child instances of AbstractText - * is highlighted. - * - * @return true if one or more root or parent elements are in a highlighted - * state. - */ - public boolean hasHighligh() { - return hasHighlight; - } - - /** - * Indicates that at least this or one of the child instances of AbstractText - * is selected. - * - * @return true if one or more root or parent elements are in a highlighted - * state. - */ - public boolean hasSelected() { - return hasSelected; - } - - /** - * Set the highlighted state, meaning that this instance or one of the child - * AbstractText objects has a highlighted state. - * - * @param hasHighlight true to indicates a highlighted states. - */ - public void setHasHighlight(boolean hasHighlight) { - this.hasHighlight = hasHighlight; - } - - /** - * Set the selected state, meaning that this instance or one of the child - * AbstractText objects has a selected state. - * - * @param hasSelected true to indicates a selected states. - */ - public void setHasSelected(boolean hasSelected) { - this.hasSelected = hasSelected; - } - - /** - * Gets the original bounds of the text unit, this value is not normalized - * to page space and represents the raw layout coordinates of the text as - * defined in the Post Script notation. This is primarily used for text - * extraction line and word break calculations. - * - * @return text bounds. - */ - public Rectangle2D.Float getTextExtractionBounds() { - return textExtractionBounds; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/GlyphText.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/GlyphText.java deleted file mode 100644 index ca087ec6bd..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/GlyphText.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.Rectangle2D; -import java.util.logging.Logger; - -/** - * Glyph Sprite contains glyph bound and textual information for drawing - * and text extraction. The Object is used as a child of TextSprite - * for painting and as a child of TextWord for text extraction and selection. - * - * @since 4.0 - */ -public class GlyphText extends AbstractText { - - private static final Logger logger = - Logger.getLogger(GlyphText.class.toString()); - - // x and y coordinates used for painting glyph - private float x, y; - - // character code used to represent glyph, maybe ascii or CID value - private String cid; - - // Unicode/ASCII value that is represented by glyph, a cid can be - // represented by one or more characters. - private String unicode; - - public GlyphText(float x, float y, Rectangle2D.Float bounds, - String cid, String unicode) { - this.x = x; - this.y = y; - this.bounds = bounds; - this.textExtractionBounds = new Rectangle2D.Float(bounds.x, bounds.y, bounds.width, bounds.height); - this.cid = cid; - this.unicode = unicode; - } - - /** - * Maps the glyph bounds to user space - * - * @param af transform from glyph space to user space - * @param af1 transform from glyph space, if shear is detected the - * extracted bounds are rotated back to the portrait layout. - */ - public void normalizeToUserSpace(AffineTransform af, AffineTransform af1) { - // map the coordinates from glyph space to user space. - GeneralPath generalPath = new GeneralPath(bounds); - generalPath.transform(af); - bounds = (Rectangle2D.Float) generalPath.getBounds2D(); - // we have some portrait type layouts where the text is actually - // running on the y-axis. The reason for this is Tm that specifies - // a -1 shear which is basically a 90 degree rotation. Which breaks - // our left to right top down text extraction logic (PDF-854). - if (af1 != null && af1.getShearX() < -1) { - // adjust of the rotation, move the text back to a normal layout. - generalPath = new GeneralPath(bounds); - generalPath.transform(new AffineTransform(0, -1, 1, 0, 0, 0)); - textExtractionBounds = (Rectangle2D.Float) generalPath.getBounds2D(); - } else if (af1 != null && af1.getShearY() < -1) { - // adjust of the rotation, move the text back to a normal layout. - generalPath = new GeneralPath(bounds); - generalPath.transform(new AffineTransform(0, 1, -1, 0, 0, 0)); - textExtractionBounds = (Rectangle2D.Float) generalPath.getBounds2D(); - } else { - // 99% of the time we just use the bounds. - textExtractionBounds = bounds; - } - - } - - public String getCid() { - return cid; - } - - public String getUnicode() { - return unicode; - } - - public float getX() { - return x; - } - - public float getY() { - return y; - } - - public Rectangle2D.Float getBounds() { - return bounds; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/LinePositionComparator.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/LinePositionComparator.java deleted file mode 100644 index 193d5bfb66..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/LinePositionComparator.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -import java.awt.*; -import java.util.Comparator; - -/** - * The LinePositionComparator is optionally called by text extraction algorithms - * to help insure text lines found on a page are ordered using the y coordinates - * of the bounding box in the cartesian plane's fourth quadrant. The sorting - * tries to order the line blocks via the coordinate system rather then the order - * that they were plotted in. - *

      - * It's assumed that all LineText that is a child of PageText will not be - * sorted on the x access. The class WordPositionComparator will be used - * to insure that words are ordered correctly in the parent PageText array. - * - * @since 5.0.6 - */ -public class LinePositionComparator implements - Comparator { - - /** - * Compares the y coordinates of the AbstractText bounding box's y coordinate. - * - * @param lt1 word text object to compare - * @param lt2 word text object to compare - * @return the value 0 if lt1.y is numerically equal to lt2.y; a value less - * than 0 if lt1.y is numerically less than lt2.y; and a value greater than 0 - * if lt1.y is numerically greater than lt2.y. - */ - public int compare(AbstractText lt1, AbstractText lt2) { - -// int comp = Float.compare(lt2.getBounds().y, lt1.getBounds().y); -// if (comp == 0){ -// comp = Float.compare(lt1.getBounds().x, lt2.getBounds().x); -// } -// return comp; - - return Float.compare(lt2.getBounds().y, lt1.getBounds().y); - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/LineText.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/LineText.java deleted file mode 100644 index 3f8494a0c0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/LineText.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.List; - -/** - * Line text is make up WordText objects. This structure is to aid the - * the identification of words for text extraction, searching and selecting. - * - * @since 4.0 - */ -public class LineText extends AbstractText implements TextSelect { - - private WordText currentWord; - - private List words; - - public LineText() { - words = new ArrayList(16); - } - - public Rectangle2D.Float getBounds() { - // lazy load the bounds as the calculation is very expensive - if (bounds == null) { - // word bounds build from child word bounds. - for (WordText word : words) { - if (bounds == null) { - bounds = new Rectangle2D.Float(); - bounds.setRect(word.getBounds()); - } else { - bounds.add(word.getBounds()); - } - } - // empty line text check, return empty bound. - if (bounds == null) { - bounds = new Rectangle2D.Float(); - } - } - return bounds; - } - - /** - * Add the sprite to the current word in this line/sentence. This method - * also candles white space detection and word division. - * - * @param sprite sprite to add to line. - */ - protected void addText(GlyphText sprite) { - - // look for white space characters and insert whitespace word - if (WordText.detectWhiteSpace(sprite) || - WordText.detectPunctuation(sprite, currentWord)) { - // add as a new word, nothing special otherwise - WordText newWord = new WordText(); - newWord.setWhiteSpace(true); - newWord.addText(sprite); - addWord(newWord); - // ready new word - currentWord = null; - } - // detect if there should be any spaces between the new sprite - // and the last sprite. - else if (getCurrentWord().detectSpace(sprite)) { - // build space word. - WordText spaceWord = currentWord.buildSpaceWord(sprite); - spaceWord.setWhiteSpace(true); - // add space word, - addWord(spaceWord); - // ready a new word - currentWord = null; - // add the text again to register the glyph - addText(sprite); - } - // business as usual - else { - getCurrentWord().addText(sprite); - } - } - - public void clearCurrentWord(){ - // make sure we don't insert a new line if the previous has no words. - if (currentWord != null && - currentWord.size() == 0) { - return; - } - currentWord = null; - } - - /** - * Adds the specified word to the end of the line collection and makes - * the new word the currentWord reference. - * - * @param wordText word to add - */ - private void addWord(WordText wordText) { - - // add the word, text or white space. - this.words.add(wordText); - - // word test - currentWord = wordText; - - } - - public void addAll(List words) { - this.words.addAll(words); - } - - protected void setWords(List words) { - this.words = words; - } - - /** - * Gets the current word, if there is none, one is created. - * - * @return current word instance. - */ - private WordText getCurrentWord() { - if (currentWord == null) { - currentWord = new WordText(); - words.add(currentWord); - } - return currentWord; - } - - /** - * Gets the words that make up this line. - * - * @return words in a line. - */ - public List getWords() { - return words; - } - - /** - * Select all text in this line; all word and glyph children. - */ - public void selectAll() { - setSelected(true); - setHasSelected(true); - for (WordText word : words) { - word.selectAll(); - } - } - - /** - * Deselects all text in this line; all word and glyph children. - */ - public void clearSelected() { - setSelected(false); - setHasSelected(false); - for (WordText word : words) { - word.clearSelected(); - } - } - - /** - * Dehighlights all text in the line; all word and glyph children. - */ - public void clearHighlighted() { - setHighlighted(false); - setHasHighlight(false); - for (WordText word : words) { - word.setHighlighted(false); - } - } - - /** - * Interates over child elements getting the selected text as defined by - * the child glyphs unicode value. Line breaks and spaces are preserved - * where possible. - * - * @return StringBuffer of selected text in this line. - */ - public StringBuilder getSelected() { - StringBuilder selectedText = new StringBuilder(); - - for (WordText word : words) { - selectedText.append(word.getSelected()); - } - return selectedText; - } - - public String toString() { - return words.toString(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/PageText.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/PageText.java deleted file mode 100644 index b9284102cc..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/PageText.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -import org.icepdf.core.pobjects.OptionalContents; -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.util.*; -import java.util.List; - -/** - * Page text represents the root element of a page's text hierarchy which - * looks something like this. - *

        - * PageText -> LineText* -> WordText* -> GlyphText* - *
      - * The hierarchy elements are build by the content parser when text extraction - * is enabled. It is build to seperate the huristics used to calculate - * word and line detection which is used for text extraction/search, - * search highlighting and text highlighting. - *

      - * It very important to note that all coordinates system represented in this - * hierarchy of object has been normalized to the page space. This allows for - * object to be sorted and drawn. Also this structure is not used for page - * layout and painting. It is is used for painting text selectin via UI input - * or search. The seperation is needed so that the text represented in Page - * text can be padded and sorted to aid in text extraction readability. - * - * @since 4.0 - */ -public class PageText implements TextSelect { - - private static boolean checkForDuplicates; - private static boolean preserveColumns; - - static { - checkForDuplicates = Defs.booleanProperty( - "org.icepdf.core.views.page.text.trim.duplicates", false); - - preserveColumns = Defs.booleanProperty( - "org.icepdf.core.views.page.text.preserveColumns", true); - } - - // pointer to current line during document parse, no other use. - private LineText currentLine; - - private ArrayList pageLines; - private ArrayList sortedPageLines; - - private AffineTransform previousTextTransform; - - private LinkedHashMap optionalPageLines; - - public PageText() { - pageLines = new ArrayList(64); - } - - public void newLine(LinkedList oCGs) { - if (oCGs != null && oCGs.size() > 0) { - if (optionalPageLines == null) { - optionalPageLines = new LinkedHashMap(10); - } - OptionalContents optionalContent = oCGs.peek(); - PageText pageText = optionalPageLines.get(optionalContent); - if (pageText == null) { - // create a text object add the glyph. - pageText = new PageText(); - pageText.newLine(); - optionalPageLines.put(optionalContent, pageText); - } else { - pageText.newLine(); - } - } - } - - public void newLine() { - // make sure we don't insert a new line if the previous has no words. - if (currentLine != null && - currentLine.getWords().size() == 0) { - return; - } - currentLine = new LineText(); - pageLines.add(currentLine); - } - - protected void addGlyph(GlyphText sprite) { - if (currentLine == null) { - newLine(); - } - currentLine.addText(sprite); - } - - /** - * Creates a copy of the pageLines array and sorts that text both - * vertically and horizontally to aid in the proper ordering during text - * extraction. The value is cached so any changes to optional content - * visibility should require that the cache is refreshed with a call to - * {@see sortAndFormatText}. - *

      - * During the extraction process extra space will automatically be added - * between words. However depending on how the PDF is encoded can result - * in too many extra spaces. So as a result this feature can be turned off - * with the system property org.icepdf.core.views.page.text.autoSpace which - * is set to True by default. - * - * @return list of page lines that are in the main content stream and any - * visible layers. - */ - public ArrayList getPageLines() { - if (sortedPageLines == null) { - sortAndFormatText(); - } - return sortedPageLines; - } - - /** - * Gets all visible lines, checking the page text for any text that is - * in an optional content group and that that group is flagged as visible. - * - * @return list of all visible lineText. - */ - private ArrayList getVisiblePageLines(boolean skip) { - ArrayList visiblePageLines = skip ? new ArrayList() : new ArrayList(pageLines); - // add optional content text that is visible. - // check optional content. - if (optionalPageLines != null) { - // iterate over optional content keys and extract text from visible groups - Set keys = optionalPageLines.keySet(); - for (OptionalContents key : keys) { - if (key != null && key.isVisible()) { - ArrayList pageLines = optionalPageLines.get(key).getVisiblePageLines(false); - LineText currentLine = new LineText(); - visiblePageLines.add(currentLine); - for (LineText lineText : pageLines) { - currentLine.addAll(lineText.getWords()); - // recalculate the bounds. - currentLine.getBounds(); - } - } - } - } - return visiblePageLines; - } - - private ArrayList getAllPageLines() { - ArrayList visiblePageLines = new ArrayList(pageLines); - // add optional content text that is visible. - // check optional content. - if (optionalPageLines != null) { - // iterate over optional content keys and extract text from visible groups - Set keys = optionalPageLines.keySet(); - LineText currentLine = new LineText(); - visiblePageLines.add(currentLine); - for (OptionalContents key : keys) { - if (key != null) { - ArrayList pageLines = optionalPageLines.get(key).getVisiblePageLines(true); - for (LineText lineText : pageLines) { - currentLine.addAll(lineText.getWords()); - } - } - } - // recalculate the bounds. - currentLine.getBounds(); - } - return visiblePageLines; - } - - /** - * Adds the specified pageLines to the array of pageLines. Generally only - * called when passing text form xObjects up to their parent shapes text. - * - * @param pageLines page lines to add. - */ - public void addPageLines(ArrayList pageLines) { - if (pageLines != null) { - this.pageLines.addAll(pageLines); - } - } - - public void setTextTransform(AffineTransform affineTransform) { - // look to see if we have shear and thus text that has been rotated, if so we insert a page break - if (previousTextTransform != null && currentLine != null) { - // hard round as we're just looking for a 90 degree shift in writing direction. - // if found we clear the current work so we can start a new word. - if ((previousTextTransform.getShearX() < 0 && (int) affineTransform.getShearX() > 0) || - (previousTextTransform.getShearX() > 0 && (int) affineTransform.getShearX() < 0) || - (previousTextTransform.getShearY() < 0 && (int) affineTransform.getShearY() > 0) || - (previousTextTransform.getShearY() > 0 && (int) affineTransform.getShearY() < 0)) { - currentLine.clearCurrentWord(); - } - } - previousTextTransform = affineTransform; - } - - public void addGlyph(GlyphText glyphText, LinkedList oCGs) { - if (oCGs != null && oCGs.size() > 0) { - if (oCGs.peek() != null) { - addOptionalPageLines(oCGs.peek(), glyphText); - } - } else { - addGlyph(glyphText); - } - } - - protected void addOptionalPageLines(OptionalContents optionalContent, - GlyphText sprite) { - if (optionalPageLines == null) { - optionalPageLines = new LinkedHashMap(10); - } - PageText pageText = optionalPageLines.get(optionalContent); - if (pageText == null) { - // create a text object add the glyph. - pageText = new PageText(); - pageText.addGlyph(sprite); - optionalPageLines.put(optionalContent, pageText); - } else { - pageText.addGlyph(sprite); - } - } - - /** - * Utility method to normalize text created in a Xform content stream - * and is only called from the contentParser when parsing 'Do' token. - * - * @param transform do matrix transform - */ - public void applyXObjectTransform(AffineTransform transform) { - for (LineText lineText : pageLines) { - lineText.clearBounds(); - for (WordText wordText : lineText.getWords()) { - wordText.clearBounds(); - for (GlyphText glyph : wordText.getGlyphs()) { - glyph.normalizeToUserSpace(transform, null); - } - } - } - } - - public void clearSelected() { - if (pageLines != null) { - for (LineText lineText : pageLines) { - lineText.clearSelected(); - } - } - if (sortedPageLines != null) { - for (LineText lineText : sortedPageLines) { - lineText.clearSelected(); - } - } - // check optional content. - if (optionalPageLines != null) { - // iterate over optional content keys and extract text from visible groups - Set keys = optionalPageLines.keySet(); - ArrayList optionalLines; - for (OptionalContents key : keys) { - if (key != null) { - optionalLines = optionalPageLines.get(key).getAllPageLines(); - if (optionalLines != null) { - for (LineText lineText : optionalLines) { - lineText.clearSelected(); - } - } - } - } - } - } - - public void clearHighlighted() { - for (LineText lineText : pageLines) { - lineText.clearHighlighted(); - } - for (LineText lineText : sortedPageLines) { - lineText.clearHighlighted(); - } - // check optional content. - if (optionalPageLines != null) { - // iterate over optional content keys and extract text from visible groups - Set keys = optionalPageLines.keySet(); - ArrayList optionalLines; - for (OptionalContents key : keys) { - if (key != null && key.isVisible()) { - optionalLines = optionalPageLines.get(key).getAllPageLines(); - for (LineText lineText : optionalLines) { - lineText.clearHighlighted(); - } - } - } - } - } - - public StringBuilder getSelected() { - StringBuilder selectedText = new StringBuilder(); - ArrayList pageLines = getPageLines(); - if (pageLines != null) { - StringBuilder selectedLineText; - for (LineText lineText : pageLines) { - selectedLineText = lineText.getSelected(); - if (selectedLineText != null && selectedLineText.length() > 0) { - selectedText.append(selectedLineText); - selectedText.append("\n"); - } - } - } - return selectedText; - } - - public void selectAll() { - ArrayList pageLines = getPageLines(); - if (pageLines != null) { - for (LineText lineText : pageLines) { - lineText.selectAll(); - } - } - } - - public void deselectAll() { - for (LineText lineText : pageLines) { - lineText.clearSelected(); - } - } - - public String toString() { - StringBuilder extractedText = new StringBuilder(); - for (LineText lineText : pageLines) { - - for (WordText wordText : lineText.getWords()) { - extractedText.append(wordText.getText()); - } - extractedText.append('\n'); - } - return extractedText.toString(); - } - - /** - * Sorts the given pageLines vertically (y coordinate) in page space. . - * - * @param pageLines page lines to sort, not directly sorted, new array is created for sorted data. - * @return new array of sorted pages lines - */ - private ArrayList sortLinesVertically(ArrayList pageLines) { - ArrayList sortedPageLines = new ArrayList(64); - // move over all - for (LineText pageLine : pageLines) { - // all page words will be on one line - java.util.List words = pageLine.getWords(); - if (words != null && words.size() > 0) { - // break the words into lines on every change of y - double lastY = Math.round(words.get(0).getTextExtractionBounds().y); - int start = 0, end = 0; - double currentY, diff; - for (WordText word : words) { - currentY = Math.round(word.getTextExtractionBounds().getY()); - // little bit of tolerance for detecting a line, basically anything that is - // > then half the current word height / 2 will be marked as a break. - // this works well enough sub and super script and inconsistencies - // on table base text. - diff = Math.abs(currentY - lastY); - if (diff != 0 && diff > word.getTextExtractionBounds().getHeight() / 2) { - LineText lineText = new LineText(); - lineText.addAll(words.subList(start, end)); - sortedPageLines.add(lineText); - start = end; - } - end++; - lastY = currentY; - } - if (start < end) { - LineText lineText = new LineText(); - lineText.addAll(words.subList(start, end)); - sortedPageLines.add(lineText); - } - } - } - return sortedPageLines; - } - - /** - * Insert optional content into the main LineText array, basically we are trying to consolidate all the - * visible text in the document. - * - * @param sortedPageLines List of LineText to add visible optional content to. - */ - private void insertOptionalLines(ArrayList sortedPageLines) { - ArrayList optionalPageLines = getVisiblePageLines(true); - if (optionalPageLines != null) { - for (LineText optionalPageLine : optionalPageLines) { - float yOptional = optionalPageLine.getBounds().y; - boolean found = false; - for (LineText sortedPageLine : sortedPageLines) { - Rectangle sortedBounds = sortedPageLine.getBounds().getBounds(); - float height = sortedBounds.height; - float y = sortedBounds.y; - float diff = Math.abs(yOptional - y); - // corner case inclusion of a word and a space which is out of order from the - // rest of the text in the document. - if (diff < height) { - sortedPageLine.addAll(optionalPageLine.getWords()); - found = true; - break; - } - } - if (!found) { - sortedPageLines.add(optionalPageLine); - } - } - } - } - - /** - * Takes the raw page lines represented as one continuous line and sorts the - * text by the y access of the word bounds. The words are then sliced into - * separate lines base on y changes. And finally each newly sorted line is - * sorted once more by each words x coordinate. - */ - public void sortAndFormatText() { - ArrayList visiblePageLines = new ArrayList(pageLines); - // create new array for storing the sorted lines - ArrayList sortedPageLines = sortLinesVertically(visiblePageLines); - // try and insert the option words on existing lines - if (sortedPageLines.size() == 0) { - sortedPageLines = getVisiblePageLines(true); - } else { - insertOptionalLines(sortedPageLines); - } - - // sort again - sortedPageLines = sortLinesVertically(sortedPageLines); - - // do a rough check for duplicate strings that are sometimes generated - // by Chrystal Reports. Enable with - // -Dorg.icepdf.core.views.page.text.trim.duplicates=true - if (checkForDuplicates) { - for (final LineText lineText : sortedPageLines) { - final List words = lineText.getWords(); - if (words.size() > 0) { - final List trimmedWords = new ArrayList(); - final Set refs = new HashSet(); - for (final WordText wordText : words) { - // use regular rectangle so get a little rounding. - final String key = wordText.getText() + wordText.getBounds().getBounds(); - if (refs.add(key)) { - trimmedWords.add(wordText); - } - } - lineText.setWords(trimmedWords); - } - } - } - - // sort each line by x coordinate. - if (sortedPageLines.size() > 0) { - for (LineText lineText : sortedPageLines) { - Collections.sort(lineText.getWords(), - new WordPositionComparator()); - } - } - - // recalculate the line bounds. - if (sortedPageLines.size() > 0) { - for (LineText lineText : sortedPageLines) { - lineText.getBounds(); - } - } - - // sort the lines - if (sortedPageLines.size() > 0 && !preserveColumns) { - Collections.sort(sortedPageLines, - new LinePositionComparator()); - } - // assign back the sorted lines. - this.sortedPageLines = sortedPageLines; - - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/Text.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/Text.java deleted file mode 100644 index 5ce3d541d5..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/Text.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -import java.awt.geom.Rectangle2D; - -/** - * Sprite interface which is base for all text sprite types. Mainly line, - * text, word and glyph. They are used for managing text extraction. - * - * @since 4.0 - */ -public interface Text { - - public Rectangle2D.Float getBounds(); - - public boolean isHighlighted(); - - public boolean isSelected(); - - public void setHighlighted(boolean highlight); - - public void setSelected(boolean selected); - - public boolean hasHighligh(); - - public boolean hasSelected(); - - public void setHasHighlight(boolean hasHighlight); - - public void setHasSelected(boolean hasSelected); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/TextPositionComparator.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/TextPositionComparator.java deleted file mode 100644 index 57703430fd..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/TextPositionComparator.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -import java.util.Comparator; - -/** - * Text Position Comparator to sort AbstractText objects that might not be - * plotted in a top down fasion. The comparator only looks at vertical position - * and does not sort text in the horizontal plain, for example LTR or RTL text - * layouts. - * - * @since 5.0.1 - */ -public class TextPositionComparator implements - Comparator { - - public int compare(AbstractText lt1, AbstractText lt2) { - float y1 = lt1.bounds.y; - float y2 = lt2.bounds.y; - float x1 = lt1.bounds.x; - float x2 = lt2.bounds.x; - return y1 != y2 ? Float.compare(y2, y1) : Float.compare(x1, x2); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/TextSelect.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/TextSelect.java deleted file mode 100644 index 07df7a85f3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/TextSelect.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -/** - * Text select definitions. - * - * @since 4.0 - */ -public interface TextSelect { - - public void clearSelected(); - - public StringBuilder getSelected(); - - public void clearHighlighted(); - - public void selectAll(); -// -// public void deselectAll(); -// -// public void selectAllRight(); -// -// public void selectAllLeft(); -// -// public boolean isSelected(); -// -// public void setSelected(boolean selected); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/WordPositionComparator.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/WordPositionComparator.java deleted file mode 100644 index 7c9a9b3166..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/WordPositionComparator.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -import java.util.Comparator; - -/** - * The WordPositionComparator is optionally called by text extraction algorithms - * to help insure words found in a line are ordered using the x coordinates - * of the bounding box in the cartesian plane's fourth quadrant. The sorting - * tries to order the word blocks via the coordinate system rather then the order - * that they were plotted in and thus shouldn't effect LTR or RTL writing formats. - *

      - * It's assumed that all WordText that is a child of LineText will not be - * sorted on the y access. The class LinePositionComparator will be used - * to insure that lines are ordered correctly in the parent PageText array. - * - * @since 5.0.6 - */ -public class WordPositionComparator implements - Comparator { - - /** - * Compares the x coordinates of the AbstractText bounding box's x coordinate. - * - * @param lt1 word text object to compare - * @param lt2 word text object to compare - * @return the value 0 if lt1.x is numerically equal to lt2.x; a value less - * than 0 if lt1.x is numerically less than lt2.x; and a value greater than 0 - * if lt1.x is numerically greater than lt2.x. - */ - public int compare(AbstractText lt1, AbstractText lt2) { - return Float.compare(lt1.getTextExtractionBounds().x, - lt2.getTextExtractionBounds().x); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/WordText.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/WordText.java deleted file mode 100644 index ccc5b812d8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/graphics/text/WordText.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.graphics.text; - -import org.icepdf.core.util.Defs; - -import java.awt.*; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Word text represents an individual word in the document. A word can - * also represent white space between words th isWhiteSpace method can be used - * to distguish between words and whiteSpace - *

      - * If extracted text has extract white space then the space width fraction - * can be adjusted. The deault value a 4th of the current character width. To - * add more sapces the number can be increase or decrease to limit the number - * of spaces that are added. The system property is as follows: - * Default
      - * org.icepdf.core.views.page.text.spaceFraction=4 - * - * @since 4.0 - */ -public class WordText extends AbstractText implements TextSelect { - - private static final Logger logger = - Logger.getLogger(WordText.class.toString()); - - // Space Glyph width fraction, the default is 1/x of the character width, - // constitutes a potential space between glyphs. - public static int spaceFraction; - - private static boolean autoSpaceInsertion; - - static { - // sets the shadow colour of the decorator. - try { - spaceFraction = Defs.sysPropertyInt( - "org.icepdf.core.views.page.text.spaceFraction", 3); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading text space fraction"); - } - } - // sets the shadow colour of the decorator. - try { - autoSpaceInsertion = Defs.sysPropertyBoolean( - "org.icepdf.core.views.page.text.autoSpace", true); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading text text auto space detection"); - } - } - } - - private GlyphText currentGlyph; - private ArrayList glyphs; - - // cached text values. - private StringBuilder text; - // is glyph white space. - private boolean isWhiteSpace; - // reference to last added text. - private int previousGlyphText; - - public WordText() { - text = new StringBuilder(); - glyphs = new ArrayList(4); - } - - public int size(){ - return text.length(); - } - - public boolean isWhiteSpace() { - return isWhiteSpace; - } - - public void setWhiteSpace(boolean whiteSpace) { - isWhiteSpace = whiteSpace; - } - - protected boolean detectSpace(GlyphText sprite) { - if (currentGlyph != null && autoSpaceInsertion) { - // last added glyph - Rectangle2D.Float bounds1 = currentGlyph.getTextExtractionBounds(); - float currentXCoord = sprite.getTextExtractionBounds().x; - float currentYCoord = sprite.getTextExtractionBounds().y; - float previousXCoord = currentGlyph.getTextExtractionBounds().x; - float previousYCoord = currentGlyph.getTextExtractionBounds().y; - // spaces can be negative if we have a LTR layout. - float space = Math.abs(currentXCoord - (previousXCoord + bounds1.width)); - // half previous glyph width will be used to determine a space - float tolerance = bounds1.width / spaceFraction; - // checking the y coordinate as well as any shift normall means a new work, this might need to get fuzzy later. - float ydiff = Math.abs(currentYCoord - previousYCoord); - return space > tolerance || ydiff > tolerance; - } else { - return false; - } - } - - protected static boolean detectPunctuation(GlyphText sprite, WordText currentWord) { - String glyphText = sprite.getUnicode(); - // make sure we don't have a decimal, we want to keep double numbers - // as one word. - if (glyphText != null && glyphText.length() > 0) { - int c = glyphText.charAt(0); - return isPunctuation(c) && !isDigit(currentWord); - } else { - return false; - } - } - - protected static boolean detectWhiteSpace(GlyphText sprite) { - String glyphText = sprite.getUnicode(); - if (glyphText != null && glyphText.length() > 0) { - int c = glyphText.charAt(0); - return isWhiteSpace(c); - } else { - return false; - } - } - - public static boolean isPunctuation(int c) { - return ((c == '.') || (c == ',') || (c == '?') || (c == '!') || - (c == ':') || (c == ';') || (c == '"') || (c == '\'') - || (c == '/') || (c == '\\') || (c == '`') || (c == '#')); - } - - public static boolean isWhiteSpace(int c) { - return ((c == ' ') || (c == '\t') || (c == '\r') || - (c == '\n') || (c == '\f')); - } - - public static boolean isDigit(WordText currentWord) { - if (currentWord != null) { - int c = currentWord.getPreviousGlyphText(); - return isDigit((char) c); - } else { - return false; - } - } - - public static boolean isDigit(char c) { - return c >= 48 && c <= 57; - } - - protected WordText buildSpaceWord(GlyphText sprite) { - - // because we are in a normalized user space we can work with ints - Rectangle2D.Float bounds1 = currentGlyph.getTextExtractionBounds(); - Rectangle.Float bounds2 = sprite.getTextExtractionBounds(); - float space = bounds2.x - (bounds1.x + bounds1.width); - - // max width of previous and next glyph, average can be broken by l or i etc. - float maxWidth = Math.max(bounds1.width, bounds2.width) / 2f; - int spaces = (int) (space / maxWidth); - if (spaces == 0) { - spaces = 1; - } - // add extra spaces - WordText whiteSpace = new WordText(); - double offset; - GlyphText spaceText = null; - Rectangle2D.Float spaceBounds; - // RTL layout - float spaceWidth = space / spaces; - boolean ltr = true; - if (spaces > 0) { - offset = bounds1.x + bounds1.width; - spaceBounds = new Rectangle2D.Float( - bounds1.x + bounds1.width, - bounds1.y, - spaceWidth, bounds1.height); - } - // LTR layout - else { - ltr = false; - offset = bounds1.x - bounds1.width; - spaces = 1;//Math.abs(spaces); - spaceBounds = new Rectangle2D.Float( - bounds.x - spaceWidth, - bounds1.y, - spaceWidth, bounds1.height); - } - // todo: consider just using one space with a wider bound - // Max out the spaces in the case the spaces value scale factor was - // not correct. We can end up with a very large number of spaces being - // inserted in some cases. - if (autoSpaceInsertion) { - for (int i = 0; i < spaces && i < 50; i++) { - whiteSpace = autoSpaceCalculation(offset, spaceBounds, whiteSpace); - if (ltr) { - spaceBounds.x += spaceBounds.width; - offset += spaceWidth; - } else { - spaceBounds.x -= spaceBounds.width; - offset -= spaceWidth; - } - } - } else { - whiteSpace = autoSpaceCalculation(offset, spaceBounds, whiteSpace); - } - return whiteSpace; - } - - private WordText autoSpaceCalculation(double offset, - Rectangle2D.Float spaceBounds, - WordText whiteSpace) { - GlyphText spaceText = new GlyphText((float) offset, - currentGlyph.getY(), - new Rectangle2D.Float(spaceBounds.x, - spaceBounds.y, - spaceBounds.width, - spaceBounds.height), - String.valueOf((char) 32), String.valueOf((char) 32)); - whiteSpace.addText(spaceText); - whiteSpace.setWhiteSpace(true); - return whiteSpace; - } - - - protected void addText(GlyphText sprite) { - // the sprite - glyphs.add(sprite); - - currentGlyph = sprite; - - // append the bounds calculation - if (bounds == null) { - Rectangle2D.Float rect = sprite.getBounds(); - bounds = new Rectangle2D.Float(rect.x, rect.y, rect.width, rect.height); - } else { - bounds.add(sprite.getBounds()); - } - if (textExtractionBounds == null) { - Rectangle2D.Float rect = sprite.getTextExtractionBounds(); - textExtractionBounds = new Rectangle2D.Float(rect.x, rect.y, rect.width, rect.height); - } else { - textExtractionBounds.add(sprite.getTextExtractionBounds()); - } - - // append the text that maps up the sprite - String unicode = sprite.getUnicode(); - previousGlyphText = unicode != null && unicode.length() > 0 ? - unicode.charAt(0) : 0; - text.append(unicode); - } - - public Rectangle2D.Float getBounds() { - if (bounds == null) { - // increase bounds as glyphs are detected. - for (GlyphText glyph : glyphs) { - if (bounds == null) { - bounds = new Rectangle2D.Float(); - bounds.setRect(glyph.getBounds()); - } else { - bounds.add(glyph.getBounds()); - } - if (textExtractionBounds == null) { - Rectangle2D.Float rect = glyph.getTextExtractionBounds(); - textExtractionBounds = new Rectangle2D.Float(rect.x, rect.y, rect.width, rect.height); - } else { - textExtractionBounds.add(glyph.getTextExtractionBounds()); - } - } - } - return bounds; - } - - public ArrayList getGlyphs() { - return glyphs; - } - - public StringBuilder getSelected() { - StringBuilder selectedText = new StringBuilder(); - for (GlyphText glyph : glyphs) { - if (glyph.isSelected()) { - selectedText.append(glyph.getUnicode()); - } - } - return selectedText; - } - - public void clearHighlighted() { - setHighlighted(false); - setHasHighlight(false); - for (GlyphText glyph : glyphs) { - glyph.setHighlighted(false); - } - } - - public void clearSelected() { - setSelected(false); - setHasSelected(false); - for (GlyphText glyph : glyphs) { - glyph.setSelected(false); - } - } - - public void selectAll() { - setSelected(true); - setHasSelected(true); - for (GlyphText glyph : glyphs) { - glyph.setSelected(true); - } - } - - public String getText() { - // iterate of sprites and get text. -// if (isWhiteSpace) { -// return text.toString().replace(" ", "_|"); -// } else if (text.toString().equals("")) -// return text.toString().replace("", "*"); -// else { - return text.toString(); -// } - } - - public int getPreviousGlyphText() { - return previousGlyphText; - } - - public String toString() { - return getText(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/CryptFilter.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/CryptFilter.java deleted file mode 100644 index 7603b34306..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/CryptFilter.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.security; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; -import java.util.Set; - -/** - * PDF 1.5 introduces crypt filters, which provide finer granularity control of - * encryption within a PDF file. The use of crypt filters involves the following - * structures: - *

        - *
      • The encryption dictionary (see Table 20) contains entries that enumerate - * the crypt filters in the document (CF) and specify which ones are used by - * default to decrypt all the streams (StmF) and strings (StrF) in the document. - * In addition, the value of the V entry shall be 4 to use crypt filters.
      • - *
      • Each crypt filter specified in the CF entry of the encryption dictionary - * shall be represented by a crypt filter dictionary, whose entries are shown - * in Table 25.
      • - *
      • A stream filter type, the Crypt filter (see 7.4.10, "Crypt Filter") - * can be specified for any stream in the document to override the default - * filter for streams. A conforming reader shall provide a standard Identity - * filter which shall pass the data unchanged (see Table 26) to allow specific - * streams, such as document metadata, to be unencrypted in an otherwise - * encrypted document. The stream's DecodeParms entry shall contain a - * Crypt filter decode parameters dictionary (see Table 14) whose Name entry - * specifies the particular crypt filter to be used (if missing, Identity is - * used). Different streams may specify different crypt filters.
      • - *
      - * Authorization to decrypt a stream shall always be obtained before the stream - * can be accessed. This typically occurs when the document is opened, as specified - * by a value of DocOpen for the AuthEvent entry in the crypt filter dictionary. - * Conforming readers and security handlers shall treat any attempt to access a - * stream for which authorization has failed as an error. AuthEvent can also be - * EFOpen, which indicates the presence of an embedded file that is encrypted - * with a crypt filter that may be different from the crypt filters used by - * default to encrypt strings and streams in the document. - */ -public class CryptFilter extends Dictionary { - - - // listing of crypt filters associated with the CF dictionary, one or more. - public HashMap cryptFilters; - - - public CryptFilter(Library library, HashMap entries) { - super(library, entries); - } - - /** - * Gets a crypt filters definition as defined in its dictionary by name. - * - * @param cryptFilterName name of crypt filter to find. - * @return crypt filter entry specified by the given name. if not found - * null is returned. - */ - public CryptFilterEntry getCryptFilterByName(Name cryptFilterName) { - // check if need to initialize the dictionary - if (cryptFilters == null) { - cryptFilters = new HashMap(1); - Set cryptKeys = entries.keySet(); - for (Object name : cryptKeys) { - cryptFilters.put((Name) name, new CryptFilterEntry(library, - (HashMap) entries.get(name))); - } - } - return cryptFilters.get(cryptFilterName); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/CryptFilterEntry.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/CryptFilterEntry.java deleted file mode 100644 index 9f2b4a81d0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/CryptFilterEntry.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.core.pobjects.security; - -import org.icepdf.core.pobjects.Dictionary; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.util.Library; - -import java.util.HashMap; - -/** - * Individual Crypt filter definition. A filter is associated with a name - * key in the CryptFilter definition. A stream or string that uses a crypt - * filter will references it by its name. - */ -public class CryptFilterEntry extends Dictionary { - - public static final Name TYPE = new Name("CryptFilter"); - public static final Name AUTHEVENT_KEY = new Name("AuthEvent"); - public static final Name CFM_KEY = new Name("CFM"); - public static final Name LENGTH_KEY = new Name("Length"); - - public CryptFilterEntry(Library library, HashMap entries) { - super(library, entries); - } - - /** - * If present, shall be CryptFilter for a crypt filter dictionary. - * - * @return dictionary type, CryptFilter - */ - public Name getType() { - return TYPE; - } - - /** - * The method used, if any, by the conforming reader to decrypt data. The - * following values shall be supported: - *
        - *
      • None - The application shall not decrypt data but shall direct the - * input stream to the security handler for decryption.
      • - *
      • V2 - The application shall ask the security handler for the - * encryption key and shall implicitly decrypt data with "Algorithm 1: - * Encryption of data using the RC4 or AES algorithms", using the RC4 algorithm.
      • - *
      • AESV2 - (PDF 1.6) The application shall ask the security handler for - * the encryption key and shall implicitly decrypt data with "Algorithm 1: - * Encryption of data using the RC4 or AES algorithms", using the AES - * algorithm in Cipher Block Chaining (CBC) mode with a 16-byte block size - * and an initialization vector that shall be randomly generated and - * placed as the first 16 bytes in the stream or string.
      • - *
      - *

      - * When the value is V2 or AESV2, the application may ask once for this - * encryption key and cache the key for subsequent use for streams that use - * the same crypt filter. Therefore, there shall be a one-to-one relationship - * between a crypt filter name and the corresponding encryption key. - *

      - * Only the values listed here shall be supported. Applications that encounter - * other values shall report that the file is encrypted with an unsupported algorithm. - *

      - * Default value: None. - * - * @return name of crypt filter method. - */ - public Name getCryptFilterMethod() { - Object tmp = library.getObject(entries, CFM_KEY); - if (tmp instanceof Name) { - return (Name) tmp; - } - return null; - } - - /** - * The event to be used to trigger the authorization that is required to - * access encryption keys used by this filter. If authorization fails, the - * event shall fail. Valid values shall be: - *

        - *
      • DocOpen: Authorization shall be required when a document is opened.
      • - *
      • EFOpen: Authorization shall be required when accessing embedded files.
      • - *
      - * Default value: DocOpen. - *

      - * If this filter is used as the value of StrF or StmF in the encryption - * dictionary (see Table 20), the conforming reader shall ignore this key - * and behave as if the value is DocOpen. - * - * @return authorization event. - */ - public Name getAuthEvent() { - Object tmp = library.getObject(entries, AUTHEVENT_KEY); - if (tmp instanceof Name) { - return (Name) tmp; - } - return null; - } - - /** - * (Optional) The bit length of the encryption key. It shall be a multiple - * of 8 in the range of 40 to 128. Security handlers may define their own - * use of the Length entry and should use it to define the bit length of - * the encryption key. Standard security handler expresses the length in - * multiples of 8 (16 means 128) and public-key security handler expresses - * it as is (128 means 128). - * - * @return lenth of encryption key - */ - public int getLength() { - int length = library.getInt(entries, LENGTH_KEY); - return Math.min(length * 8, 128); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/EncryptionDictionary.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/EncryptionDictionary.java deleted file mode 100644 index f45a8450bb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/EncryptionDictionary.java +++ /dev/null @@ -1,634 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.security; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.util.Library; - -import java.util.HashMap; -import java.util.List; - -/** - *

      The EncryptionDictionary class is used to hold values needed by the Standard - * Security Handler, Public Key Handlers and Crypt filters. This PDF object - * is found via a document's Trailer object, but only when the Trailer has an - * encrypted named reference.

      - *

      - *

      The dictionary is composed of combinations of the following entries defined - * by the different encryption types. ICEpdf currently only supports the - * Standard Security Handler.

      - *

      - *

      - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
      Common to all Encryption Dictionaries
      KeyTypeValue
      Filtername(Required) The name of the preferred security handler for this - * document; typically it is the name of the security handler that was - * used to encrypt the document. If SubFilter is not present, only this - * security handler should be used when opening the document. If it is - * present, viewer applications are free to use any security handler - * that implements the format specified by SubFilter.
      SubFiltername(Optional; PDF 1.3) A name that completely specifies the format and - * interpretation of the contents of the encryption dictionary. It is - * needed in order to allow security handlers other than the one - * specified by Filter to decrypt the document. If it is absent, other - * security handlers will not be able to decrypt the document.
      Vnumber(Optional but strongly recommended) A code specifying the algorithm - * to be used in encrypting and decrypting the document: - *
        - *
      • 0 - An algorithm that is undocumented and no longer - * supported, and whose use is strongly discouraged.
      • - *
      • 1 - Algorithm 3.1, with an encryption key length - * of 40 bits; see below.
      • - *
      • 2 - (PDF 1.4) Algorithm 3.1, but allowing - * encryption key lengths greater than 40 bits.
      • - *
      • 3 - (PDF 1.4) An unpublished algorithm allowing encryption - * key lengths ranging from 40 to 128 bits. (This algorithm - * is unpublished as an export requirement of the U.S. - * Department of Commerce.)
      • - *
      • (PDF 1.5) The security handler defines the use of encryption - * and decryption in the document, using the rules specified by - * the CF, StmF, and StrF entries.
      • - *
      - *
      Lengthinteger(Optional; PDF 1.4; only if V is 2 or 3) The length of the - * encryption key, in bits. The value must be a multiple of 8, in the - * range 40 to 128. Default value: 40.
      CFdictionary(Optional; meaningful only when the value of V is 4; PDF 1.5) A - * dictionary whose keys are crypt filter names and whose values are - * the corresponding crypt filter dictionaries.
      StmFname(Optional; meaningful only when the value of V is 4; PDF 1.5) The - * name of the crypt filter that is used by default when encrypting - * streams; it must correspond to a key in the CF dictionary or a - * standard crypt filter name. All streams in the document, except for - * cross-reference streams or those that have a crypt entry in their - * Filter array are decrypted by the security handler, using this - * crypt filter.
      StrFname(Optional; meaningful only when the value of V is 4; PDF 1.5) The - * name of the crypt filter that is used when decrypting all strings - * in the document; it must correspond to a key in the CF dictionary - * or a standard crypt filter name.
      - *

      - *

      The dictionary composes of the following values that can be returned via - * their named mehtod or by a generic getValue method if the key's name is known. - * The values of the O and U entries in this dictionary are used to determine - * whether a password entered when the document is opened is the correct owner - * password, user password, or neither.

      - *

      - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
      Standard Encryption Dictionary Entries
      KeyTypeValue
      Rnumber - *

      (Required) A number specifying which revision of the standard - * security handler should be used to interpret this dictionary. The - * revision number should be:

      - *
        - *
      • 2 if the document is encrypted with a V value less than 2 - * and does not have any of the access permissions set (via the - * P entry, below) that are designated "Revision3"
      • - *
      • 3 if the document is encrypted with a V value of 2 or 3, or - * has any "Revision 3" access permissions set.
      • - *
      • 4 if the document is encrypted with a V value of 4.
      • - *
      - *
      OString(Required) A 32-byte string, based on both the owner and user - * passwords, that is used in computing the encryption key and in - * determining whether a valid owner password was entered.
      UStringU string (Required) A 32-byte string, based on the user password, - * that is used in determining whether to prompt the user for a - * password and, if so, whether a valid user or owner password was - * entered.
      PInteger(Required) A set of flags specifying which operations are permitted - * when the document is opened with user access. - *
      - *

      - *

      Encryption dictionaries for public-key security handlers contain the - * common entries shown above. In addition, they may contain the entries - * shown below.

      - *

      - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
      Additional public-key Dictionary Entries
      KeyTypeValue
      Recipientsarray(Required when SubFilter is adbe.pkcs7.s3 or adbe.pkcs7.s4; PDF 1.3) - * An array of strings, where each string is a PKCS#7 object listing - * recipients that have been granted equal access rights to the document. - * The data contained in the PKCS#7 object includes both a cryptographic - * key that is used to decrypt the encrypted data and the access - * permissions that apply to the recipient list. There should be only - * one object per unique set of access permissions; if a recipient - * appears in more than one list, the permissions used will be those - * found in the first matching list.
      - * Note:
      - * When SubFilter is adbe.pkcs7.s5, recipient lists are specified in - * the crypt filter dictionary.
      - *

      - *

      Encryption dictionaries for crypt filter security handlers contain the - * common entries shown above. In addition, they may contain the entries - * shown below

      - *

      - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
      Standard Encryption Dictionary Entries
      KeyTypeValue
      Typename(Optional) If present, must be CryptFilter for a crypt filter - * dictionary.
      CFMname(Optional) The method used, if any, by the viewer application to - * decrypt data. In PDF 1.5, the following values are supported: - *
        - *
      • None: (default)the viewer application does not decrypt data, - * but directs the input stream to the security handler for - * decryption.
      • - *
      • V2: the viewer application asks the security handler for the - * decryption key and implicitly decrypts data using Algorithm - * 3.1. A viewer application may ask once for this decryption - * key, then cache the key for subsequent use for streams that - * use the same crypt filter; therefore, there must be a one-to-one - * relationship between a crypt filter name and the corresponding - * decryption key.
      • - *
      - *
      Lengthinteger(Optional) When the value of CFM is V2, this entry is used to - * indicate the bit length of the decryption key. It must be a multiple - * of 8 in the range of 40 to 128. Default value: 128. When the value - * of CFM is None, security handlers can define their own use of this - * entry, but are encouraged to follow the usage conventions defined - * for V2.
      AuthEventname - * (Optional) The event to be used to trigger the authorization that is - * required to access decryption keys used by this filter. If - * authorization fails, the event should fail. Acceptable values are: - *
        - *
      • DocOpen: (default) authorization is required when a document - * is opened.
      • - *
      • EFOpen: authorization is required when about to access embedded - * files.
      • - *
      - * If this filter is used as the value of StrF or StmF in the encryption - * dictionary, the viewer application should ignore this key and behave - * as if the value is DocOpen. - *
      - * - * @since 1.1 - */ -public class EncryptionDictionary extends Dictionary { - - public static final Name FILTER_KEY = new Name("Filter"); - public static final Name SUB_FILTER_KEY = new Name("SubFilter"); - public static final Name V_KEY = new Name("V"); - public static final Name LENGTH_KEY = new Name("Length"); - public static final Name R_KEY = new Name("R"); - public static final Name O_KEY = new Name("O"); - public static final Name U_KEY = new Name("U"); - public static final Name P_KEY = new Name("P"); - public static final Name CF_KEY = new Name("CF"); - public static final Name STMF_KEY = new Name("StmF"); - public static final Name STRF_KEY = new Name("StrF"); - public static final Name EEF_KEY = new Name("EEF"); - public static final Name OE_KEY = new Name("OE"); - public static final Name UE_KEY = new Name("UE"); - public static final Name PERMS_KEY = new Name("Perms"); - public static final Name ENCRYPT_METADATA_KEY = new Name("EncryptMetadata"); - - // File ID, generated when document is created, first index used by - // encryption algorithms - private List fileID = null; - - private CryptFilter cryptFilter; - - // Revision 5 authentication holders as they are passwords - // are validate when the key is calculated. - private boolean isAuthenticatedUserPassword; - private boolean isAuthenticatedOwnerPassword; - - /** - * Creates a new Encryption Dictionary object. - * - * @param lib library dictionary of all objects in document. - * @param encryptionDictionary dictionary of all values taken from encrypt key - * in the documents Trailer reference. - * @param fileID Vector containing the two file ID values originally - * parsed from the Trailer reference. - */ - public EncryptionDictionary(Library lib, HashMap encryptionDictionary, List fileID) { - super(lib, encryptionDictionary); - this.entries = encryptionDictionary; - this.fileID = fileID; - } - - /** - * Gets the document's File ID. - * - * @return vector containing two values that represent the file ID - */ - public List getFileID() { - return fileID; - } - -/** - * Entries common to all encryption dictionaries - */ - - /** - * Gets the preferred security handler name. - * - * @return handler name. - */ - public Name getPreferredSecurityHandlerName() { - return library.getName(entries, FILTER_KEY); - } - - /** - * Gets the preferred security handler sub-name. - * - * @return handler sub-name. - */ - public Name getPreferredSecurityHandlerSubName() { - return library.getName(entries, SUB_FILTER_KEY); - } - - /** - * Gets a code specifying the algorithm to be used in encrypting and - * decrypting the document: - *

        - *
      • 0 An algorithm that is undocumented. This value shall not be used.
      • - *
      • 1 "Algorithm 1: Encryption of data using the RC4 or AES algorithms" - * in 7.6.2, "General Encryption Algorithm," with an encryption key length - * of 40 bits; see below.
      • - *
      • 2 (PDF 1.4) "Algorithm 1: Encryption of data using the RC4 or AES - * algorithms"in 7.6.2, "General Encryption Algorithm," but permitting - * encryption key lengths greater than 40 bits.
      • - *
      • 3(PDF 1.4) An unpublished algorithm that permits encryption key - * lengths ranging from 40 to 128 bits. This value shall not appear in a - * conforming PDF file.
      • - *
      • 4(PDF 1.5) The security handler defines the use of encryption and - * decryption in the document, using the rules specified by the CF, StmF, - * and StrF entries. The default value if this entry is omitted shall be - * 0, but when present should be a value of 1 or greater.
      • - *
      - * - * @return encryption version. - */ - public int getVersion() { - return library.getInt(entries, V_KEY); - } - - /** - * Gets the length of the encryption key, in bits. - * - * @return length of encryption key. - */ - public int getKeyLength() { - int length = 40; - int len = library.getInt(entries, LENGTH_KEY); - if (len != 0) { - length = len; - } - return length; - } - -/** - * Entries added for standard encryption dictionaries - */ - - /** - * Gets the revision number of the standard security handler. - * - * @return revision number. - */ - public int getRevisionNumber() { - return library.getInt(entries, R_KEY); - } - - /** - * Gets the 32-byte string used for verifying the owner password. - * - * @return 32-byte string representing the key O. - */ - public String getBigO() { - Object tmp = library.getObject(entries, O_KEY); - return getLiteralString(tmp); - } - - /** - * Gets the 32-byte string used for verifying the user password. - * - * @return 32-byte string representing the key U. - */ - public String getBigU() { - Object tmp = library.getObject(entries, U_KEY); - return getLiteralString(tmp); - } - - /** - * Gets the integer flag which specifies the operation permitted when the - * document is opened with user access. - * - * @return return flag specifying user access. - */ - public int getPermissions() { - return library.getInt(entries, P_KEY); - } - - - /** - * (Optional; meaningful only when the value of V is 4; PDF 1.5) - * A dictionary whose keys shall be crypt filter names and whose values - * shall be the corresponding crypt filter dictionaries (see Table 25). - * Every crypt filter used in the document shall have an entry in this - * dictionary, except for the standard crypt filter names (see Table 26). - *

      - * The conforming reader shall ignore entries in CF dictionary with the keys - * equal to those listed in Table 26 and use properties of the respective - * standard crypt filters. - * - * @return crypt filter object if found, null otherwise. - */ - public CryptFilter getCryptFilter() { - if (cryptFilter == null) { - HashMap tmp = (HashMap) library.getObject(entries, CF_KEY); - if (tmp != null) { - cryptFilter = new CryptFilter(library, tmp); - return cryptFilter; - } - } - return cryptFilter; - } - - /** - * (Optional; meaningful only when the value of V is 4; PDF 1.5) - * The name of the crypt filter that shall be used by default when decrypting - * streams. The name shall be a key in the CF dictionary or a standard crypt - * filter name specified in Table 26. All streams in the document, except - * for cross-reference streams (see 7.5.8, "Cross-Reference Streams") or - * streams that have a Crypt entry in their Filterarray (see Table 6), - * shall be decrypted by the security handler, using this crypt filter. - *

      - * Default value: Identity. - *

      - * - * @return name of the default stream filter name. - */ - public Name getStmF() { - Object tmp = library.getObject(entries, STMF_KEY); - if (tmp != null && tmp instanceof Name) { - return (Name) tmp; - } - return null; - } - - - /** - * (Optional; meaningful only when the value of V is 4; PDF 1.5) - * The name of the crypt filter that shall be used when decrypting all - * strings in the document. The name shall be a key in the CF dictionary or - * a standard crypt filter name specified in Table 26. - *

      - * Default value: Identity. - * - * @return name of the default string filter name. - */ - public Name getStrF() { - Object tmp = library.getObject(entries, STRF_KEY); - if (tmp != null && tmp instanceof Name) { - return (Name) tmp; - } - return null; - } - - /** - * (Optional; meaningful only when the value of V is 4; PDF 1.6) The name - * of the crypt filter that shall be used when encrypting embedded file - * streams that do not have their own crypt filter specifier; it shall - * correspond to a key in the CFdictionary or a standard crypt filter name - * specified in Table 26. - *

      - * This entry shall be provided by the security handler. Conforming writers - * shall respect this value when encrypting embedded files, except for - * embedded file streams that have their own crypt filter specifier. If - * this entry is not present, and the embedded file stream does not contain - * a crypt filter specifier, the stream shall be encrypted using the default - * stream crypt filter specified by StmF. - *

      - * EFF:name - */ - public Name getEEF() { - Object tmp = library.getObject(entries, EEF_KEY); - if (tmp != null && tmp instanceof Name) { - return (Name) tmp; - } - return null; - } - - - /** - * Gets the 32-byte string, based on the owner and user passwords, that is - * used in the computing the encryption key. - * - * @return 32-byte string representing the key OE. - */ - public String getBigOE() { - Object tmp = library.getObject(entries, OE_KEY); - return getLiteralString(tmp); - } - - /** - * Gets the 32-byte string, based on the user password, that is - * used in the computing the encryption key. - * - * @return 32-byte string representing the key UE. - */ - public String getBigUE() { - Object tmp = library.getObject(entries, UE_KEY); - return getLiteralString(tmp); - } - - /** - * A16-byte string, encrypted with the file encryption key, that contains an - * encrypted copy of the permission flags. - * - * @return 16-byte string representing the key Perms. - */ - public String getPerms() { - Object tmp = library.getObject(entries, PERMS_KEY); - return getLiteralString(tmp); - } - - public String getLiteralString(Object value){ - if (value instanceof LiteralStringObject) { - return ((StringObject) value).getLiteralString(); - } else if (value instanceof HexStringObject) { - return ((HexStringObject) value).getRawHexToString().toString(); - } else { - return null; - } - } - - /** - * Indicates whether the document-level metadata stream (see Section 10.2.2, - * "Metadata Streams") is to be encrypted. Applications should respect - * this value. - * - * @return true if document-level metadata is encrypted - */ - public boolean isEncryptMetaData() { - if (entries.containsKey(ENCRYPT_METADATA_KEY)) { - return library.getBoolean(entries, ENCRYPT_METADATA_KEY); - }else{ - // default value if not specified. - return true; - } - } - - protected boolean isAuthenticatedUserPassword() { - return isAuthenticatedUserPassword; - } - - protected void setAuthenticatedUserPassword(boolean authenticatedUserPassword) { - isAuthenticatedUserPassword = authenticatedUserPassword; - } - - protected boolean isAuthenticatedOwnerPassword() { - return isAuthenticatedOwnerPassword; - } - - protected void setAuthenticatedOwnerPassword(boolean authenticatedOwnerPassword) { - isAuthenticatedOwnerPassword = authenticatedOwnerPassword; - } - - /** - * Class utility methods - */ - - /** - * Gets any dictionary key specified by the key parameter. - * - * @param key named key to retrieve from dictionary. - * @return return keys value if found; null, otherwise. - */ - public Object getValue(Object key) { - return entries.get(key); - } - - public String toString() { - return "Encryption Dictionary: \n" + - " fileID: " + getFileID() + " \n" + - " Filter: " + getPreferredSecurityHandlerName() + " \n" + - " SubFilter: " + getPreferredSecurityHandlerSubName() + " \n" + - " V: " + getVersion() + " \n" + - " P: " + getPermissions() + " \n" + - " Length:" + getKeyLength() + " \n" + - " CF: " + cryptFilter + " \n" + - " StmF: " + getStmF() + " \n" + - " StrF: " + getStrF() + " \n" + - " R: " + getRevisionNumber() + " \n" + - " O: " + getBigO() + " \n" + - " U: " + getBigU() + " \n" + - " UE: " + getBigUE() + " \n" + - " OE: " + getBigOE() + " \n" + - " Recipients: " + "not done yet" + " \n" + - " "; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/Permissions.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/Permissions.java deleted file mode 100644 index 2aa7ef2d8c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/Permissions.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.security; - -/** - *

      Standard encryption has permissions associated with it which is defined - * by a key in the encryption dictionary. It is up to the viewer application - * to respect these permissions.

      - *

      - *

      The value of the P key is an unsigned 32-bit integer containing a set of - * flags specifying which access permissions should be granted when the document - * is opened with user access. The below list shows the meanings of these flags. - * Bit positions within the flag word are numbered from 1 (low-order) to 32 - * (high-order); a 1 bit in any position enables the corresponding access - * permission. Which bits are meaningful, and in some cases how they are - * interpreted, depends on the security handler's revision number (specified in - * the encryption dictionary's R entry).

      - *

      - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
      Bits Meaning
      1-2Reserved; must be 0.
      3 (Revision 2) Print the document.
      - * (Revision 3) Print the document (possibly not at the highest - * quality (possibly not at the highest quality level, depending on - * whether bit 12 is also set). - *
      4Modify the contents of the document by operations other than those - * controlled by bits 6, 9, and 11.
      5(Revision 2) Copy or otherwise extract text and graphics from the - * document, including extracting text and graphics (in support of - * accessibility to disabled users or for other purposes). (Revision 3) - * Copy or otherwise extract text and graphics from the document by - * operations other than that controlled by bit 10.
      6Add or modify text annotations, fill in interactive form fields, - * and, if bit 4 is also set, create or modify interactive form fields - * (including signature fields).
      7-8Reserved; must be 1.
      9(Revision 3 only) Fill in existing interactive form fields - * (including signature fields), even if bit 6 is clear.
      10(Revision 3 only) Extract text and graphics (in support of - * accessibility to disabled users or for other purposes).
      11(Revision 3 only) Assemble the document (insert, rotate, or delete - * pages and create bookmarks or thumbnail images), even if bit 4 is - * clear.
      12(Revision 3 only) Print the document to a representation from which - * a faithful digital copy of the PDF content could be generated. When - * this bit is clear (and bit 3 is set), printing is limited to a - * lowlevel representation of the appearance, possibly of degraded - * quality.
      13-32(Revision 3 only) Reserved; must be 1.
      - *
      - * Note:
      - * PDF integer objects in fact are represented internally in signed - * twos complement form. Since all the reserved high-order flag bits in the - * encryption dictionary's P value are required to be 1, the value must be - * specified as a negative integer. For example, assuming revision 2 of the - * security handler, the value -44 allows printing and copying but disallows - * modifying the contents and annotations. - * - * @since 1.1 - */ -public class Permissions { - - // constants for parsing bits from P value - // bit 3, 11111111111111111111000011000100 - private static final int PRINT_DOCUMENT_BIT_3 = 0xFFFFF0C4; - // bit 4, 11111111111111111111000011001000 - private static final int MODIFY_DOCUMENT_BIT_4 = 0xFFFFF0C8; - // bit 5, 11111111111111111111000011010000 - private static final int DATA_EXTRACTION_BIT_5 = 0xFFFFF0D0; - // bit 6, 11111111111111111111000011100000 - private static final int MODIFY_TEXT_BIT_6 = 0xFFFFF0E0; - // bit 9, 11111111111111111111000111000000 - private static final int MODIFY_FORMS_BIT_9 = 0xFFFFF1C0; - // bit 10, 11111111111111111111001011000000 - private static final int ACCESSIBILITY_BIT_10 = 0xFFFFF2C0; - // bit 11, 11111111111111111111010011000000 - private static final int ASSEMBLE_DOCUMENT_BIT_11 = 0xFFFFF4C0; - // bit 12 11111111111111111111100011000000 - private static final int PRINT_QUALITY_BIT_12 = 0xFFFFF8C0; - - // Constants for retrieving permission values - - /** - * Determine if printing of document is allowed. - */ - public static final int PRINT_DOCUMENT = 0; - /** - * Determine the quality of printed allowed. - */ - public static final int PRINT_DOCUMENT_QUALITY = 1; - /** - * Determine if changing the document is allowed. - */ - public static final int MODIFY_DOCUMENT = 2; - /** - * Determine if content copying or extraction is allowed. - */ - public static final int CONTENT_EXTRACTION = 3; - /** - * Determine if authoring comments and form fields is allowed. - */ - public static final int AUTHORING_FORM_FIELDS = 4; - /** - * Determine if form field fill-in or signing is allowed. - */ - public static final int FORM_FIELD_FILL_SIGNING = 5; - /** - * Determine if content accessibility is allowed. - */ - public static final int CONTENT_ACCESSABILITY = 6; - /** - * Determine if document assembly is allowed. - */ - public static final int DOCUMENT_ASSEMBLY = 7; - - - // Permission values, indexes are mapped to constant values - private boolean[] permissions = new boolean[10]; - // original permission integer from encrypt dictionary - // not permission bits and revered bits. 11111111111111111111000011000000 - private int permissionFlags = 0xFFFFF0C0; - // Revision of standard encryption algorithms - private int revision = 2; - - // Initiated flag - boolean isInit = false; - - /** - * Creates a new object which can determine a document's user permissions. - * - * @param dictionary Encryption dictionary which contains a P key. - */ - public Permissions(EncryptionDictionary dictionary) { - this.permissionFlags = dictionary.getPermissions(); - revision = dictionary.getRevisionNumber(); - } - - /** - * Initiate the permission object. Extracts Permission bit values from - * P key. - */ - public void init() { - - for (int i = 0; i < permissions.length; i++) { - permissions[i] = false; - } - - // Create permissions based on Revision 2 rules - if (revision == 2) { - // print document rules - if ((permissionFlags & PRINT_DOCUMENT_BIT_3) - == PRINT_DOCUMENT_BIT_3) { - permissions[PRINT_DOCUMENT] = true; - } - // modify document - if ((permissionFlags & MODIFY_DOCUMENT_BIT_4) - == MODIFY_DOCUMENT_BIT_4) { - permissions[MODIFY_DOCUMENT] = true; - } - // copy or extract text and graphics - if ((permissionFlags & DATA_EXTRACTION_BIT_5) - == DATA_EXTRACTION_BIT_5) { - permissions[CONTENT_EXTRACTION] = true; - } - // authoring forms, not in 2, but use CONTENT_EXTRACTION permission - if (permissions[CONTENT_EXTRACTION]) { - permissions[AUTHORING_FORM_FIELDS] = true; - } - // Fill in existing interactive form fields, not in 2, but use - // CONTENT_EXTRACTION permission - if (permissions[CONTENT_EXTRACTION]) { - permissions[FORM_FIELD_FILL_SIGNING] = true; - } - // document accessibility, not in 2, but use CONTENT_EXTRACTION - // permission - if (permissions[CONTENT_EXTRACTION]) { - permissions[CONTENT_ACCESSABILITY] = true; - } - // allow assembly of document, not in 2, but use MODIFY_DOCUMENT - // permission - if (permissions[MODIFY_DOCUMENT]) { - permissions[DOCUMENT_ASSEMBLY] = true; - } - // Print document quality, if true, print low quality version - if ((permissionFlags & PRINT_QUALITY_BIT_12) - == PRINT_QUALITY_BIT_12) { - permissions[PRINT_DOCUMENT_QUALITY] = true; - } - - isInit = true; - - } - // Revision 3 rules - else if (revision >= 3) { - // print document rules - if ((permissionFlags & PRINT_DOCUMENT_BIT_3) - == PRINT_DOCUMENT_BIT_3) { - permissions[PRINT_DOCUMENT] = true; - } - // modify document - if ((permissionFlags & MODIFY_DOCUMENT_BIT_4) - == MODIFY_DOCUMENT_BIT_4) { - permissions[MODIFY_DOCUMENT] = true; - } - // copy or extract text and graphics - if ((permissionFlags & DATA_EXTRACTION_BIT_5) - == DATA_EXTRACTION_BIT_5) { - permissions[CONTENT_EXTRACTION] = true; - } - // authoring forms - if ((permissionFlags & MODIFY_TEXT_BIT_6) - == MODIFY_TEXT_BIT_6) { - permissions[AUTHORING_FORM_FIELDS] = true; - } - // Fill in existing interactive form fields - if ((permissionFlags & MODIFY_FORMS_BIT_9) - == MODIFY_FORMS_BIT_9) { - permissions[FORM_FIELD_FILL_SIGNING] = true; - } - // document accessibility - if ((permissionFlags & ACCESSIBILITY_BIT_10) - == ACCESSIBILITY_BIT_10) { - permissions[CONTENT_ACCESSABILITY] = true; - } - // allow assembly of document - if ((permissionFlags & ASSEMBLE_DOCUMENT_BIT_11) - == ASSEMBLE_DOCUMENT_BIT_11) { - permissions[DOCUMENT_ASSEMBLY] = true; - } - // Print document quality, if true, print low quality version - if ((permissionFlags & PRINT_QUALITY_BIT_12) - == PRINT_QUALITY_BIT_12) { - permissions[PRINT_DOCUMENT_QUALITY] = true; - } - isInit = true; - } - - } - - /** - * Gets the permission value of the specified Permission constant. - * - * @param permissionIndex one of the classes constants for determining a - * specific user permission. - * @return boolean value of the permission being called. - */ - public boolean getPermissions(final int permissionIndex) { - if (!isInit) { - init(); - } - // return false if the permission index is out of bounds. - return !(permissionIndex < 0 || permissionIndex > permissions.length) - && permissions[permissionIndex]; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/PublicSecurityHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/PublicSecurityHandler.java deleted file mode 100644 index 3f139b3e0b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/PublicSecurityHandler.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.security; - -/** - * Creates a new Public-key Security Handler. - * Note: This class is not implemented. - */ -public class PublicSecurityHandler { -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/SecurityHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/SecurityHandler.java deleted file mode 100644 index 677afb0e53..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/SecurityHandler.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.security; - -import org.icepdf.core.pobjects.Reference; - -import java.io.InputStream; -import java.util.HashMap; - -/** - * Defines common behaviors for Security Handlers. - * - * @since 1.1 - */ -public abstract class SecurityHandler implements SecurityHandlerInterface { - - protected String handlerName = null; - - protected EncryptionDictionary encryptionDictionary = null; - - protected Permissions permissions = null; - - public SecurityHandler(EncryptionDictionary encryptionDictionary) { - this.encryptionDictionary = encryptionDictionary; - } - - public abstract boolean isAuthorized(String password); - - public abstract boolean isUserAuthorized(String password); - - public abstract boolean isOwnerAuthorized(String password); - - public abstract byte[] encrypt(Reference objectReference, - byte[] encryptionKey, - byte[] data); - - public abstract byte[] decrypt(Reference objectReference, - byte[] encryptionKey, - byte[] data); - - public abstract InputStream encryptInputStream( - Reference objectReference, - byte[] encryptionKey, - HashMap decodeParams, - InputStream input); - - public abstract InputStream decryptInputStream( - Reference objectReference, - byte[] encryptionKey, - HashMap decodeParams, - InputStream input); - - public abstract byte[] getEncryptionKey(); - - public abstract byte[] getDecryptionKey(); - - public abstract String getHandlerName(); - - public abstract Permissions getPermissions(); - - public abstract void init(); - - public abstract void dispose(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/SecurityHandlerInterface.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/SecurityHandlerInterface.java deleted file mode 100644 index 743e944d03..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/SecurityHandlerInterface.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.security; - -import org.icepdf.core.pobjects.Reference; - -import java.io.InputStream; -import java.util.HashMap; - -/** - * The interface for objects which defines a Security Handler for a PDF - * document. A custom Security Handlers should implement this interface. - * - * @since 1.1 - */ -public interface SecurityHandlerInterface { - - /** - * Determines whether the supplied password is authorized to view the - * PDF document. If a password is rejected, the user should be restricted - * from viewing the document. - * - * @param password password to authorize - * @return true, if the password was authorized successfully; false, otherwise. - */ - public boolean isAuthorized(String password); - - /** - * Determines whether the supplied user password is authorized to view the - * PDF document. If a password is rejected, the user should be restricted - * from viewing the document. - * - * @param password password to authorize - * @return true, if the password was authorized successfully; false, otherwise. - */ - public boolean isUserAuthorized(String password); - - /** - * Determines whether the supplied owner password is authorized to view the - * PDF document. If a password is rejected, the user should be restricted - * from viewing the document. - * - * @param password password to authorize - * @return true, if the password was authorized successfully; false, otherwise. - */ - public boolean isOwnerAuthorized(String password); - - /** - * Encrypt the PDF data bytestream or string. - * - * @param objectReference reference to PDF object being encrypted; this object - * contains the PDF object number and revision. - * @param encryptionKey encryption key used by encryption algorithm. - * @param data byte data to be encrypted; either represents an object stream - * or string value. - * @return the encrypted stream or string byte data - */ - public byte[] encrypt(Reference objectReference, - byte[] encryptionKey, - byte[] data); - - /** - * Decrypt the PDF data bytestream or string. - * - * @param objectReference reference to PDF object being encrypted; this object - * contains the PDF object number and revision. - * @param encryptionKey encryption key used by decryption algorithm. - * @param data byte data to be decrypted; either represents an object stream - * or string value. - * @return the decrypted stream or string byte data - */ - public byte[] decrypt(Reference objectReference, - byte[] encryptionKey, - byte[] data); - - /** - * Encrypt the PDF data byteStream. - * - * @param objectReference reference to PDF object being encrypted; this object - * contains the PDF object number and revision. - * @param encryptionKey encryption key used by decryption algorithm. - * @param input inputStream data to be decrypted; either represents an object stream - * or string value. - * @return the ecrypted stream or string byte data - */ - InputStream encryptInputStream( - Reference objectReference, - byte[] encryptionKey, - HashMap decodeParams, - InputStream input); - - /** - * Decrypt the PDF data byteStream. - * - * @param objectReference reference to PDF object being encrypted; this object - * contains the PDF object number and revision. - * @param encryptionKey encryption key used by decryption algorithm. - * @param input inputStream data to be decrypted; either represents an object stream - * or string value. - * @return the decrypted stream or string byte data - */ - InputStream decryptInputStream( - Reference objectReference, - byte[] encryptionKey, - HashMap decodeParams, - InputStream input); - - /** - * Gets the encryption key used by the security handler for encrypting data. - * - * @return byte data representing encryption key - */ - public byte[] getEncryptionKey(); - - /** - * Gets the encryption key used by the security handler for decryption data. - * - * @return byte data representing encryption key - */ - public byte[] getDecryptionKey(); - - /** - * Gets the name of the default security handler. - * - * @return string representing security handler name - */ - public String getHandlerName(); - - /** - * Gets the PDF permissions object associated with this document's - * security handler. - * - * @return security handlers permissions object - */ - public Permissions getPermissions(); - - /** - * Initiate the security handler - */ - public void init(); - - /** - * Dispose of the security handler. - */ - public void dispose(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/SecurityManager.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/SecurityManager.java deleted file mode 100644 index 3dbc1ed679..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/SecurityManager.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.security; - -import org.icepdf.core.exceptions.PDFSecurityException; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; - -import java.io.InputStream; -import java.security.Provider; -import java.security.Security; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      The Security Manager class manages the encryption of encrypted - * PDF documents. The class is initiated by the Document class if a - * Crypt key is found in the document's trailer. The singleton pattern - * is implemented so that it can be called from anywhere with the PDF - * object structure.

      - *

      - *

      There is currently only support for Adobe Standard encryption which is - * supported by the StandardSecurityHandler. Additional support for custom - * security handlers, public-key handlers and crypt filters is currently under - * development.

      - *

      - *

      The Security Manager needs tobe compliant with Sun Java JCE 1.2.1 implementation. - * The security manager assumes that - * org.bouncycastle.jce.provider.BouncyCastleProvider can be found on the class - * path and will try to load the class accordingly. However, if you have another - * crypto API that you would like to use, the system property - * org.icepdf.core.pobjects.security.provider can be set to the provider's class path.

      - * - * @since 1.1 - */ -public class SecurityManager { - - private static final Logger logger = - Logger.getLogger(SecurityManager.class.toString()); - - // Default Encryption dictionary, which also contians keys need for - // standard, crypt and public security handlers. - private EncryptionDictionary encryptDictionary = null; - - // Pointer to class which implements the SecurityHandler interface - private SecurityHandler securityHandler = null; - - // flag for detecting JCE - private static boolean foundJCE = false; - - // key caches, fairly expensive calculation - private byte[] encryptionKey; - private byte[] decryptionKey; - - // Add security provider of choice before Sun RSA provider (if any) - static { - // Load security handler from system property if possible - String defaultSecurityProvider = - "org.bouncycastle.jce.provider.BouncyCastleProvider"; - - // check system property security provider - String customSecurityProvider = - Defs.sysProperty("org.icepdf.core.security.jceProvider"); - - // if no custom security provider load default security provider - if (customSecurityProvider != null) { - defaultSecurityProvider = customSecurityProvider; - } - try { - // try and create a new provider - Object provider = Class.forName(defaultSecurityProvider).newInstance(); - Security.insertProviderAt((Provider) provider, 2); - } catch (ClassNotFoundException e) { - logger.log(Level.FINE, "Optional BouncyCastle security provider not found"); - } catch (InstantiationException e) { - logger.log(Level.FINE, "Optional BouncyCastle security provider could not be instantiated"); - } catch (IllegalAccessException e) { - logger.log(Level.FINE, "Optional BouncyCastle security provider could not be created"); - } - - try { - Class.forName("javax.crypto.Cipher"); - foundJCE = true; - } catch (ClassNotFoundException e) { - logger.log(Level.SEVERE, "Sun JCE Support Not Found"); - } - } - - /** - * Disposes of the security handler instance. - */ - public void dispose() { - - } - - /** - * Creates new instance of SecurityManager object. - * - * @param library library of documents PDF objects - * @param encryptionDictionary encryption dictionary key values - * @param fileID fileID of PDF document - * @throws PDFSecurityException if the security provider could not be found - */ - public SecurityManager(Library library, HashMap encryptionDictionary, - List fileID) - throws PDFSecurityException { - - // Check to make sure that if run under JDK 1.3 that the JCE libraries - // are installed as extra packages - if (!foundJCE) { - logger.log(Level.SEVERE, "Sun JCE support was not found on classpath"); - throw new PDFSecurityException("Sun JCE Support Not Found"); - } - - // create dictionary for document - encryptDictionary = - new EncryptionDictionary(library, encryptionDictionary, fileID); - - // create security Handler based on dictionary entries. - if (encryptDictionary.getPreferredSecurityHandlerName().getName(). - equalsIgnoreCase("Standard")) { - securityHandler = new StandardSecurityHandler(encryptDictionary); - // initiate the handler - securityHandler.init(); - } else { - throw new PDFSecurityException("Security Provider Not Found."); - } - } - - /** - * Gets the permission associated with the document's encryption handler. - * - * @return permission object - */ - public Permissions getPermissions() { - return securityHandler.getPermissions(); - } - - /** - * Gets the SecurityHandler associated with this Security Manager. - * - * @return security handler object. - */ - public SecurityHandler getSecurityHandler() { - return securityHandler; - } - - /** - * Gets the encryption dictionary associated with the document encryption - * handler. - * - * @return encryption dictionary - */ - public EncryptionDictionary getEncryptionDictionary() { - return encryptDictionary; - } - - /** - * Gets the encryption key used by the security handler when encrypting data. - * - * @return encryption key used to encrypt the data - */ - public byte[] getEncryptionKey() { - if (encryptionKey == null) { - encryptionKey = securityHandler.getEncryptionKey(); - } - return encryptionKey; - } - - /** - * Gets the decrypt key used by the security handler when decrypting data. - * - * @return decryption key used to encrypt the data - */ - public byte[] getDecryptionKey() { - if (decryptionKey == null) { - decryptionKey = securityHandler.getDecryptionKey(); - } - return decryptionKey; - } - - /** - * Encrypt the data using the encryptionKey and - * objectReference of the PDF stream or String object. - * - * @param objectReference PDF objects number and revision number - * @param encryptionKey encryption key used to encrypt the data - * @param data byte data of a PDF Stream or String object - * @return encrypted data - */ - public byte[] encrypt(Reference objectReference, - byte[] encryptionKey, - byte[] data) { - - return securityHandler.encrypt(objectReference, encryptionKey, data); - } - - /** - * Decrypt the data using the encryptionKey and - * objectReference of the PDF stream or String object. - * - * @param objectReference PDF objects number and revision number - * @param encryptionKey encryption key used to decrypt the data - * @param data byte data of a PDF Stream or String object - * @return decrypted data - */ - public byte[] decrypt(Reference objectReference, - byte[] encryptionKey, - byte[] data) { - - return securityHandler.decrypt(objectReference, encryptionKey, data); - } - - /** - * Return a new InputStream, from which read operations will return - * data, read and decrypt from the InputStream parameter - * objectReference of the PDF stream or String object. - * - * @param objectReference PDF objects number and revision number - * @param encryptionKey encryption key used to decrypt the data - * @param input InputStream giving access to encrypted data - * @param decodeParams crypt filter optional parameters, can be null. - * @param returnInputIfNullResult If results end up being null, then return input instead of null - * @return InputStream giving access to decrypted data - */ - public InputStream decryptInputStream( - Reference objectReference, - byte[] encryptionKey, - HashMap decodeParams, - InputStream input, - boolean returnInputIfNullResult) { - InputStream result = securityHandler.decryptInputStream( - objectReference, encryptionKey, decodeParams, input); - if (returnInputIfNullResult && result == null) - result = input; - return result; - } - - /** - * Return a new InputStream, from which read operations will return - * data, read and decrypt from the InputStream parameter - * objectReference of the PDF stream or String object. - * - * @param objectReference PDF objects number and revision number - * @param encryptionKey encryption key used to decrypt the data - * @param input InputStream giving access to encrypted data - * @param decodeParams crypt filter optional parameters, can be null. - * @param returnInputIfNullResult If results end up being null, then return input instead of null - * @return InputStream giving access to decrypted data - */ - public InputStream encryptInputStream( - Reference objectReference, - byte[] encryptionKey, - HashMap decodeParams, - InputStream input, - boolean returnInputIfNullResult) { - InputStream result = securityHandler.encryptInputStream( - objectReference, encryptionKey, decodeParams, input); - if (returnInputIfNullResult && result == null) - result = input; - return result; - } - - /** - * Determines whether the supplied password is authorized to view the - * PDF document. If a password is rejected, the user should be restricted - * from viewing the document. - * - * @param password password to authorize - * @return true, if the password was authorized successfully; false, otherwise. - */ - public boolean isAuthorized(String password) { - return securityHandler.isAuthorized(password); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/StandardEncryption.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/StandardEncryption.java deleted file mode 100644 index 494d27eb5e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/StandardEncryption.java +++ /dev/null @@ -1,1228 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.security; - -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.util.Utils; - -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * PDF's standard security handler allows access permissions and up to two passwords - * to be specified for a document. The purpose of this class is to encapsulate - * the algorithms used by the Standard Security Handler. - *

      - * All of the algorithms used for encryption related calculations are based - * on the suto code described in the Adobe PDF Specification 1.5. - * - * @since 1.1 - */ -class StandardEncryption { - - private static final Logger logger = - Logger.getLogger(StandardEncryption.class.toString()); - - /** - * The application shall not decrypt data but shall direct the input stream - * to the security handler for decryption (NO SUPPORT) - */ - public static final String ENCRYPTION_TYPE_NONE = "None"; - /** - * The application shall ask the security handler for the encryption key and - * shall implicitly decrypt data with "Algorithm 1: Encryption of data using - * the RC4 or AES algorithms", using the RC4 algorithm. - */ - public static final String ENCRYPTION_TYPE_V2 = "V2"; - public static final String ENCRYPTION_TYPE_V3 = "V3"; - /** - * (PDF 1.6) The application shall ask the security handler for the - * encryption key and shall implicitly decrypt data with "Algorithm 1: - * Encryption of data using the RC4 or AES algorithms", using the AES - * algorithm in Cipher Block Chaining (CBC) mode with a 16-byte block size - * and an initialization vector that shall be randomly generated and placed - * as the first 16 bytes in the stream or string. - */ - public static final String ENCRYPTION_TYPE_AES_V2 = "AESV2"; - - /** - * Padding String used in PDF encryption related algorithms - * < 28 BF 4E 5E 4E 75 8A 41 64 00 4E 56 FF FA 01 08 - * 2E 2E 00 B6 D0 68 3E 80 2F 0C A9 FE 64 53 69 7A > - */ - private static final byte[] PADDING = { - (byte) 0x28, (byte) 0xBF, (byte) 0x4E, - (byte) 0x5E, (byte) 0x4E, (byte) 0x75, - (byte) 0x8A, (byte) 0x41, (byte) 0x64, - (byte) 0x00, (byte) 0x4E, (byte) 0x56, - (byte) 0xFF, (byte) 0xFA, (byte) 0x01, - (byte) 0x08, (byte) 0x2E, (byte) 0x2E, - (byte) 0x00, (byte) 0xB6, (byte) 0xD0, - (byte) 0x68, (byte) 0x3E, (byte) 0x80, - (byte) 0x2F, (byte) 0x0C, (byte) 0xA9, - (byte) 0xFE, (byte) 0x64, (byte) 0x53, - (byte) 0x69, (byte) 0x7A}; - - private static final byte[] AES_sAIT = { - (byte) 0x73, // s - (byte) 0x41, // A - (byte) 0x6C, // I - (byte) 0x54 // T - }; - - // block size of aes key. - private static final int BLOCK_SIZE = 16; - - // Stores data about encryption - private EncryptionDictionary encryptionDictionary; - - // Standard encryption key - private byte[] encryptionKey; - - // last used object reference - private Reference objectReference; - - // last used RC4 encryption key - private byte[] rc4Key = null; - - // user password; - private String userPassword = ""; - - // user password; - private String ownerPassword = ""; - - /** - * Create a new instance of the StandardEncryption object. - * - * @param encryptionDictionary standard encryption dictionary values - */ - public StandardEncryption(EncryptionDictionary encryptionDictionary) { - this.encryptionDictionary = encryptionDictionary; - } - - /** - * General encryption algorithm 3.1 for encryption of data using an - * encryption key. - * - * @param objectReference object number of object being encrypted - * @param encryptionKey encryption key for document - * @param algorithmType V2 or AESV2 standard encryption encryption types. - * @param inputData date to encrypted/decrypt. - * @return encrypted/decrypted data. - */ - public byte[] generalEncryptionAlgorithm(Reference objectReference, - byte[] encryptionKey, - final String algorithmType, - byte[] inputData, - boolean encrypt) { - - if (objectReference == null || encryptionKey == null || - inputData == null) { - // throw security exception - return null; - } - - // Algorithm 3.1, version 1-4 - if (encryptionDictionary.getVersion() < 5) { - - // RC4 or AES algorithm detection - boolean isRc4 = algorithmType.equals(ENCRYPTION_TYPE_V2); - - // optimization, if the encryptionKey and objectReference are the - // same there is no reason to calculate a new key. - if (rc4Key == null || this.encryptionKey != encryptionKey || - this.objectReference != objectReference) { - - this.objectReference = objectReference; - - // Step 1 to 3, bytes - byte[] step3Bytes = resetObjectReference(objectReference, isRc4); - - // Step 4: Use the first (n+5) byes, up to a max of 16 from the MD5 - // hash - int n = encryptionKey.length; - rc4Key = new byte[Math.min(n + 5, BLOCK_SIZE)]; - System.arraycopy(step3Bytes, 0, rc4Key, 0, rc4Key.length); - } - - // if we are encrypting we need to properly pad the byte array. - int encryptionMode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; - - // Set up an RC4 cipher and try to decrypt: - byte[] finalData = null; // return data if all goes well - try { - // Use above as key for the RC4 encryption function. - if (isRc4) { - // Use above as key for the RC4 encryption function. - SecretKeySpec key = new SecretKeySpec(rc4Key, "RC4"); - Cipher rc4 = Cipher.getInstance("RC4"); - rc4.init(encryptionMode, key); - // finally add the stream or string data - finalData = rc4.doFinal(inputData); - } else { - SecretKeySpec key = new SecretKeySpec(rc4Key, "AES"); - Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding"); - - // decrypt the data. - if (encryptionMode == Cipher.DECRYPT_MODE) { - // calculate 16 byte initialization vector. - byte[] initialisationVector = new byte[BLOCK_SIZE]; - // should never happen as it would mean a string that won't encrypted properly as it - // would be missing full length 16 byte public key. - if (inputData.length < BLOCK_SIZE) { - byte[] tmp = new byte[BLOCK_SIZE]; - System.arraycopy(inputData, 0, tmp, 0, inputData.length); - inputData = tmp; - } - // grab the public key. - System.arraycopy(inputData, 0, initialisationVector, 0, BLOCK_SIZE); - final IvParameterSpec iVParameterSpec = - new IvParameterSpec(initialisationVector); - - // trim the input, get rid of the key and expose the data to decrypt - byte[] intermData = new byte[inputData.length - BLOCK_SIZE]; - System.arraycopy(inputData, BLOCK_SIZE, intermData, 0, intermData.length); - - // finally add the stream or string data - aes.init(encryptionMode, key, iVParameterSpec); - finalData = aes.doFinal(intermData); - } else { - // padding is taken care of by PKCS5Padding, so we don't have to touch the data. - final IvParameterSpec iVParameterSpec = new IvParameterSpec(generateIv()); - aes.init(encryptionMode, key, iVParameterSpec); - finalData = aes.doFinal(inputData); - - // add randomness to the start - byte[] output = new byte[iVParameterSpec.getIV().length + finalData.length]; - System.arraycopy(iVParameterSpec.getIV(), 0, output, 0, BLOCK_SIZE); - System.arraycopy(finalData, 0, output, BLOCK_SIZE, finalData.length); - finalData = output; - } - } - - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } catch (IllegalBlockSizeException ex) { - logger.log(Level.FINE, "IllegalBlockSizeException.", ex); - } catch (BadPaddingException ex) { - logger.log(Level.FINE, "BadPaddingException.", ex); - } catch (NoSuchPaddingException ex) { - logger.log(Level.FINE, "NoSuchPaddingException.", ex); - } catch (InvalidKeyException ex) { - logger.log(Level.FINE, "InvalidKeyException.", ex); - } catch (InvalidAlgorithmParameterException ex) { - logger.log(Level.FINE, "InvalidAlgorithmParameterException", ex); - } - - return finalData; - } - // Algorithm 3.1a, version 5 - else if (encryptionDictionary.getVersion() == 5) { - // Use the 32-byte file encryption key for the AES-256 symmetric - // key algorithm, along with the string or stream data to be encrypted. - - // Use the AES algorithm in Cipher Block Chaining (CBC) mode, which - // requires an initialization vector. The block size parameter is - // set to 16 bytes, and the initialization vector is a 16-byte random - // number that is stored as the first 16 bytes of the encrypted - // stream or string. - try { - SecretKeySpec key = new SecretKeySpec(encryptionKey, "AES"); - Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding"); - - // calculate 16 byte initialization vector. - byte[] initialisationVector = new byte[BLOCK_SIZE]; - System.arraycopy(inputData, 0, initialisationVector, 0, BLOCK_SIZE); - - // trim the input - byte[] intermData = new byte[inputData.length - BLOCK_SIZE]; - System.arraycopy(inputData, BLOCK_SIZE, intermData, 0, intermData.length); - - final IvParameterSpec iVParameterSpec = - new IvParameterSpec(initialisationVector); - - aes.init(Cipher.DECRYPT_MODE, key, iVParameterSpec); - - // finally add the stream or string data - byte[] finalData = aes.doFinal(intermData); - return finalData; - - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } catch (IllegalBlockSizeException ex) { - logger.log(Level.FINE, "IllegalBlockSizeException.", ex); - } catch (BadPaddingException ex) { - logger.log(Level.FINE, "BadPaddingException.", ex); - } catch (NoSuchPaddingException ex) { - logger.log(Level.FINE, "NoSuchPaddingException.", ex); - } catch (InvalidKeyException ex) { - logger.log(Level.FINE, "InvalidKeyException.", ex); - } catch (InvalidAlgorithmParameterException ex) { - logger.log(Level.FINE, "InvalidAlgorithmParameterException", ex); - } - } - return null; - } - - /** - * Generates a recure random 16 byte (128 bit) public key for string to be - * encryped using AES. - * - * @return 16 byte public key. - */ - private byte[] generateIv() { - SecureRandom random = new SecureRandom(); - byte[] ivBytes = new byte[BLOCK_SIZE]; - random.nextBytes(ivBytes); - return ivBytes; - } - - /** - * General encryption algorithm 3.1 for encryption of data using an - * encryption key. - * - * Must be synchronized for stream decoding. - */ - public synchronized InputStream generalEncryptionInputStream( - Reference objectReference, - byte[] encryptionKey, - final String algorithmType, - InputStream input, boolean encrypt) { - if (objectReference == null || encryptionKey == null || input == null) { - // throw security exception - return null; - } - - // Algorithm 3.1, version 1-4 - if (encryptionDictionary.getVersion() < 5) { - // RC4 or AES algorithm detection - boolean isRc4 = algorithmType.equals(ENCRYPTION_TYPE_V2); - - // optimization, if the encryptionKey and objectReference are the - // same there is no reason to calculate a new key. - if (rc4Key == null || this.encryptionKey != encryptionKey || - this.objectReference != objectReference) { - - this.objectReference = objectReference; - - // Step 1 to 3, bytes - byte[] step3Bytes = resetObjectReference(objectReference, isRc4); - - // Step 4: Use the first (n+5) byes, up to a max of 16 from the MD5 - // hash - int n = encryptionKey.length; - rc4Key = new byte[Math.min(n + 5, BLOCK_SIZE)]; - System.arraycopy(step3Bytes, 0, rc4Key, 0, rc4Key.length); - } - - // if we are encrypting we need to properly pad the byte array. - int encryptionMode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; - // Set up an RC4 cipher and try to decrypt: - try { - SecretKeySpec key = new SecretKeySpec(rc4Key, "AES"); - - // Use above as key for the RC4 encryption function. - if (isRc4) { - Cipher rc4 = Cipher.getInstance("RC4"); - rc4.init(Cipher.DECRYPT_MODE, key); - // finally add the stream or string data - CipherInputStream cin = new CipherInputStream(input, rc4); - return cin; - } - // use above a key for the AES encryption function. - else { - Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding"); - if (encryptionMode == Cipher.DECRYPT_MODE) { - // calculate 16 byte initialization vector. - byte[] initialisationVector = new byte[BLOCK_SIZE]; - input.read(initialisationVector); - final IvParameterSpec iVParameterSpec = new IvParameterSpec(initialisationVector); - aes.init(encryptionMode, key, iVParameterSpec); - // finally add the stream or string data - CipherInputStream cin = new CipherInputStream(input, aes); - return cin; - } else { - final IvParameterSpec iVParameterSpec = new IvParameterSpec(generateIv()); - aes.init(encryptionMode, key, iVParameterSpec); - ByteArrayOutputStream outputByteArray = new ByteArrayOutputStream(); - // finally add the stream or string data - CipherOutputStream cos = new CipherOutputStream(outputByteArray, aes); - try { - byte[] data = new byte[4096]; - int read; - while ((read = input.read(data)) != -1) { - cos.write(data, 0, read); - } - } finally { - cos.close(); - input.close(); - } - byte[] finalData = outputByteArray.toByteArray(); - // add randomness to the start - byte[] output = new byte[iVParameterSpec.getIV().length + finalData.length]; - System.arraycopy(iVParameterSpec.getIV(), 0, output, 0, BLOCK_SIZE); - System.arraycopy(finalData, 0, output, BLOCK_SIZE, finalData.length); - finalData = output; - return new ByteArrayInputStream(finalData); - - } - - } - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } catch (NoSuchPaddingException ex) { - logger.log(Level.FINE, "NoSuchPaddingException.", ex); - } catch (InvalidKeyException ex) { - logger.log(Level.FINE, "InvalidKeyException.", ex); - } catch (InvalidAlgorithmParameterException ex) { - logger.log(Level.FINE, "InvalidAlgorithmParameterException", ex); - } catch (IOException ex) { - logger.log(Level.FINE, "InvalidAlgorithmParameterException", ex); - } - } - // Algorithm 3.1a, version 5 - else if (encryptionDictionary.getVersion() == 5) { - // Use the 32-byte file encryption key for the AES-256 symmetric - // key algorithm, along with the string or stream data to be encrypted. - - // Use the AES algorithm in Cipher Block Chaining (CBC) mode, which - // requires an initialization vector. The block size parameter is - // set to 16 bytes, and the initialization vector is a 16-byte random - // number that is stored as the first 16 bytes of the encrypted - // stream or string. - try { - // use above a key for the AES encryption function. - SecretKeySpec key = new SecretKeySpec(encryptionKey, "AES"); - Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding"); - - // calculate 16 byte initialization vector. - byte[] initialisationVector = new byte[BLOCK_SIZE]; - input.read(initialisationVector); - - final IvParameterSpec iVParameterSpec = - new IvParameterSpec(initialisationVector); - - aes.init(Cipher.DECRYPT_MODE, key, iVParameterSpec); - - // finally add the stream or string data - CipherInputStream cin = new CipherInputStream(input, aes); - return cin; - - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } catch (NoSuchPaddingException ex) { - logger.log(Level.FINE, "NoSuchPaddingException.", ex); - } catch (InvalidKeyException ex) { - logger.log(Level.FINE, "InvalidKeyException.", ex); - } catch (InvalidAlgorithmParameterException ex) { - logger.log(Level.FINE, "InvalidAlgorithmParameterException", ex); - } catch (IOException ex) { - logger.log(Level.FINE, "InvalidAlgorithmParameterException", ex); - } - } - return null; - } - - /** - * Step 1-3 of the general encryption algorithm 3.1. The procedure - * is as follows: - *

        - * Treat the object number and generation number as binary integers, extend - * the original n-byte encryption key to n + 5 bytes by appending the - * low-order 3 bytes of the object number and the low-order 2 bytes of the - * generation number in that order, low-order byte first. (n is 5 unless - * the value of V in the encryption dictionary is greater than 1, in which - * case the n is the value of Length divided by 8.) - *
        - * If using the AES algorithm, extend the encryption key an additional - * 4 bytes by adding the value "sAlT", which corresponds to the hexadecimal - * values 0x73, 0x41, 0x6C, 0x54. (This addition is done for backward - * compatibility and is not intended to provide additional security.) - *
      - * - * @param objectReference pdf object reference or the identifier of the - * inderect object in the case of a string. - * @param isRc4 if true use the RC4 stream cipher, if false use the AES - * symmetric block cipher. - * @return Byte [] manipulated as specified. - */ - public byte[] resetObjectReference(Reference objectReference, boolean isRc4) { - - // Step 1: separate object and generation numbers for objectReference - int objectNumber = objectReference.getObjectNumber(); - int generationNumber = objectReference.getGenerationNumber(); - - // Step 2: - // v > 1 n is the value of Length divided by 8. - int n = 5; - if (encryptionDictionary.getVersion() > 1) { - n = encryptionDictionary.getKeyLength() / 8;//enencryptionKey.length; - } - // extend the original n-byte encryption key to n + 5 bytes - - int paddingLength = 5; - if (!isRc4) { - paddingLength += 4; - } - - byte[] step2Bytes = new byte[n + paddingLength]; - - // make the copy - System.arraycopy(encryptionKey, 0, step2Bytes, 0, n); - - // appending the low-order 3 bytes of the object number - step2Bytes[n] = (byte) (objectNumber & 0xff); - step2Bytes[n + 1] = (byte) (objectNumber >> 8 & 0xff); - step2Bytes[n + 2] = (byte) (objectNumber >> 16 & 0xff); - // appending low-order 2 bytes of the generation number low-order - step2Bytes[n + 3] = (byte) (generationNumber & 0xff); - step2Bytes[n + 4] = (byte) (generationNumber >> 8 & 0xff); - - // if using AES algorithm extend by four bytes "sAIT" (0x73, 0x41, 0x6c, 0x54) - if (!isRc4) { - step2Bytes[n + 5] = AES_sAIT[0]; - step2Bytes[n + 6] = AES_sAIT[1]; - step2Bytes[n + 7] = AES_sAIT[2]; - step2Bytes[n + 8] = AES_sAIT[3]; - } - - // Step 3: Initialize the MD5 hash function and pass in step2Bytes - MessageDigest md5 = null; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException builtin) { - } - // and pass in padded password from step 1 - md5.update(step2Bytes); - - // finally return the modified object reference - return md5.digest(); - } - - /** - * Encryption key algorithm 3.2 for computing an encryption key given - * a password string. - */ - public byte[] encryptionKeyAlgorithm(String password, int keyLength) { - - if (encryptionDictionary.getRevisionNumber() < 5) { - // Step 1: pad the password - byte[] paddedPassword = padPassword(password); - - // Step 2: initialize the MD5 hash function - MessageDigest md5 = null; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } - // and pass in padded password from step 1 - md5.update(paddedPassword); - - // Step 3: Pass the value of the encryption dictionary's 0 entry - byte[] bigO = Utils.convertByteCharSequenceToByteArray( - encryptionDictionary.getBigO()); - md5.update(bigO); - - // Step 4: treat P as an unsigned 4-byte integer - for (int i = 0, p = encryptionDictionary.getPermissions(); i < 4; i++, - p >>= 8) { - md5.update((byte) (p & 0xFF)); - } - - // Step 5: Pass in the first element of the file's file identifies array - String firstFileID = encryptionDictionary.getLiteralString(encryptionDictionary.getFileID().get(0)); - byte[] fileID = Utils.convertByteCharSequenceToByteArray(firstFileID); - md5.update(fileID); - - // Step 6: If document metadata is not being encrypted, pass 4 bytes with - // the value of 0xFFFFFFFF to the MD5 hash, Security handlers of revision 4 or greater) - if (encryptionDictionary.getRevisionNumber() >= 4 && - !encryptionDictionary.isEncryptMetaData()) { - for (int i = 0; i < 4; ++i) { - md5.update((byte) 0xFF); - } - } - - // Step 7: Finish Hash. - paddedPassword = md5.digest(); - - // key length - int keySize = encryptionDictionary.getRevisionNumber() == 2 ? 5 : keyLength / 8; - if (keySize > paddedPassword.length) { - keySize = paddedPassword.length; - } - byte[] out = new byte[keySize]; - - // Step 8: Do the following 50 times: take the output from the previous - // MD5 hash and pass it as a input into a new MD5 hash; - // only for R >= 3 - try { - if (encryptionDictionary.getRevisionNumber() >= 3) { - for (int i = 0; i < 50; i++) { - md5.update(paddedPassword, 0, keySize); - md5.digest(paddedPassword, 0, paddedPassword.length); - } - } - } catch (DigestException e) { - logger.log(Level.WARNING, "Error creating MD5 digest.", e); - } - - // Step 9: Set the encryption key to the first n bytes of the output from - // the MD5 hash - - // truncate out to the appropriate value - System.arraycopy(paddedPassword, - 0, - out, - 0, - keySize); - // assign instance - encryptionKey = out; - - return out; - } - // algorithm 3.2a for Revision 5 - else if (encryptionDictionary.getRevisionNumber() == 5) { - try { - byte[] passwordBytes = Utils.convertByteCharSequenceToByteArray(password); - if (passwordBytes == null) { - passwordBytes = new byte[0]; - } - - byte[] ownerPassword = Utils.convertByteCharSequenceToByteArray( - encryptionDictionary.getBigO()); - byte[] userPassword = Utils.convertByteCharSequenceToByteArray( - encryptionDictionary.getBigU()); - // To understand the algorithm below, it is necessary to treat - // the O and U strings in the Encrypt dictionary as made up of - // three sections. The first 32 bytes are a hash value . - // The next 8 bytes are called the Validation Salt. - // The final 8 bytes are called the Key Salt. - MessageDigest md = MessageDigest.getInstance("SHA-256"); - // 3.) computing the SHA-256 hash of the UTF-8 password, 127 - // bytes if it is longer than 127 bytes. - md.update(passwordBytes, 0, Math.min(passwordBytes.length, 127)); - // concatenated with the 8 bytes of owner Validation Salt, - md.update(ownerPassword, 32, 8); - // concatenated with the 48-byte U string - md.update(userPassword, 0, 48); - // calculate the 32 bit result - byte[] hash = md.digest(); - // Check if the 32-byte result matches the first 32 bytes of the - // O string, this is the owner password. - boolean isOwnerPassword = byteCompare(hash, ownerPassword, 32); - encryptionDictionary.setAuthenticatedOwnerPassword(isOwnerPassword); - if (isOwnerPassword) { - // calculate an intermediate owner key - md.update(passwordBytes, 0, Math.min(passwordBytes.length, 127)); - // concatenate 8 bytes of owner key salt - md.update(ownerPassword, 32, 8); - // concatenated with the 48-byte u string - md.update(userPassword, 0, 48); - hash = md.digest(); - // the 32 byte hash result is the key to decrypt the 32byte - // oe string using AES-256 in CBC mode with no padding and an - // initialization vector of zero. - // the 32byte result is the file encryption key. - byte[] oePassword = Utils.convertByteCharSequenceToByteArray( - encryptionDictionary.getBigOE()); - encryptionKey = AES256CBC(hash, oePassword); - } - // 4.)test the password against the user password. - else { - // concatenate password - md.update(passwordBytes, 0, Math.min(passwordBytes.length, 127)); - // concatenated with the 8 bytes of user Validation Salt - md.update(userPassword, 32, 8); - hash = md.digest(); - // test first 32 bytes against the user string. - boolean isUserPassword = byteCompare(hash, userPassword, 32); - encryptionDictionary.setAuthenticatedUserPassword(isUserPassword); - if (isUserPassword) { - // calculate an intermediate owner key - md.update(passwordBytes, 0, Math.min(passwordBytes.length, 127)); - // concatenate 8 bytes of owner key salt - md.update(userPassword, 40, 8); - hash = md.digest(); - // the 32 byte hash result is the key to decrypt the 32byte - // ue string using AES-256 in CBC mode with no padding and an - // initialization vector of zero. - // the 32byte result is the file encryption key. - byte[] uePassword = Utils.convertByteCharSequenceToByteArray( - encryptionDictionary.getBigUE()); - encryptionKey = AES256CBC(hash, uePassword); - } else { - logger.warning("User password is incorrect. "); - } - } - // 5.)Decrypt the 16-byte Perms string using AES-256 in ECB mode - // with an initialization vector of zero and the file encryption - // key as the key. - byte[] perms = Utils.convertByteCharSequenceToByteArray( - encryptionDictionary.getPerms()); - byte[] decryptedPerms = AES256CBC(encryptionKey, perms); - - // Verify that bytes 9-11 of the result are the characters 'a', 'd', 'b'. - if (decryptedPerms[9] != (byte) 'a' || - decryptedPerms[10] != (byte) 'd' || - decryptedPerms[11] != (byte) 'b') { - logger.warning("User password is incorrect."); - return null; - } - // Bytes 0-3 of the decrypted Perms entry, treated as a - // little-endian integer, are the user permissions. They should - // match the value in the P key. - int permissions = (decryptedPerms[0] & 0xff) | - ((decryptedPerms[1] & 0xff) << 8) | - ((decryptedPerms[2] & 0xff) << 16) | - ((decryptedPerms[2] & 0xff) << 24); - int pPermissions = encryptionDictionary.getPermissions(); - if (pPermissions != permissions) { - logger.warning("Perms and P do not match"); - } - return encryptionKey; - } catch (NoSuchAlgorithmException e) { - logger.warning("Error computing the the 3.2a Encryption key."); - } - } else { - logger.warning("Adobe standard Encryption R = 6 is not supported."); - } - return null; - } - - /** - * ToDo: xjava.security.Padding, look at class for interface to see - * if PDFPadding class could/should be built - *

      - * Pad or truncate the password string to exactly 32 bytes. If the - * password is more than 32 bytes long, use only its first 32 bytes; if it - * is less than 32 bytes long, pad it by appending the required number of - * additional bytes from the beginning of the PADDING string. - *

      - * NOTE: This is algorithm is the 1st step of algorithm 3.2 - * and is commonly used by other methods in this class - * - * @param password password to padded - * @return returned updated password with appropriate padding applied - */ - protected static byte[] padPassword(String password) { - - // create the standard 32 byte password - byte[] paddedPassword = new byte[32]; - - // Passwords can be null, if so set it to an empty string - if (password == null || "".equals(password)) { - return PADDING; - } - - - int passwordLength = Math.min(password.length(), 32); - - byte[] bytePassword = - Utils.convertByteCharSequenceToByteArray(password); - // copy passwords bytes, but truncate the password is > 32 bytes - System.arraycopy(bytePassword, 0, paddedPassword, 0, passwordLength); - - // pad the password if it is < 32 bytes - System.arraycopy(PADDING, - 0, - paddedPassword, - // start copy at end of string - passwordLength, - // append need bytes from PADDING - 32 - passwordLength); - - return paddedPassword; - } - - /** - * Computing Owner password value, Algorithm 3.3. - *

      - * AESv3 passwords are not handle by this method, instead use - * {@link #generalEncryptionAlgorithm(org.icepdf.core.pobjects.Reference, byte[], String, byte[], boolean)} - * If the result is not null then the encryptionDictionary will container - * values for isAuthenticatedOwnerPassword and isAuthenticatedUserPassword. - * - * @param ownerPassword owner pasword string. If there is no owner, - * password use the user password instead. - * @param userPassword user password. - * @param isAuthentication if true, only steps 1-4 of the algorithm will be - * completed. If false, all 8 steps of the algorithm will be - * completed - * Note :
      - * There may be a bug in this algorithm when all 8 steps are called. - * 1-4 are work properly, but 1-8 can not generate an O value that is - * the same as the orgional documents O. This is not a currently a - * problem as we do not author PDF documents. - */ - public byte[] calculateOwnerPassword(String ownerPassword, - String userPassword, - boolean isAuthentication) { - // Step 1: padd the owner password, use the userPassword if empty. - if ("".equals(ownerPassword) && !"".equals(userPassword)) { - ownerPassword = userPassword; - } - byte[] paddedOwnerPassword = padPassword(ownerPassword); - - // Step 2: Initialize the MD5 hash function and pass in step 2. - MessageDigest md5 = null; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - logger.log(Level.FINE, "Could not fint MD5 Digest", e); - } - // and pass in padded password from step 1 - paddedOwnerPassword = md5.digest(paddedOwnerPassword); - - // Step 3: Do the following 50 times: take the output from the previous - // MD5 hash and pass it as input into a new MD5 hash; - // only for R = 3 - if (encryptionDictionary.getRevisionNumber() >= 3) { - for (int i = 0; i < 50; i++) { - paddedOwnerPassword = md5.digest(paddedOwnerPassword); - } - } - - // Step 4: Create an RC4 encryption key using the first n bytes of the - // final MD5 hash, where n is always 5 for revision 2 and the value - // of the encryption dictionary's Length entry for revision 3. - // Set up an RC4 cipher and try to encrypt: - - // grap the needed n bytes. - int dataSize = 5; // default for R == 2 - if (encryptionDictionary.getRevisionNumber() >= 3) { - dataSize = encryptionDictionary.getKeyLength() / 8; - } - if (dataSize > paddedOwnerPassword.length) { - dataSize = paddedOwnerPassword.length; - } - - // truncate the byte array RC4 encryption key - byte[] encryptionKey = new byte[dataSize]; - - System.arraycopy(paddedOwnerPassword, 0, encryptionKey, 0, dataSize); - - // Key is needed by algorithm 3.7, Authenticating owner password - if (isAuthentication) { - return encryptionKey; - } - - // Step 5: Pad or truncate the user password string - byte[] paddedUserPassword = padPassword(userPassword); - - // Step 6: Encrypt the result of step 4, using the RC4 encryption - // function with the encryption key obtained in step 4 - byte[] finalData = null; - try { - // Use above as key for the RC4 encryption function. - SecretKeySpec key = new SecretKeySpec(encryptionKey, "RC4"); - Cipher rc4 = Cipher.getInstance("RC4"); - rc4.init(Cipher.ENCRYPT_MODE, key); - - // finally add the stream or string data - finalData = rc4.update(paddedUserPassword); - - - // Step 7: Do the following 19 times: Take the output from the previous - // invocation of the RC4 function and pass it as input to a new - // invocation of the function; use an encryption key generated by taking - // each byte of the encryption key in step 4 and performing an XOR - // operation between that byte and the single-byte value of the - // iteration counter - if (encryptionDictionary.getRevisionNumber() >= 3) { - - // key to be made on each interaction - byte[] indexedKey = new byte[encryptionKey.length]; - // start the 19? interactions - for (int i = 1; i <= 19; i++) { - - // build new key for each i xor on each byte - for (int j = 0; j < encryptionKey.length; j++) { - indexedKey[j] = (byte) (encryptionKey[j] ^ i); - } - // create new key and init rc4 - key = new SecretKeySpec(indexedKey, "RC4"); - //Cipher tmpRc4 = Cipher.getInstance("RC4"); - rc4.init(Cipher.ENCRYPT_MODE, key); - // encrypt the old data with the new key - finalData = rc4.update(finalData); - } - } - - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } catch (NoSuchPaddingException ex) { - logger.log(Level.FINE, "NoSuchPaddingException.", ex); - } catch (InvalidKeyException ex) { - logger.log(Level.FINE, "InvalidKeyException.", ex); - } - - - // Debug Code. -// String O = encryptionDictionary.getBigO(); -// System.out.print("Original O " + O.length() + " "); -// byte[] bigO = new byte[O.length()]; -// for (int i=0; i < bigO.length; i++){ -// //bigO[i] = (byte)O.charAt(i); -// System.out.print((int)O.charAt(i)); -// } -// System.out.println(); -// -// System.out.print("new O " + finalData.length + " "); -// for (int i=0; i < finalData.length; i++){ -// System.out.print((int)finalData[i]); -// } -// System.out.println(); - - // Step 8: return the final invocation of the RC4 function as O - return finalData; - } - - /** - * Computing Owner password value, Algorithm 3.4 is respected for - * Revision = 2 and Algorithm 3.5 is respected for Revisison = 3, null - * otherwise. - *

      - * AESv3 passwords are not handle by this method, instead use - * {@link #generalEncryptionAlgorithm(org.icepdf.core.pobjects.Reference, byte[], String, byte[], boolean)} - * If the result is not null then the encryptionDictionary will container - * values for isAuthenticatedOwnerPassword and isAuthenticatedUserPassword. - * - * @param userPassword user password. - * @return byte array representing the U value for the encryption dictionary - */ - public byte[] calculateUserPassword(String userPassword) { - - // Step 1: Create an encryption key based on the user password String, - // as described in Algorithm 3.2 - byte[] encryptionKey = encryptionKeyAlgorithm( - userPassword, - encryptionDictionary.getKeyLength()); - - // Algorithm 3.4 steps, 2 - 3 - if (encryptionDictionary.getRevisionNumber() == 2) { - // Step 2: Encrypt the 32-byte padding string show in step 1, using - // an RC4 encryption function with the encryption key from the - // preceding step - - // 32-byte padding string - byte[] paddedUserPassword = PADDING.clone(); - // encrypt the data - byte[] finalData = null; - try { - // Use above as key for the RC4 encryption function. - SecretKeySpec key = new SecretKeySpec(encryptionKey, "RC4"); - Cipher rc4 = Cipher.getInstance("RC4"); - rc4.init(Cipher.ENCRYPT_MODE, key); - - // finally encrypt the padding string - finalData = rc4.doFinal(paddedUserPassword); - - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } catch (IllegalBlockSizeException ex) { - logger.log(Level.FINE, "IllegalBlockSizeException.", ex); - } catch (BadPaddingException ex) { - logger.log(Level.FINE, "BadPaddingException.", ex); - } catch (NoSuchPaddingException ex) { - logger.log(Level.FINE, "NoSuchPaddingException.", ex); - } catch (InvalidKeyException ex) { - logger.log(Level.FINE, "InvalidKeyException.", ex); - } - // Step 3: return the result of step 2 as the value of the U entry - return finalData; - } - // algorithm 3.5 steps, 2 - 6 - else if (encryptionDictionary.getRevisionNumber() >= 3 && - encryptionDictionary.getRevisionNumber() < 5) { - // Step 2: Initialize the MD5 hash function and pass the 32-byte - // padding string shown in step 1 of Algorithm 3.2 as input to - // this function - byte[] paddedUserPassword = PADDING.clone(); - MessageDigest md5 = null; - try { - md5 = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - logger.log(Level.FINE, "MD5 digester could not be found", e); - } - // and pass in padded password 32-byte padding string - md5.update(paddedUserPassword); - - // Step 3: Pass the first element of the files identify array to the - // hash function and finish the hash. - String firstFileID = encryptionDictionary.getLiteralString(encryptionDictionary.getFileID().get(0)); - byte[] fileID = Utils.convertByteCharSequenceToByteArray(firstFileID); - byte[] encryptData = md5.digest(fileID); - - // Step 4: Encrypt the 16 byte result of the hash, using an RC4 - // encryption function with the encryption key from step 1 - //System.out.println("R=3 " + encryptData.length); - - // The final data should be 16 bytes long - // currently no checking for this. - - try { - // Use above as key for the RC4 encryption function. - SecretKeySpec key = new SecretKeySpec(encryptionKey, "RC4"); - Cipher rc4 = Cipher.getInstance("RC4"); - rc4.init(Cipher.ENCRYPT_MODE, key); - - // finally encrypt the padding string - encryptData = rc4.update(encryptData); - - // Step 5: Do the following 19 times: Take the output from the previous - // invocation of the RC4 function and pass it as input to a new - // invocation of the function; use an encryption key generated by taking - // each byte of the encryption key in step 4 and performing an XOR - // operation between that byte and the single-byte value of the - // iteration counter - - // key to be made on each interaction - byte[] indexedKey = new byte[encryptionKey.length]; - // start the 19? interactions - for (int i = 1; i <= 19; i++) { - - // build new key for each i xor on each byte - for (int j = 0; j < encryptionKey.length; j++) { - indexedKey[j] = (byte) (encryptionKey[j] ^ (byte) i); - } - // create new key and init rc4 - key = new SecretKeySpec(indexedKey, "RC4"); - rc4.init(Cipher.ENCRYPT_MODE, key); - // encrypt the old data with the new key - encryptData = rc4.update(encryptData); - } - - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } catch (NoSuchPaddingException ex) { - logger.log(Level.FINE, "NoSuchPaddingException.", ex); - } catch (InvalidKeyException ex) { - logger.log(Level.FINE, "InvalidKeyException.", ex); - } - // Step 6: Append 16 bytes of arbitrary padding to the output from - // the final invocation of the RC4 function and return the 32-byte - // result as the value of the U entry. - byte[] finalData = new byte[32]; - System.arraycopy(encryptData, 0, finalData, 0, BLOCK_SIZE); - System.arraycopy(PADDING, 0, finalData, BLOCK_SIZE, BLOCK_SIZE); - - return finalData; - } else { - return null; - } - } - - /** - * Authenticating the user password, algorithm 3.6 - * - * @param userPassword user password to check for authenticity - * @return true if the userPassword matches the value the encryption - * dictionary U value, false otherwise. - */ - public boolean authenticateUserPassword(String userPassword) { - // Step 1: Perform all but the last step of Algorithm 3.4(Revision 2) or - // Algorithm 3.5 (Revision 3) using the supplied password string. - byte[] tmpUValue = calculateUserPassword(userPassword); - - byte[] bigU = Utils.convertByteCharSequenceToByteArray( - encryptionDictionary.getBigU()); - - byte[] trunkUValue; - // compare all 32 bytes. - if (encryptionDictionary.getRevisionNumber() == 2) { - trunkUValue = new byte[32]; - System.arraycopy(tmpUValue, 0, trunkUValue, 0, trunkUValue.length); - } - // truncate to first 16 bytes for R >= 3 - else if (encryptionDictionary.getRevisionNumber() >= 3 && - encryptionDictionary.getRevisionNumber() < 5) { - trunkUValue = new byte[BLOCK_SIZE]; - System.arraycopy(tmpUValue, 0, trunkUValue, 0, trunkUValue.length); - } else { - return false; - } - - // Step 2: If the result of step 1 is equal o the value of the - // encryption dictionary's U entry, the password supplied is the correct - // user password. - - boolean found = true; - for (int i = 0; i < trunkUValue.length; i++) { - if (trunkUValue[i] != bigU[i]) { - found = false; - break; - } - } - return found; - } - - /** - * Authenticating the owner password, algorithm 3.7 - */ - public boolean authenticateOwnerPassword(String ownerPassword) { - // Step 1: Computer an encryption key from the supplied password string, - // as described in steps 1 to 4 of algorithm 3.3. - byte[] encryptionKey = calculateOwnerPassword(ownerPassword, - "", true); - - // Step 2: start decryption of O - byte[] decryptedO = null; - try { - // get bigO value - byte[] bigO = Utils.convertByteCharSequenceToByteArray( - encryptionDictionary.getBigO()); - if (encryptionDictionary.getRevisionNumber() == 2) { - // Step 2 (R == 2): decrypt the value of the encryption dictionary - // O entry, using an RC4 encryption function with the encryption - // key computed in step 1. - - // Use above as key for the RC4 encryption function. - SecretKeySpec key = new SecretKeySpec(encryptionKey, "RC4"); - Cipher rc4 = Cipher.getInstance("RC4"); - rc4.init(Cipher.DECRYPT_MODE, key); - decryptedO = rc4.doFinal(bigO); - } - // Step 2 (R >= 3): Do the following 19 times: Take the output from the previous - // invocation of the RC4 function and pass it as input to a new - // invocation of the function; use an encryption key generated by taking - // each byte of the encryption key in step 4 and performing an XOR - // operation between that byte and the single-byte value of the - // iteration counter - else {//if (encryptionDictionary.getRevisionNumber() >= 3){ - // key to be made on each interaction - byte[] indexedKey = new byte[encryptionKey.length]; - - decryptedO = bigO; - // start the 19->0? interactions - for (int i = 19; i >= 0; i--) { - - // build new key for each i xor on each byte - for (int j = 0; j < indexedKey.length; j++) { - indexedKey[j] = (byte) (encryptionKey[j] ^ (byte) i); - } - // create new key and init rc4 - SecretKeySpec key = new SecretKeySpec(indexedKey, "RC4"); - Cipher rc4 = Cipher.getInstance("RC4"); - rc4.init(Cipher.ENCRYPT_MODE, key); - // encrypt the old data with the new key - decryptedO = rc4.update(decryptedO); - } - } - - // Step 3: The result of step 2 purports to be the user password. - // Authenticate this user password using Algorithm 3.6. If it is found - // to be correct, the password supplied is the correct owner password. - - String tmpUserPassword = Utils.convertByteArrayToByteString(decryptedO); - //System.out.println("tmp user password " + tmpUserPassword); - boolean isValid = authenticateUserPassword(tmpUserPassword); - - if (isValid) { - userPassword = tmpUserPassword; - this.ownerPassword = ownerPassword; - // setup permissions if valid - } - - return isValid; - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } catch (IllegalBlockSizeException ex) { - logger.log(Level.FINE, "IllegalBlockSizeException.", ex); - } catch (BadPaddingException ex) { - logger.log(Level.FINE, "BadPaddingException.", ex); - } catch (NoSuchPaddingException ex) { - logger.log(Level.FINE, "NoSuchPaddingException.", ex); - } catch (InvalidKeyException ex) { - logger.log(Level.FINE, "InvalidKeyException.", ex); - } - - return false; - - } - - public String getUserPassword() { - return userPassword; - } - - public String getOwnerPassword() { - return ownerPassword; - } - - /** - * Utility to decrypt the encryptedString via the intermediateKey. AES - * encryption with cypher block chaining and no padding. - * - * @param intermediateKey key to use for decryption - * @param encryptedString byte[] to decrypt - * @return - */ - private static byte[] AES256CBC(byte[] intermediateKey, byte[] encryptedString) { - byte[] finalData = null; - try { - // AES with cipher block chaining and no padding - SecretKeySpec key = new SecretKeySpec(intermediateKey, "AES"); - Cipher aes = Cipher.getInstance("AES/CBC/NoPadding"); - // empty initialization vector - final IvParameterSpec iVParameterSpec = - new IvParameterSpec(new byte[BLOCK_SIZE]); - // go! - aes.init(Cipher.DECRYPT_MODE, key, iVParameterSpec); - // finally add the stream or string data - finalData = aes.doFinal(encryptedString); - } catch (NoSuchAlgorithmException ex) { - logger.log(Level.FINE, "NoSuchAlgorithmException.", ex); - } catch (IllegalBlockSizeException ex) { - logger.log(Level.FINE, "IllegalBlockSizeException.", ex); - } catch (BadPaddingException ex) { - logger.log(Level.FINE, "BadPaddingException.", ex); - } catch (NoSuchPaddingException ex) { - logger.log(Level.FINE, "NoSuchPaddingException.", ex); - } catch (InvalidKeyException ex) { - logger.log(Level.FINE, "InvalidKeyException.", ex); - } catch (InvalidAlgorithmParameterException ex) { - logger.log(Level.FINE, "InvalidAlgorithmParameterException", ex); - } - return finalData; - } - - /** - * Compare two byte arrays to the specified max index. No check is made - * for an index out of bounds error. - * - * @param byteArray1 byte array to compare - * @param byteArray2 byte array to compare - * @param range number of elements to compare starting at zero. - * @return true if the - */ - private static boolean byteCompare(byte[] byteArray1, byte[] byteArray2, int range) { - for (int i = 0; i < range; i++) { - if (byteArray1[i] != byteArray2[i]) { - return false; - } - } - return true; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/StandardSecurityHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/StandardSecurityHandler.java deleted file mode 100644 index 42a629f668..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/pobjects/security/StandardSecurityHandler.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.pobjects.security; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Reference; - -import java.io.InputStream; -import java.util.HashMap; - -/** - *

      ICEpdf's standard security handler allows access permissions and up to two passwords - * to be specified for a document: an owner password and a user password. An - * application's decision to encrypt a document is based on whether the user - * creating the document specifies any passwords or access restrictions (for example, in a - * security settings dialog that the user can invoke before saving the PDF file); if so, - * the document is encrypted, and the permissions and information required to validate - * the passwords are stored in the encryption dictionary. (An application may - * also create an encrypted document without any user interaction, if it has some - * other source of information about what passwords and permissions to use.)

      - *

      - *

      If a user attempts to open an encrypted document that has a user password, the - * viewer application should prompt for a password. Correctly supplying either - * password allows the user to open the document, decrypt it, and display it on the - * screen. If the document does not have a user password, no password is requested; - * the viewer application can simply open, decrypt, and display the document. - * Whether additional operations are allowed on a decrypted document depends on - * which password (if any) was supplied when the document was opened and on - * any access restrictions that were specified when the document was created: - *

        - *
      • Opening the document with the correct owner password (assuming it is not - * the same as the user password) allows full (owner) access to the - * document. This unlimited access includes the ability to change the - * document's passwords and access permissions.
      • - *

        - *

      • Opening the document with the correct user password (or opening a - * document that does not have a user password) allows additional operations - * to be performed according to the user access permissions specified in the - * document's encryption dictionary.
      • - *
      - *

      - *

      Access permissions are specified in the form of flags corresponding to the - * various operations, and the set of operations to which they correspond, - * depends in turn on the security handler's revision number (also stored in the - * encryption dictionary). If the revision number is 2 or greater, the - * operations to which user access can be controlled are as follows: - *

      - *

        - *
      • Modifying the document's contents
      • - *

        - *

      • Copying or otherwise extracting text and graphics from the document, - * including extraction for accessibility purposes (that is, to make the - * contents of the document accessible through assistive technologies such - * as screen readers or Braille output devices
      • - *

        - *

      • Adding or modifying text annotations and interactive form fields
      • - *

        - *

      • Printing the document
      • - *
      - *

      - *

      If the security handler's revision number is 3 or greater, user access to the - * following operations can be controlled more selectively: - *

        - *
      • Filling in forms (that is, filling in existing interactive form fields) - * and signing the document (which amounts to filling in existing signature - * fields, a type of interactive form field)
      • - *

        - *

      • Assembling the document: inserting, rotating, or deleting pages and - * creating navigation elements such as bookmarks or thumbnail images
      • - *

        - *

      • Printing to a representation from which a faithful digital copy of the - * PDF content could be generated. Disallowing such printing may result in - * degradation of output quality (a feature implemented as "Print As Image" - * in Acrobat)
      • - *
      - *

      In addition, revision 3 enables the extraction of text and graphics (in - * support of accessibility to disabled users or for other purposes) to be - * controlled separately. Beginning with revision 4, the standard security - * handler supports crypt filters. The support is limited to the Identity crypt - * filter and crypt filters named StdCF whose dictionaries contain a CFM value - * of V2 and an AuthEvent value of DocOpen.

      - * - * @since 1.1 - */ -public class StandardSecurityHandler extends SecurityHandler { - - public static final Name NAME_KEY = new Name("Name"); - public static final Name IDENTITY_KEY = new Name("Identity"); - - // StandardEncryption holds algorithms specific to adobe standard encryption - private StandardEncryption standardEncryption = null; - - // encryption key used for encryption, Standard encryption is symmetric, so - // only one key is needed. - private byte[] encryptionKey; - - // initiated flag - private boolean initiated; - - // string to store password used for decoding, the user password is always - // used for encryption, never the user password. - private String password; - - public StandardSecurityHandler(EncryptionDictionary encryptionDictionary) { - super(encryptionDictionary); - // Full name of handler - handlerName = "Adobe Standard Security"; - } - - public boolean isAuthorized(String password) { - if (encryptionDictionary.getRevisionNumber() < 5) { - boolean value = standardEncryption.authenticateUserPassword(password); - // check password against user password - if (!value) { - // check password against owner password - value = standardEncryption.authenticateOwnerPassword(password); - // Get user, password, as it is used for generating encryption keys - if (value) { - this.password = standardEncryption.getUserPassword(); - } - } else { - // assign password for future use - this.password = password; - } - return value; - } else if (encryptionDictionary.getRevisionNumber() == 5) { - // try and calculate the document key. - byte[] encryptionKey = standardEncryption.encryptionKeyAlgorithm( - password, - encryptionDictionary.getKeyLength()); - this.password = password; - return encryptionKey != null; - } else { - return false; - } - } - - public boolean isOwnerAuthorized(String password) { - // owner password is not stored as it is not used for decryption - if (encryptionDictionary.getRevisionNumber() < 5) { - return standardEncryption.authenticateOwnerPassword(password); - } else { - return encryptionDictionary.isAuthenticatedOwnerPassword(); - } - } - - public boolean isUserAuthorized(String password) { - // owner password is not stored as it is not used for decryption - if (encryptionDictionary.getRevisionNumber() < 5) { - boolean value = standardEncryption.authenticateUserPassword(password); - if (value) { - this.password = password; - } - return value; - } else { - return encryptionDictionary.isAuthenticatedUserPassword(); - } - } - - public byte[] encrypt(Reference objectReference, - byte[] encryptionKey, - byte[] data) { - - // check if crypt filters are being used and find out if V2 or AESV2 - String algorithmType = getAlgorithmType(); - - // use the general encryption algorithm for encryption - return standardEncryption.generalEncryptionAlgorithm( - objectReference, encryptionKey, algorithmType, data, true); - } - - - public byte[] decrypt(Reference objectReference, - byte[] encryptionKey, - byte[] data) { - // check if crypt filters are being used and find out if V2 or AESV2 - String algorithmType = getAlgorithmType(); - - // use the general encryption algorithm for encryption - return standardEncryption.generalEncryptionAlgorithm( - objectReference, encryptionKey, algorithmType, data, false); - } - - /** - * Utility to determine encryption type used. - */ - private String getAlgorithmType() { - String algorithmType; - if (encryptionDictionary.getCryptFilter() != null) { - CryptFilterEntry cryptFilterEntry = - encryptionDictionary.getCryptFilter().getCryptFilterByName( - encryptionDictionary.getStrF()); - - algorithmType = cryptFilterEntry.getCryptFilterMethod().getName(); - } else { - algorithmType = StandardEncryption.ENCRYPTION_TYPE_V2; - } - return algorithmType; - } - - public InputStream decryptInputStream( - Reference objectReference, - byte[] encryptionKey, - HashMap decodeParams, - InputStream input) { - return getInputStream(objectReference, encryptionKey, decodeParams, input, false); - } - - public InputStream encryptInputStream( - Reference objectReference, - byte[] encryptionKey, - HashMap decodeParams, - InputStream input) { - return getInputStream(objectReference, encryptionKey, decodeParams, input, true); - } - - public InputStream getInputStream( - Reference objectReference, - byte[] encryptionKey, - HashMap decodeParams, - InputStream input, boolean encrypted) { - - // find the name of the crypt filter used in the CF dictionary - CryptFilterEntry cryptFilter = null; - if (decodeParams != null) { - Name filterName = (Name) decodeParams.get(NAME_KEY); - if (filterName != null) { - // identity means don't use the cryprt filter or encryption at all - // for the stream. - if (filterName.equals(IDENTITY_KEY)) { - return input; - } else { - // find the filter name in the encryption dictionary - cryptFilter = encryptionDictionary. - getCryptFilter().getCryptFilterByName(filterName); - } - } else if (encryptionDictionary.getCryptFilter() != null) { - // corner case, some images treams also use the "decodeParams" - // dictionary, if it doesn't contain a filter name then we - // want to make sure we assign the standard one so the steam - // can be unencrypted. - cryptFilter = encryptionDictionary.getCryptFilter().getCryptFilterByName( - encryptionDictionary.getStmF()); - } - } - // We default to the method specified in by StrmF in the security dictionary - else if (encryptionDictionary.getCryptFilter() != null) { - cryptFilter = encryptionDictionary.getCryptFilter().getCryptFilterByName( - encryptionDictionary.getStmF()); - } - - // get the method used for the general encryption algorithm - String algorithmType; - if (cryptFilter != null) { - algorithmType = cryptFilter.getCryptFilterMethod().getName(); - } else { - algorithmType = StandardEncryption.ENCRYPTION_TYPE_V2; - } - - return standardEncryption.generalEncryptionInputStream( - objectReference, encryptionKey, algorithmType, input, encrypted); - } - - public byte[] getEncryptionKey() { - - if (!initiated) { - // make sure class instance var have been setup - this.init(); - } - // calculate the encryptionKey based on the given user name - encryptionKey = standardEncryption.encryptionKeyAlgorithm( - password, - encryptionDictionary.getKeyLength()); - - return encryptionKey; - } - - public byte[] getDecryptionKey() { - return getEncryptionKey(); - } - - public Permissions getPermissions() { - if (!initiated) { - // make sure class instance var have been setup - this.init(); - } - return permissions; - } - - public String getHandlerName() { - return this.handlerName; - } - - public void init() { - // initiate a new instance - standardEncryption = new StandardEncryption(encryptionDictionary); - // initiate permissions - permissions = new Permissions(encryptionDictionary); - permissions.init(); - // update flag - initiated = true; - } - - public void dispose() { - standardEncryption = null; - encryptionKey = null; - permissions = null; - // update flag - initiated = false; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/search/DocumentSearchController.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/search/DocumentSearchController.java deleted file mode 100644 index c63444828d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/search/DocumentSearchController.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.search; - -import org.icepdf.core.pobjects.graphics.text.LineText; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.pobjects.graphics.text.WordText; - -import java.util.ArrayList; -import java.util.List; - -/** - * Document search controller interface for content text searches - * - * @since 4.0 - */ -public interface DocumentSearchController { - /** - * Searches the given page using the specified term and properties. The - * search model is updated to store the pages Page text as a weak reference - * which can be queried using isSearchHighlightNeeded to efficiently make - * sure that a pages text is highlighted even after a despose/init cycle. - * If the text state is no longer present then the search should be executed - * again. - *

      - * This method clears the search results for the page before it searches. If - * you wish to have cumulative search results then searches terms should - * be added with {@link #addSearchTerm(String, boolean, boolean)} and the - * method {@link #searchPage(int)} should be called after each term is - * added or after all have been added. - * - * @param pageIndex page to search - * @param caseSensitive if true use case sensitive searches - * @param wholeWord if true use whole word searches - * @param term term to search for - * @return number for hits for this page. - */ - int searchHighlightPage(int pageIndex, String term, - boolean caseSensitive, boolean wholeWord); - - /** - * Searches the page index given the search terms that have been added - * with {@link #addSearchTerm(String, boolean, boolean)}. If search - * hits where detected then the Page's PageText is added to the cache. - *

      - * This method represent the core search algorithm for this - * DocumentSearchController implementation. This method can be overridden - * if a different search algorithm or functionality is needed. - * - * @param pageIndex page index to search - * @return number of hits found for this page. - */ - int searchHighlightPage(int pageIndex); - - /** - * Searches the page index given the search terms that have been added - * with {@link #addSearchTerm(String, boolean, boolean)}. If search - * hits where detected then the Page's PageText is added to the cache. - *

      - * This class differences from {@link #searchHighlightPage(int)} in that - * is returns a list of lineText fragments for each hit but the LinText - * is padded by pre and post words that surround the hit in the page - * context. - *

      - * This method represent the core search algorithm for this - * DocumentSearchController implementation. This method can be overridden - * if a different search algorithm or functionality is needed. - * - * @param pageIndex page index to search - * @param wordPadding word padding on either side of hit to give context - * to found words in the returned LineText. Values should be greater than - * zero - * @return number of hits found for this page. - */ - List searchHighlightPage(int pageIndex, int wordPadding); - - /** - * Search page but only return words that are hits. Highlighting is till - * applied but this method can be used if other data needs to be extracted - * from the found words. - * - * @param pageIndex page to search - * @return list of words that match the term and search properties. - */ - ArrayList searchPage(int pageIndex); - - /** - * Add the search term to the list of search terms. The term is split - * into words based on white space and punctuation. No checks are done - * for duplication. - *

      - * A new search needs to be executed for this change to take place. - * - * @param term single word or phrase to search for. - * @param caseSensitive is search case sensitive. - * @param wholeWord is search whole word sensitive. - * @return searchTerm newly create search term. - */ - SearchTerm addSearchTerm(String term, boolean caseSensitive, - boolean wholeWord); - - /** - * Removes the specified search term from the search. A new search needs - * to be executed for this change to take place. - * - * @param searchTerm search term to remove. - */ - void removeSearchTerm(SearchTerm searchTerm); - - /** - * Clear all searched items for specified page. - * - * @param pageIndex page index to clear - */ - void clearSearchHighlight(int pageIndex); - - /** - * Clears all highlighted text states for this this document. This optimized - * to use the the SearchHighlightModel to only clear pages that still have - * selected states. - */ - void clearAllSearchHighlight(); - - /** - * Test to see if a search highlight is needed. This is done by first - * check if there is a hit for this page and if the PageText object is the - * same as the one specified as a param. If they are not the same PageText - * object then we need to do refresh as the page was disposed and - * reinitialized with new content. - * - * @param pageIndex page index to text for restuls. - * @param pageText current pageText object associated with the pageIndex. - * @return true if refresh is needed, false otherwise. - */ - boolean isSearchHighlightRefreshNeeded(int pageIndex, PageText pageText); - - /** - * Disposes controller clearing resources. - */ - void dispose(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/search/SearchTerm.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/search/SearchTerm.java deleted file mode 100644 index 21ca9beb65..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/search/SearchTerm.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.search; - -import java.util.ArrayList; - -/** - * Text searchs are used by the search controller to search for text in a - * document. A search can have one or more search terms which are all searched - * for in a given search. - * - * @since 4.0 - */ -public class SearchTerm { - - //original term before it was cut up into terms. - private String term; - - // number of string in search term, one or more strings that make - // up a phrase. words, white space and punctuation - private ArrayList terms; - - // case sensitive search - private boolean caseSensitive; - // whole word search. - private boolean wholeWord; - - /** - * Creates a new search term. - * - * @param term full string represented by terms. - * @param terms terms that make ups serach - * @param caseSensitive true to specify a case sensitive search - * @param wholeWord true to specify a whole word only search. - */ - public SearchTerm(String term, ArrayList terms, - boolean caseSensitive, boolean wholeWord) { - this.term = term; - this.terms = terms; - this.caseSensitive = caseSensitive; - this.wholeWord = wholeWord; - } - - /** - * Gets individual strings that make up the search term, - * - * @return list of strings that contain searchable words. - */ - public ArrayList getTerms() { - return terms; - } - - /** - * Get origional search term. - * - * @return term, word or phrase used to search. - */ - public String getTerm() { - return term; - } - - /** - * Specifies if the search term should be treated as case sensitive. - * - * @return true if cases senstive search, otherwise false. - */ - public boolean isCaseSensitive() { - return caseSensitive; - } - - /** - * Specifies if the search term should be treated as whole word hits only. - * - * @return true if whole word search, otherwise false. - */ - public boolean isWholeWord() { - return wholeWord; - } - - @Override - public boolean equals(Object object) { - if (object instanceof SearchTerm) { - SearchTerm test = (SearchTerm) object; - return test.isCaseSensitive() == caseSensitive && - test.isWholeWord() == wholeWord && - test.getTerm().equals(term); - } else { - return false; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/ColorUtil.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/ColorUtil.java deleted file mode 100644 index 646e002a51..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/ColorUtil.java +++ /dev/null @@ -1,1137 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -import java.awt.*; -import java.util.HashMap; - -/** - * ColorUtil is a utra effecient named color parser. The class has a list - * of all html named colours and their matching hex values. - * - * @since 2.7.1 - */ -public class ColorUtil { - - private static final int[] defaultColors = { - 0xf0f8ff, // aliceblue - 0xfaebd7, // antiquewhite - 0x00ffff, // aqua - 0x7fffd4, // aquamarine - 0xf0ffff, // azure - 0xf5f5dc, // beige - 0xffe4c4, // bisque - 0x000000, // black - 0xffebcd, // blanchedalmond - 0x0000ff, // blue - 0x8a2be2, // blueviolet - 0xa52a2a, // brown - 0xdeb887, // burlywood - 0x5f9ea0, // cadetblue - 0x7fff00, // chartreuse - 0xd2691e, // chocolate - 0xff7f50, // coral - 0x6495ed, // cornflowerblue - 0xfff8dc, // cornsilk - 0xdc143c, // crimson - 0x00ffff, // cyan - 0x00008b, // darkblue - 0x008b8b, // darkcyan - 0xb8860b, // darkgoldenrod - 0xa9a9a9, // darkgray - 0x006400, // darkgreen - 0xa9a9a9, // darkgrey - 0xbdb76b, // darkkhaki - 0x8b008b, // darkmagenta - 0x556b2f, // darkolivegreen - 0xff8c00, // darkorange - 0x9932cc, // darkorchid - 0x8b0000, // darkred - 0xe9967a, // darksalmon - 0x8fbc8f, // darkseagreen - 0x483d8b, // darkslateblue - 0x2f4f4f, // darkslategray - 0x2f4f4f, // darkslategrey - 0x00ced1, // darkturquoise - 0x9400d3, // darkviolet - 0xff1493, // deeppink - 0x00bfff, // deepskyblue - 0x696969, // dimgray - 0x696969, // dimgrey - 0x1e90ff, // dodgerblue - 0xb22222, // firebrick - 0xfffaf0, // floralwhite - 0x228b22, // forestgreen - 0xff00ff, // fuchsia - 0xdcdcdc, // gainsboro - 0xf8f8ff, // ghostwhite - 0xffd700, // gold - 0xdaa520, // goldenrod - 0x808080, // gray - 0x808080, // grey - 0x008000, // green - 0xadff2f, // greenyellow - 0xf0fff0, // honeydew - 0xff69b4, // hotpink - 0xcd5c5c, // indianred - 0x4b0082, // indigo - 0xfffff0, // ivory - 0xf0e68c, // khaki - 0xe6e6fa, // lavender - 0xfff0f5, // lavenderblush - 0x7cfc00, // lawngreen - 0xfffacd, // lemonchiffon - 0xadd8e6, // lightblue - 0xf08080, // lightcoral - 0xe0ffff, // lightcyan - 0xfafad2, // lightgoldenrodyellow - 0xd3d3d3, // lightgray - 0x90ee90, // lightgreen - 0xd3d3d3, // lightgrey - 0xffb6c1, // lightpink - 0xffa07a, // lightsalmon - 0x20b2aa, // lightseagreen - 0x87cefa, // lightskyblue - 0x778899, // lightslategray - 0x778899, // lightslategrey - 0xb0c4de, // lightsteelblue - 0xffffe0, // lightyellow - 0x00ff00, // lime - 0x32cd32, // limegreen - 0xfaf0e6, // linen - 0xff00ff, // magenta - 0x800000, // maroon - 0x66cdaa, // mediumaquamarine - 0x0000cd, // mediumblue - 0xba55d3, // mediumorchid - 0x9370db, // mediumpurple - 0x3cb371, // mediumseagreen - 0x7b68ee, // mediumslateblue - 0x00fa9a, // mediumspringgreen - 0x48d1cc, // mediumturquoise - 0xc71585, // mediumvioletred - 0x191970, // midnightblue - 0xf5fffa, // mintcream - 0xffe4e1, // mistyrose - 0xffe4b5, // moccasin - 0xffdead, // navajowhite - 0x000080, // navy - 0xfdf5e6, // oldlace - 0x808000, // olive - 0x6b8e23, // olivedrab - 0xffa500, // orange - 0xff4500, // orangered - 0xda70d6, // orchid - 0xeee8aa, // palegoldenrod - 0x98fb98, // palegreen - 0xafeeee, // paleturquoise - 0xdb7093, // palevioletred - 0xffefd5, // papayawhip - 0xffdab9, // peachpuff - 0xcd853f, // peru - 0xffc0cb, // pink - 0xdda0dd, // plum - 0xb0e0e6, // powderblue - 0x800080, // purple - 0xff0000, // red - 0xbc8f8f, // rosybrown - 0x4169e1, // royalblue - 0x8b4513, // saddlebrown - 0xfa8072, // salmon - 0xf4a460, // sandybrown - 0x2e8b57, // seagreen - 0xfff5ee, // seashell - 0xa0522d, // sienna - 0xc0c0c0, // silver - 0x87ceeb, // skyblue - 0x6a5acd, // slateblue - 0x708090, // slategray - 0x708090, // slategrey - 0xfffafa, // snow - 0x00ff7f, // springgreen - 0x4682b4, // steelblue - 0xd2b48c, // tan - 0x008080, // teal - 0xd8bfd8, // thistle - 0xff6347, // tomato - 0x40e0d0, // turquoise - 0xee82ee, // violet - 0xf5deb3, // wheat - 0xffffff, // white - 0xf5f5f5, // whitesmoke - 0xffff00, // yellow - 0x9acd32, // yellowgreen - }; - - private static final HashMap colors = new HashMap(); - - /** - * Converts a named colour to hex rgb notation. For example black is - * converted to #000000 and white to #FFFFFF. - * - * @param name know colour name to be converted - * @return name of converted string, the same name is returned if their was - * a conversion failure. - */ - public static final String convertColorNameToRGB(String name) { - int c = convertNamedColor(name.toLowerCase()); - if (c >= 0) { - //int rgb = c.getRGB(); - char[] buf = new char[7]; - buf[0] = '#'; - for (int pos = 1, shift = 20; shift >= 0; ++pos, shift -= 4) { - int d = 0xF & (c >> shift); - buf[pos] = (char) ((d < 10) ? d + '0' : d + 'A' - 10); - } - name = new String(buf, 0, 7); - } - return name; - } - - /** - * Converts a colour to hex rgb notation. For example black is - * converted to #000000 and white to #FFFFFF. - * - * @param color know colour to be converted - * @return name of converted string, the same name is returned if their was - * a conversion failure. - */ - public static final String convertColorToRGB(Color color) { - int c = color.getRGB(); - return String.format("#%06X", (0xFFFFFF & c)); - } - - /** - * Converts the colour to an integer value. - * - * @param name colour value in either hex or string format. - * @return valid int colour value or -1 if no colour could be resolved - */ - public static int convertColor(String name) { - try { - // see if string starts with # - if (name.startsWith("#")) { - name = name.substring(1); - } - return Integer.parseInt(name, 16); - } catch (NumberFormatException e) { - // intentionally left empty - } - // otherwise try and pare the colour name. - return convertNamedColor(name); - } - - - /** - * Converts the named colour to an integer value. This integer value can - * then be used to generate a valid java.awt.Color object. - * - * @param name name of colour to convert. - * @return integer >= 0 if named colour was converted successfully, -1 - * otherwise. - */ - public static final int convertNamedColor(String name) { - int index = getDefaultColorIndex(name); - - if (index >= 0) { - return defaultColors[index]; - } - - Integer ii = (Integer) colors.get(name); - if (ii != null) { - return ii.intValue(); - } - - return -1; - - //return (index >= 0) ? defaultColors[index] : ((Integer)colors.get(name)).intValue(); - } - - private static final int getDefaultColorIndex(String s) { - int id; - final int -// #string_id_map# -// Should be real index plus one due to auto switch generator limitations - Id_aliceblue = 1, - Id_antiquewhite = 2, - Id_aqua = 3, - Id_aquamarine = 4, - Id_azure = 5, - Id_beige = 6, - Id_bisque = 7, - Id_black = 8, - Id_blanchedalmond = 9, - Id_blue = 10, - Id_blueviolet = 11, - Id_brown = 12, - Id_burlywood = 13, - Id_cadetblue = 14, - Id_chartreuse = 15, - Id_chocolate = 16, - Id_coral = 17, - Id_cornflowerblue = 18, - Id_cornsilk = 19, - Id_crimson = 20, - Id_cyan = 21, - Id_darkblue = 22, - Id_darkcyan = 23, - Id_darkgoldenrod = 24, - Id_darkgray = 25, - Id_darkgreen = 26, - Id_darkgrey = 27, - Id_darkkhaki = 28, - Id_darkmagenta = 29, - Id_darkolivegreen = 30, - Id_darkorange = 31, - Id_darkorchid = 32, - Id_darkred = 33, - Id_darksalmon = 34, - Id_darkseagreen = 35, - Id_darkslateblue = 36, - Id_darkslategray = 37, - Id_darkslategrey = 38, - Id_darkturquoise = 39, - Id_darkviolet = 40, - Id_deeppink = 41, - Id_deepskyblue = 42, - Id_dimgray = 43, - Id_dimgrey = 44, - Id_dodgerblue = 45, - Id_firebrick = 46, - Id_floralwhite = 47, - Id_forestgreen = 48, - Id_fuchsia = 49, - Id_gainsboro = 50, - Id_ghostwhite = 51, - Id_gold = 52, - Id_goldenrod = 53, - Id_gray = 54, - Id_grey = 55, - Id_green = 56, - Id_greenyellow = 57, - Id_honeydew = 58, - Id_hotpink = 59, - Id_indianred = 60, - Id_indigo = 61, - Id_ivory = 62, - Id_khaki = 63, - Id_lavender = 64, - Id_lavenderblush = 65, - Id_lawngreen = 66, - Id_lemonchiffon = 67, - Id_lightblue = 68, - Id_lightcoral = 69, - Id_lightcyan = 70, - Id_lightgoldenrodyellow = 71, - Id_lightgray = 72, - Id_lightgreen = 73, - Id_lightgrey = 74, - Id_lightpink = 75, - Id_lightsalmon = 76, - Id_lightseagreen = 77, - Id_lightskyblue = 78, - Id_lightslategray = 79, - Id_lightslategrey = 80, - Id_lightsteelblue = 81, - Id_lightyellow = 82, - Id_lime = 83, - Id_limegreen = 84, - Id_linen = 85, - Id_magenta = 86, - Id_maroon = 87, - Id_mediumaquamarine = 88, - Id_mediumblue = 89, - Id_mediumorchid = 90, - Id_mediumpurple = 91, - Id_mediumseagreen = 92, - Id_mediumslateblue = 93, - Id_mediumspringgreen = 94, - Id_mediumturquoise = 95, - Id_mediumvioletred = 96, - Id_midnightblue = 97, - Id_mintcream = 98, - Id_mistyrose = 99, - Id_moccasin = 100, - Id_navajowhite = 101, - Id_navy = 102, - Id_oldlace = 103, - Id_olive = 104, - Id_olivedrab = 105, - Id_orange = 106, - Id_orangered = 107, - Id_orchid = 108, - Id_palegoldenrod = 109, - Id_palegreen = 110, - Id_paleturquoise = 111, - Id_palevioletred = 112, - Id_papayawhip = 113, - Id_peachpuff = 114, - Id_peru = 115, - Id_pink = 116, - Id_plum = 117, - Id_powderblue = 118, - Id_purple = 119, - Id_red = 120, - Id_rosybrown = 121, - Id_royalblue = 122, - Id_saddlebrown = 123, - Id_salmon = 124, - Id_sandybrown = 125, - Id_seagreen = 126, - Id_seashell = 127, - Id_sienna = 128, - Id_silver = 129, - Id_skyblue = 130, - Id_slateblue = 131, - Id_slategray = 132, - Id_slategrey = 133, - Id_snow = 134, - Id_springgreen = 135, - Id_steelblue = 136, - Id_tan = 137, - Id_teal = 138, - Id_thistle = 139, - Id_tomato = 140, - Id_turquoise = 141, - Id_violet = 142, - Id_wheat = 143, - Id_white = 144, - Id_whitesmoke = 145, - Id_yellow = 146, - Id_yellowgreen = 147; - - // This is really cool as the look up is based string index commonality - // which greatly reduces the parse time. Should really update our - // main content parser to work this way. - -// #generated# Last update: 2001-10-19 16:09:43 CEST - L0: - { - id = 0; - String X = null; - int c; - L: - switch (s.length()) { - case 3: - c = s.charAt(0); - if (c == 'r') { - if (s.charAt(2) == 'd' && s.charAt(1) == 'e') { - id = Id_red; - break L0; - } - } else if (c == 't') { - if (s.charAt(2) == 'n' && s.charAt(1) == 'a') { - id = Id_tan; - break L0; - } - } - break L; - case 4: - switch (s.charAt(3)) { - case 'a': - X = "aqua"; - id = Id_aqua; - break L; - case 'd': - X = "gold"; - id = Id_gold; - break L; - case 'e': - c = s.charAt(0); - if (c == 'b') { - if (s.charAt(2) == 'u' && s.charAt(1) == 'l') { - id = Id_blue; - break L0; - } - } else if (c == 'l') { - if (s.charAt(2) == 'm' && s.charAt(1) == 'i') { - id = Id_lime; - break L0; - } - } - break L; - case 'k': - X = "pink"; - id = Id_pink; - break L; - case 'l': - X = "teal"; - id = Id_teal; - break L; - case 'm': - X = "plum"; - id = Id_plum; - break L; - case 'n': - X = "cyan"; - id = Id_cyan; - break L; - case 'u': - X = "peru"; - id = Id_peru; - break L; - case 'w': - X = "snow"; - id = Id_snow; - break L; - case 'y': - c = s.charAt(2); - if (c == 'a') { - if (s.charAt(0) == 'g' && s.charAt(1) == 'r') { - id = Id_gray; - break L0; - } - } else if (c == 'e') { - if (s.charAt(0) == 'g' && s.charAt(1) == 'r') { - id = Id_grey; - break L0; - } - } else if (c == 'v') { - if (s.charAt(0) == 'n' && s.charAt(1) == 'a') { - id = Id_navy; - break L0; - } - } - break L; - } - break L; - case 5: - switch (s.charAt(0)) { - case 'a': - X = "azure"; - id = Id_azure; - break L; - case 'b': - c = s.charAt(4); - if (c == 'e') { - X = "beige"; - id = Id_beige; - } else if (c == 'k') { - X = "black"; - id = Id_black; - } else if (c == 'n') { - X = "brown"; - id = Id_brown; - } - break L; - case 'c': - X = "coral"; - id = Id_coral; - break L; - case 'g': - X = "green"; - id = Id_green; - break L; - case 'i': - X = "ivory"; - id = Id_ivory; - break L; - case 'k': - X = "khaki"; - id = Id_khaki; - break L; - case 'l': - X = "linen"; - id = Id_linen; - break L; - case 'o': - X = "olive"; - id = Id_olive; - break L; - case 'w': - c = s.charAt(4); - if (c == 'e') { - X = "white"; - id = Id_white; - } else if (c == 't') { - X = "wheat"; - id = Id_wheat; - } - break L; - } - break L; - case 6: - switch (s.charAt(3)) { - case 'a': - X = "tomato"; - id = Id_tomato; - break L; - case 'h': - X = "orchid"; - id = Id_orchid; - break L; - case 'i': - X = "indigo"; - id = Id_indigo; - break L; - case 'l': - c = s.charAt(0); - if (c == 'v') { - X = "violet"; - id = Id_violet; - } else if (c == 'y') { - X = "yellow"; - id = Id_yellow; - } - break L; - case 'm': - X = "salmon"; - id = Id_salmon; - break L; - case 'n': - c = s.charAt(0); - if (c == 'o') { - X = "orange"; - id = Id_orange; - } else if (c == 's') { - X = "sienna"; - id = Id_sienna; - } - break L; - case 'o': - X = "maroon"; - id = Id_maroon; - break L; - case 'p': - X = "purple"; - id = Id_purple; - break L; - case 'q': - X = "bisque"; - id = Id_bisque; - break L; - case 'v': - X = "silver"; - id = Id_silver; - break L; - } - break L; - case 7: - switch (s.charAt(3)) { - case 'b': - X = "skyblue"; - id = Id_skyblue; - break L; - case 'e': - X = "magenta"; - id = Id_magenta; - break L; - case 'g': - c = s.charAt(5); - if (c == 'a') { - X = "dimgray"; - id = Id_dimgray; - } else if (c == 'e') { - X = "dimgrey"; - id = Id_dimgrey; - } - break L; - case 'h': - X = "fuchsia"; - id = Id_fuchsia; - break L; - case 'k': - X = "darkred"; - id = Id_darkred; - break L; - case 'l': - X = "oldlace"; - id = Id_oldlace; - break L; - case 'm': - X = "crimson"; - id = Id_crimson; - break L; - case 'p': - X = "hotpink"; - id = Id_hotpink; - break L; - case 's': - X = "thistle"; - id = Id_thistle; - break L; - } - break L; - case 8: - switch (s.charAt(4)) { - case 'a': - X = "moccasin"; - id = Id_moccasin; - break L; - case 'b': - X = "darkblue"; - id = Id_darkblue; - break L; - case 'c': - X = "darkcyan"; - id = Id_darkcyan; - break L; - case 'g': - c = s.charAt(6); - if (c == 'a') { - X = "darkgray"; - id = Id_darkgray; - } else if (c == 'e') { - X = "darkgrey"; - id = Id_darkgrey; - } - break L; - case 'h': - X = "seashell"; - id = Id_seashell; - break L; - case 'n': - X = "lavender"; - id = Id_lavender; - break L; - case 'p': - X = "deeppink"; - id = Id_deeppink; - break L; - case 'r': - X = "seagreen"; - id = Id_seagreen; - break L; - case 's': - X = "cornsilk"; - id = Id_cornsilk; - break L; - case 'y': - X = "honeydew"; - id = Id_honeydew; - break L; - } - break L; - case 9: - switch (s.charAt(0)) { - case 'a': - X = "aliceblue"; - id = Id_aliceblue; - break L; - case 'b': - X = "burlywood"; - id = Id_burlywood; - break L; - case 'c': - c = s.charAt(1); - if (c == 'a') { - X = "cadetblue"; - id = Id_cadetblue; - } else if (c == 'h') { - X = "chocolate"; - id = Id_chocolate; - } - break L; - case 'd': - c = s.charAt(8); - if (c == 'i') { - X = "darkkhaki"; - id = Id_darkkhaki; - } else if (c == 'n') { - X = "darkgreen"; - id = Id_darkgreen; - } - break L; - case 'f': - X = "firebrick"; - id = Id_firebrick; - break L; - case 'g': - c = s.charAt(8); - if (c == 'd') { - X = "goldenrod"; - id = Id_goldenrod; - } else if (c == 'o') { - X = "gainsboro"; - id = Id_gainsboro; - } - break L; - case 'i': - X = "indianred"; - id = Id_indianred; - break L; - case 'l': - switch (s.charAt(5)) { - case 'b': - X = "lightblue"; - id = Id_lightblue; - break L; - case 'c': - X = "lightcyan"; - id = Id_lightcyan; - break L; - case 'g': - c = s.charAt(7); - if (c == 'a') { - X = "lightgray"; - id = Id_lightgray; - } else if (c == 'e') { - X = "lightgrey"; - id = Id_lightgrey; - } - break L; - case 'p': - X = "lightpink"; - id = Id_lightpink; - break L; - case 'r': - c = s.charAt(1); - if (c == 'a') { - X = "lawngreen"; - id = Id_lawngreen; - } else if (c == 'i') { - X = "limegreen"; - id = Id_limegreen; - } - break L; - } - break L; - case 'm': - c = s.charAt(8); - if (c == 'e') { - X = "mistyrose"; - id = Id_mistyrose; - } else if (c == 'm') { - X = "mintcream"; - id = Id_mintcream; - } - break L; - case 'o': - c = s.charAt(8); - if (c == 'b') { - X = "olivedrab"; - id = Id_olivedrab; - } else if (c == 'd') { - X = "orangered"; - id = Id_orangered; - } - break L; - case 'p': - c = s.charAt(8); - if (c == 'f') { - X = "peachpuff"; - id = Id_peachpuff; - } else if (c == 'n') { - X = "palegreen"; - id = Id_palegreen; - } - break L; - case 'r': - c = s.charAt(8); - if (c == 'e') { - X = "royalblue"; - id = Id_royalblue; - } else if (c == 'n') { - X = "rosybrown"; - id = Id_rosybrown; - } - break L; - case 's': - c = s.charAt(7); - if (c == 'a') { - X = "slategray"; - id = Id_slategray; - } else if (c == 'e') { - X = "slategrey"; - id = Id_slategrey; - } else if (c == 'u') { - c = s.charAt(1); - if (c == 'l') { - X = "slateblue"; - id = Id_slateblue; - } else if (c == 't') { - X = "steelblue"; - id = Id_steelblue; - } - } - break L; - case 't': - X = "turquoise"; - id = Id_turquoise; - break L; - } - break L; - case 10: - switch (s.charAt(8)) { - case 'a': - X = "lightcoral"; - id = Id_lightcoral; - break L; - case 'e': - c = s.charAt(0); - if (c == 'b') { - X = "blueviolet"; - id = Id_blueviolet; - } else if (c == 'd') { - X = "darkviolet"; - id = Id_darkviolet; - } else if (c == 'l') { - X = "lightgreen"; - id = Id_lightgreen; - } - break L; - case 'g': - X = "darkorange"; - id = Id_darkorange; - break L; - case 'i': - c = s.charAt(0); - if (c == 'd') { - X = "darkorchid"; - id = Id_darkorchid; - } else if (c == 'p') { - X = "papayawhip"; - id = Id_papayawhip; - } - break L; - case 'k': - X = "whitesmoke"; - id = Id_whitesmoke; - break L; - case 'n': - X = "aquamarine"; - id = Id_aquamarine; - break L; - case 'o': - X = "darksalmon"; - id = Id_darksalmon; - break L; - case 's': - X = "chartreuse"; - id = Id_chartreuse; - break L; - case 't': - X = "ghostwhite"; - id = Id_ghostwhite; - break L; - case 'u': - c = s.charAt(0); - if (c == 'd') { - X = "dodgerblue"; - id = Id_dodgerblue; - } else if (c == 'm') { - X = "mediumblue"; - id = Id_mediumblue; - } else if (c == 'p') { - X = "powderblue"; - id = Id_powderblue; - } - break L; - case 'w': - X = "sandybrown"; - id = Id_sandybrown; - break L; - } - break L; - case 11: - switch (s.charAt(5)) { - case 'a': - X = "darkmagenta"; - id = Id_darkmagenta; - break L; - case 'e': - X = "saddlebrown"; - id = Id_saddlebrown; - break L; - case 'g': - X = "springgreen"; - id = Id_springgreen; - break L; - case 'k': - X = "deepskyblue"; - id = Id_deepskyblue; - break L; - case 'l': - X = "floralwhite"; - id = Id_floralwhite; - break L; - case 'o': - X = "navajowhite"; - id = Id_navajowhite; - break L; - case 's': - X = "lightsalmon"; - id = Id_lightsalmon; - break L; - case 't': - X = "forestgreen"; - id = Id_forestgreen; - break L; - case 'w': - X = "yellowgreen"; - id = Id_yellowgreen; - break L; - case 'y': - c = s.charAt(0); - if (c == 'g') { - X = "greenyellow"; - id = Id_greenyellow; - } else if (c == 'l') { - X = "lightyellow"; - id = Id_lightyellow; - } - break L; - } - break L; - case 12: - switch (s.charAt(7)) { - case 'g': - X = "darkseagreen"; - id = Id_darkseagreen; - break L; - case 'i': - X = "lemonchiffon"; - id = Id_lemonchiffon; - break L; - case 'r': - X = "mediumorchid"; - id = Id_mediumorchid; - break L; - case 't': - X = "midnightblue"; - id = Id_midnightblue; - break L; - case 'u': - X = "mediumpurple"; - id = Id_mediumpurple; - break L; - case 'w': - X = "antiquewhite"; - id = Id_antiquewhite; - break L; - case 'y': - X = "lightskyblue"; - id = Id_lightskyblue; - break L; - } - break L; - case 13: - switch (s.charAt(9)) { - case 'b': - X = "darkslateblue"; - id = Id_darkslateblue; - break L; - case 'g': - c = s.charAt(11); - if (c == 'a') { - X = "darkslategray"; - id = Id_darkslategray; - } else if (c == 'e') { - X = "darkslategrey"; - id = Id_darkslategrey; - } - break L; - case 'l': - X = "lavenderblush"; - id = Id_lavenderblush; - break L; - case 'n': - c = s.charAt(0); - if (c == 'd') { - X = "darkgoldenrod"; - id = Id_darkgoldenrod; - } else if (c == 'p') { - X = "palegoldenrod"; - id = Id_palegoldenrod; - } - break L; - case 'o': - c = s.charAt(0); - if (c == 'd') { - X = "darkturquoise"; - id = Id_darkturquoise; - } else if (c == 'p') { - X = "paleturquoise"; - id = Id_paleturquoise; - } - break L; - case 'r': - X = "lightseagreen"; - id = Id_lightseagreen; - break L; - case 't': - X = "palevioletred"; - id = Id_palevioletred; - break L; - } - break L; - case 14: - switch (s.charAt(6)) { - case 'e': - X = "blanchedalmond"; - id = Id_blanchedalmond; - break L; - case 'i': - X = "darkolivegreen"; - id = Id_darkolivegreen; - break L; - case 'l': - c = s.charAt(12); - if (c == 'a') { - X = "lightslategray"; - id = Id_lightslategray; - } else if (c == 'e') { - X = "lightslategrey"; - id = Id_lightslategrey; - } - break L; - case 'o': - X = "cornflowerblue"; - id = Id_cornflowerblue; - break L; - case 's': - X = "mediumseagreen"; - id = Id_mediumseagreen; - break L; - case 't': - X = "lightsteelblue"; - id = Id_lightsteelblue; - break L; - } - break L; - case 15: - c = s.charAt(6); - if (c == 's') { - X = "mediumslateblue"; - id = Id_mediumslateblue; - } else if (c == 't') { - X = "mediumturquoise"; - id = Id_mediumturquoise; - } else if (c == 'v') { - X = "mediumvioletred"; - id = Id_mediumvioletred; - } - break L; - case 16: - X = "mediumaquamarine"; - id = Id_mediumaquamarine; - break L; - case 17: - X = "mediumspringgreen"; - id = Id_mediumspringgreen; - break L; - case 20: - X = "lightgoldenrodyellow"; - id = Id_lightgoldenrodyellow; - break L; - } - if (X != null && X != s && !X.equals(s)) id = 0; - } -// #/generated# -// #/string_id_map# - return id - 1; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Defs.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Defs.java deleted file mode 100644 index 710bb628aa..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Defs.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; - - -public class Defs { - - private static final Logger logger = - Logger.getLogger(Defs.class.toString()); - - /** - * Equivalent to property(name, null) - */ - public static String property(String name) { - return property(name, null); - } - - /** - * Return value for system property name or * - * defaultValue if the property does not exist * or a security - * manager denies access to it - */ - public static String property(String name, String defaultValue) { - try { - return System.getProperty(name, defaultValue); - } catch (SecurityException ex) { - // recal method so that property change takes effect - logger.log(Level.FINE, "Security exception, property could not be set.", ex); - } - return defaultValue; - } - - - /** - * Return value for system property name parsed as int or * - * defaultValue if the property does not exist * or a security - * manager denies access to it - */ - public static int intProperty(String name, int defaultValue) { - String value = property(name); - if (value != null) { - try { - return Integer.parseInt(value); - } catch (NumberFormatException ex) { - logger.log(Level.FINE, "Failed to parse property.", ex); - } - } - return defaultValue; - } - - /** - * Return value for system property name parsed as double or * - * defaultValue if the property does not exist * or a security - * manager denies access to it - */ - public static double doubleProperty(String name, double defaultValue) { - String value = property(name); - if (value != null) { - try { - return Double.parseDouble(value); - } catch (NumberFormatException ex) { - logger.log(Level.FINE, "Failed to parse property.", ex); - } - } - return defaultValue; - } - - - /** - * Shortcut for booleanProperty(name, false) - */ - public static boolean booleanProperty(String name) { - return booleanProperty(name, false); - } - - /** - * If security manager allow access to the system property name * and - * it exists, then return true if it is set to yes, true * and - * false if set to no, false. Otherwise returns * - * defaultValue - */ - public static boolean booleanProperty(String name, boolean defaultValue) { - String value = property(name); - if (value != null) { - switch (value.length()) { - case 2: - if ("no".equals(value.toLowerCase())) return false; - break; - case 3: - if ("yes".equals(value.toLowerCase())) return true; - break; - case 4: - if ("true".equals(value.toLowerCase())) return true; - break; - case 5: - if ("false".equals(value.toLowerCase())) return false; - break; - } - } - return defaultValue; - } - - /** - * Alias to property(String name) - */ - public static String sysProperty(String name) { - return property(name); - } - - /** - * Alias to property(String name, String defaultValue) - */ - public static String sysProperty(String name, String defaultValue) { - return property(name, defaultValue); - } - - /** - * Alias to intProperty(String name, int defaultValue) - */ - public static int sysPropertyInt(String name, int defaultValue) { - return intProperty(name, defaultValue); - } - - /** - * Alias to doubleProperty(String name, double defaultValue) - */ - public static double sysPropertyDouble(String name, double defaultValue) { - return doubleProperty(name, defaultValue); - } - - /** - * Alias to booleanProperty(String name) - */ - public static boolean sysPropertyBoolean(String name) { - return booleanProperty(name); - } - - /** - * Alias to booleanProperty(String name, boolean defaultValue) - */ - public static boolean sysPropertyBoolean(String name, - boolean defaultValue) { - return booleanProperty(name, defaultValue); - } - - /** - * Set system property to value. * If SecurityManager denies - * property modification, silently ignore * property change. * if value is - * null, property won't be set. - */ - public static void setProperty(String property, Object value) { - try { - Properties prop = System.getProperties(); - if (value != null) { - prop.put(property, value); - } - } catch (SecurityException ex) { - // recall method so that property change takes effect - logger.log(Level.FINE, "Security exception, property could not be set.", ex); - } - } - - - /** - * Set system property to value. * If SecurityManager denies - * property modification, print debug trace - */ - public static void setSystemProperty(String name, String value) { - setProperty(name, value); - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/FontUtil.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/FontUtil.java deleted file mode 100644 index c9efef10bc..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/FontUtil.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -/** - * Font utility contains a bunch of commonly used font utility methods. - * - * @since 3.1 - */ -public class FontUtil { - - // awt font style lookup style tokens - private static final String AWT_STYLE_BOLD_ITAL = "boldital"; - private static final String AWT_STYLE_DEMI_ITAL = "demiital"; - private static final String AWT_STYLE_ITAL = "ital"; - private static final String AWT_STYLE_OBLI = "obli"; - - // Font style names used to derive family names. - private static final String STYLE_BOLD_ITALIC = "bolditalic"; - private static final String STYLE_DEMI_ITALIC = "demiitalic"; - private static final String STYLE_BOLD = "bold"; - private static final String STYLE_DEMI = "demi"; - private static final String STYLE_ITALIC = "italic"; - private static final String STYLE_BLACK = "black"; - - /** - * Utility method which maps know style strings to an AWT font style constants. - * The style attribute read as follows from the java.awt.font constructor: - *

        - * the style constant for the Font The style argument is an integer bitmask - * that may be PLAIN, or a bitwise union of BOLD and/or ITALIC - * (for example, ITALIC or BOLD|ITALIC). If the style argument does not - * conform to one of the expected integer bitmasks then the style is set to PLAIN. - *
      - * - * @param name base name of font. - * @return integer representing dffs - */ - public static int guessAWTFontStyle(String name) { - name = name.toLowerCase(); - int decorations = 0; - if (name.indexOf(AWT_STYLE_BOLD_ITAL) > 0 || - name.indexOf(AWT_STYLE_DEMI_ITAL) > 0) { - decorations |= java.awt.Font.BOLD | java.awt.Font.ITALIC; - } else if (name.indexOf(STYLE_BOLD) > 0 || - name.indexOf(STYLE_BLACK) > 0 || - name.indexOf(STYLE_DEMI) > 0) { - decorations |= java.awt.Font.BOLD; - } else if (name.indexOf(AWT_STYLE_ITAL) > 0 || - name.indexOf(AWT_STYLE_OBLI) > 0) { - decorations |= java.awt.Font.ITALIC; - } else { - decorations |= java.awt.Font.PLAIN; - } - return decorations; - } - - /** - * Utility method for guessing a font family name from its base name. Font - * names are usually made up of a familyName followed by a style - * name. For example: - *

      - *

        - *
      • Arial,BoldItalic
      • - *
      • Times-Bold"
      • - *
      • Arial BoldItalic
      • - *
      • TimesNewRomansBold
      • - *
      - * - * @param name base name of font. - * @return guess of the base fonts name. - */ - public static String guessFamily(String name) { - String fam = name; - int inx; - // Family name usually precedes a common, ie. "Arial,BoldItalic" - if ((inx = fam.indexOf(',')) > 0) - fam = fam.substring(0, inx); - // Family name usually precedes a dash, example "Times-Bold", - if ((inx = fam.lastIndexOf('-')) > 0) - fam = fam.substring(0, inx); - // Family name with no dash or commas, example "TimesNewRomansBold" or - // "CalibriBoldItalic" - if ((inx = fam.toLowerCase().lastIndexOf(STYLE_BOLD_ITALIC)) > 0) { - fam = fam.substring(0, inx); - } else if ((inx = fam.toLowerCase().lastIndexOf(STYLE_DEMI_ITALIC)) > 0) { - fam = fam.substring(0, inx); - } else if ((inx = fam.toLowerCase().lastIndexOf(STYLE_BOLD)) > 0) { - fam = fam.substring(0, inx); - } else if ((inx = fam.toLowerCase().lastIndexOf(STYLE_ITALIC)) > 0) { - fam = fam.substring(0, inx); - } else if ((inx = fam.toLowerCase().lastIndexOf(STYLE_BLACK)) > 0) { - fam = fam.substring(0, inx); - } - return fam; - } - - /** - * For a font subset, the PostScript name of the font—the value of the font’s - * BaseFont entry and the font descriptor’s FontName entry shall begin with - * a tag followed by a plus sign (+). The tag shall consist of exactly six - * uppercase letters; the choice of letters is arbitrary, but different - * subsets in the same PDF file shall have different tags - *

      - * This method will strip the font subset from the font name and return - * the font name. - * - * @param name font name to strip of subset name. - * @return bare font name. - */ - public static String removeBaseFontSubset(String name) { - if (name != null && name.length() > 7) { - int i = name.indexOf('+') + 1; - return name.substring(i, name.length()); - } else { - return name; - } - } - - /** - * Utility method for normailing strings, to lowercase and remove any spaces. - * - * @param name base name of font - * @return normalized copy of string. - */ - public static String normalizeString(String name) { - name = guessFamily(name); - StringBuilder normalized = new StringBuilder(name.toLowerCase()); - for (int k = normalized.length() - 1; k >= 0; k--) { - if (normalized.charAt(k) == 32) { - normalized.deleteCharAt(k); - k--; - } - } - return normalized.toString(); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/GraphicsRenderingHints.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/GraphicsRenderingHints.java deleted file mode 100644 index b406969305..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/GraphicsRenderingHints.java +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -import java.awt.*; - -/** - *

      The GraphicsRenderingHints class provides a central place for - * storing Java2D rendering hints settings. The - * GraphicsRenderingHints object is used to apply different rendering - * hints for printing and screen presentation when rending a Page's content.

      - *

      - *

      The "screen" and "print" configuration are configurable with system properties. - * See the ICEpdf Developer's Guide for more information about configuring - * these properites.

      - * - * @author Mark Collette - * @since 2.0 - */ -public class GraphicsRenderingHints { - - /** - * Constant used to specify rendering hint specific to screen rendering. - */ - public static final int SCREEN = 1; - - /** - * Constant used to specify rendering hint specific to print rendering. - */ - public static final int PRINT = 2; - - /** - * Gets the singleton representation of this object. - * - * @return a reference to the singleton GraphicsRenderingHints object. - */ - public static synchronized GraphicsRenderingHints getDefault() { - if (singleton == null) { - singleton = new GraphicsRenderingHints(); - } - return singleton; - } - - // singleton value of this object. - private static GraphicsRenderingHints singleton; - - /** - * Load values from the system properties if any and assign defaults. - */ - private GraphicsRenderingHints() { - setFromProperties(); - } - - /** - * Gets the rendering hints for either the SCREEN or PRINT mode. - * - * @param hintType SCREEN or PRINT, if incorrectly specified PRINT settings - * are returned. - * @return RenderingHints used by Java2D graphics context. - */ - public RenderingHints getRenderingHints(final int hintType) { - if (hintType == SCREEN) - return (RenderingHints) screenHints.clone(); - else - return (RenderingHints) printHints.clone(); - } - - public Color getPageBackgroundColor(final int hintType) { - if (hintType == SCREEN) - return screenBackground; - else - return printBackground; - } - - /** - * Rereads the system properties responsible for setting the rendering hints - * for both the PRINT and SCREEN modes. - */ - public synchronized void reset() { - setFromProperties(); - } - - /** - * Utility method for reading the system properties. - */ - private void setFromProperties() { - // grab System properties for screen rendering attributes - String property = Defs.sysProperty("org.icepdf.core.screen.alphaInterpolation"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_ALPHA_INTERPOLATION_QUALITY")) { - screenAlphaInterpolocation = RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY; - } else if (property.equalsIgnoreCase("VALUE_ALPHA_INTERPOLATION_DEFAULT")) { - screenAlphaInterpolocation = RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_ALPHA_INTERPOLATION_SPEED")) { - screenAlphaInterpolocation = RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED; - } - } - property = Defs.sysProperty("org.icepdf.core.screen.antiAliasing"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_ANTIALIAS_DEFAULT")) { - screenAntiAliasing = RenderingHints.VALUE_ANTIALIAS_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_ANTIALIAS_ON")) { - screenAntiAliasing = RenderingHints.VALUE_ANTIALIAS_ON; - } else if (property.equalsIgnoreCase("VALUE_ANTIALIAS_OFF")) { - screenAntiAliasing = RenderingHints.VALUE_ANTIALIAS_OFF; - } - } - property = Defs.sysProperty("org.icepdf.core.screen.textAntiAliasing"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_TEXT_ANTIALIAS_DEFAULT")) { - screenTextAntiAliasing = RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_TEXT_ANTIALIAS_ON")) { - screenTextAntiAliasing = RenderingHints.VALUE_TEXT_ANTIALIAS_ON; - } else if (property.equalsIgnoreCase("VALUE_TEXT_ANTIALIAS_OFF")) { - screenTextAntiAliasing = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF; - } - } - property = Defs.sysProperty("org.icepdf.core.screen.colorRender"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_COLOR_RENDER_DEFAULT")) { - screenColorRendering = RenderingHints.VALUE_COLOR_RENDER_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_COLOR_RENDER_QUALITY")) { - screenColorRendering = RenderingHints.VALUE_COLOR_RENDER_QUALITY; - } else if (property.equalsIgnoreCase("VALUE_COLOR_RENDER_SPEED")) { - screenColorRendering = RenderingHints.VALUE_COLOR_RENDER_SPEED; - } - } - property = Defs.sysProperty("org.icepdf.core.screen.dither"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_DITHER_DEFAULT")) { - screenDithering = RenderingHints.VALUE_DITHER_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_DITHER_DISABLE")) { - screenDithering = RenderingHints.VALUE_DITHER_DISABLE; - } else if (property.equalsIgnoreCase("VALUE_DITHER_ENABLE")) { - screenDithering = RenderingHints.VALUE_DITHER_ENABLE; - } - } - property = Defs.sysProperty("org.icepdf.core.screen.fractionalmetrics"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_FRACTIONALMETRICS_DEFAULT")) { - screenFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_FRACTIONALMETRICS_ON")) { - screenFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_ON; - } else if (property.equalsIgnoreCase("VALUE_FRACTIONALMETRICS_OFF")) { - screenFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_OFF; - } - } - property = Defs.sysProperty("org.icepdf.core.screen.interpolation"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_INTERPOLATION_BICUBIC")) { - screenInterPolation = RenderingHints.VALUE_INTERPOLATION_BICUBIC; - } else if (property.equalsIgnoreCase("VALUE_INTERPOLATION_BILINEAR")) { - screenInterPolation = RenderingHints.VALUE_INTERPOLATION_BILINEAR; - } else if (property.equalsIgnoreCase("VALUE_INTERPOLATION_NEAREST_NEIGHBOR")) { - screenInterPolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; - } - } - property = Defs.sysProperty("org.icepdf.core.screen.render"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_RENDER_DEFAULT")) { - screenRendering = RenderingHints.VALUE_RENDER_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_RENDER_QUALITY")) { - screenRendering = RenderingHints.VALUE_RENDER_QUALITY; - } else if (property.equalsIgnoreCase("VALUE_RENDER_SPEED")) { - screenRendering = RenderingHints.VALUE_RENDER_SPEED; - } - } - property = Defs.sysProperty("org.icepdf.core.screen.stroke"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_STROKE_DEFAULT")) { - screenStrokeControl = RenderingHints.VALUE_STROKE_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_STROKE_NORMALIZE")) { - screenStrokeControl = RenderingHints.VALUE_STROKE_NORMALIZE; - } else if (property.equalsIgnoreCase("VALUE_STROKE_PURE")) { - screenStrokeControl = RenderingHints.VALUE_STROKE_PURE; - } - } - property = Defs.sysProperty("org.icepdf.core.screen.background"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_DRAW_WHITE_BACKGROUND")) { - screenBackground = Color.white; - } else if (property.equalsIgnoreCase("VALUE_DRAW_NO_BACKGROUND")) { - screenBackground = null; - } - } - - screenHints = new RenderingHints( - RenderingHints.KEY_ALPHA_INTERPOLATION, screenAlphaInterpolocation); - screenHints.put(RenderingHints.KEY_ANTIALIASING, screenAntiAliasing); - screenHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, screenTextAntiAliasing); - screenHints.put(RenderingHints.KEY_COLOR_RENDERING, screenColorRendering); - screenHints.put(RenderingHints.KEY_DITHERING, screenDithering); - screenHints.put(RenderingHints.KEY_FRACTIONALMETRICS, screenFractionalMetrics); - screenHints.put(RenderingHints.KEY_INTERPOLATION, screenInterPolation); - screenHints.put(RenderingHints.KEY_RENDERING, screenRendering); - screenHints.put(RenderingHints.KEY_STROKE_CONTROL, screenStrokeControl); - - - // grab System properties for print rendering attributes - property = Defs.sysProperty("org.icepdf.core.print.alphaInterpolation"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_ALPHA_INTERPOLATION_QUALITY")) { - printAlphaInterpolocation = RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY; - } else if (property.equalsIgnoreCase("VALUE_ALPHA_INTERPOLATION_DEFAULT")) { - printAlphaInterpolocation = RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_ALPHA_INTERPOLATION_SPEED")) { - printAlphaInterpolocation = RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED; - } - } - property = Defs.sysProperty("org.icepdf.core.print.antiAliasing"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_ANTIALIAS_DEFAULT")) { - printAntiAliasing = RenderingHints.VALUE_ANTIALIAS_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_ANTIALIAS_ON")) { - printAntiAliasing = RenderingHints.VALUE_ANTIALIAS_ON; - } else if (property.equalsIgnoreCase("VALUE_ANTIALIAS_OFF")) { - printAntiAliasing = RenderingHints.VALUE_ANTIALIAS_OFF; - } - } - property = Defs.sysProperty("org.icepdf.core.print.textAntiAliasing"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_TEXT_ANTIALIAS_DEFAULT")) { - printTextAntiAliasing = RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_TEXT_ANTIALIAS_ON")) { - printTextAntiAliasing = RenderingHints.VALUE_TEXT_ANTIALIAS_ON; - } else if (property.equalsIgnoreCase("VALUE_TEXT_ANTIALIAS_OFF")) { - printTextAntiAliasing = RenderingHints.VALUE_TEXT_ANTIALIAS_OFF; - } - } - property = Defs.sysProperty("org.icepdf.core.print.colorRender"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_COLOR_RENDER_DEFAULT")) { - printColorRendering = RenderingHints.VALUE_COLOR_RENDER_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_COLOR_RENDER_QUALITY")) { - printColorRendering = RenderingHints.VALUE_COLOR_RENDER_QUALITY; - } else if (property.equalsIgnoreCase("VALUE_COLOR_RENDER_SPEED")) { - printColorRendering = RenderingHints.VALUE_COLOR_RENDER_SPEED; - } - } - property = Defs.sysProperty("org.icepdf.core.print.dither"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_DITHER_DEFAULT")) { - printDithering = RenderingHints.VALUE_DITHER_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_DITHER_DISABLE")) { - printDithering = RenderingHints.VALUE_DITHER_DISABLE; - } else if (property.equalsIgnoreCase("VALUE_DITHER_ENABLE")) { - printDithering = RenderingHints.VALUE_DITHER_ENABLE; - } - } - property = Defs.sysProperty("org.icepdf.core.print.fractionalmetrics"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_FRACTIONALMETRICS_DEFAULT")) { - printFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_FRACTIONALMETRICS_ON")) { - printFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_ON; - } else if (property.equalsIgnoreCase("VALUE_FRACTIONALMETRICS_OFF")) { - printFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_OFF; - } - } - property = Defs.sysProperty("org.icepdf.core.print.interpolation"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_INTERPOLATION_BICUBIC")) { - printInterPolation = RenderingHints.VALUE_INTERPOLATION_BICUBIC; - } else if (property.equalsIgnoreCase("VALUE_INTERPOLATION_BILINEAR")) { - printInterPolation = RenderingHints.VALUE_INTERPOLATION_BILINEAR; - } else if (property.equalsIgnoreCase("VALUE_INTERPOLATION_NEAREST_NEIGHBOR")) { - printInterPolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; - } - } - property = Defs.sysProperty("org.icepdf.core.print.render"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_RENDER_DEFAULT")) { - printRendering = RenderingHints.VALUE_RENDER_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_RENDER_QUALITY")) { - printRendering = RenderingHints.VALUE_RENDER_QUALITY; - } else if (property.equalsIgnoreCase("VALUE_RENDER_SPEED")) { - printRendering = RenderingHints.VALUE_RENDER_SPEED; - } - } - property = Defs.sysProperty("org.icepdf.core.print.stroke"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_STROKE_DEFAULT")) { - printStrokeControl = RenderingHints.VALUE_STROKE_DEFAULT; - } else if (property.equalsIgnoreCase("VALUE_STROKE_NORMALIZE")) { - printStrokeControl = RenderingHints.VALUE_STROKE_NORMALIZE; - } else if (property.equalsIgnoreCase("VALUE_STROKE_PURE")) { - printStrokeControl = RenderingHints.VALUE_STROKE_PURE; - } - } - property = Defs.sysProperty("org.icepdf.core.print.background"); - if (property != null) { - if (property.equalsIgnoreCase("VALUE_DRAW_WHITE_BACKGROUND")) { - printBackground = Color.white; - } else if (property.equalsIgnoreCase("VALUE_DRAW_NO_BACKGROUND")) { - printBackground = null; - } - } - - printHints = new RenderingHints( - RenderingHints.KEY_ALPHA_INTERPOLATION, printAlphaInterpolocation); - printHints.put(RenderingHints.KEY_ANTIALIASING, printAntiAliasing); - printHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, printTextAntiAliasing); - printHints.put(RenderingHints.KEY_COLOR_RENDERING, printColorRendering); - printHints.put(RenderingHints.KEY_DITHERING, printDithering); - printHints.put(RenderingHints.KEY_FRACTIONALMETRICS, printFractionalMetrics); - printHints.put(RenderingHints.KEY_INTERPOLATION, printInterPolation); - printHints.put(RenderingHints.KEY_RENDERING, printRendering); - printHints.put(RenderingHints.KEY_STROKE_CONTROL, printStrokeControl); - } - - - /** - * This hint controls how partially-transparent - * drawing operations are composited. The default value is - * VALUE_ALPHA_INTERPOLATION_QUALITY - */ - Object printAlphaInterpolocation = RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY; - /** - * This hint controls if text and images will be drawn using anitialiasing. - * The default value is VALUE_ANTIALIAS_ON - */ - Object printAntiAliasing = RenderingHints.VALUE_ANTIALIAS_ON; - /** - * This hint controls if text will be drawn using anitialiasing. This property - * can not set to ON unless printAntiAliasing is set to ON - * The default value is VALUE_ANTIALIAS_ON - */ - Object printTextAntiAliasing = RenderingHints.VALUE_TEXT_ANTIALIAS_ON; - /** - * This hint controls colour rendering quality. - * The default value is VALUE_COLOR_RENDER_QUALITY - */ - Object printColorRendering = RenderingHints.VALUE_COLOR_RENDER_QUALITY; - /** - * This hint controls dithering of an image. - * The default value is VALUE_DITHER_ENABLE - */ - Object printDithering = RenderingHints.VALUE_DITHER_ENABLE; - /** - * This hint controls fractional Metrics calculations for drawing text. - * The default value is VALUE_FRACTIONALMETRICS_ON - */ - Object printFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_ON; - /** - * This hint controls image interpolation. - * The default value is VALUE_INTERPOLATION_BILINEAR - */ - Object printInterPolation = RenderingHints.VALUE_INTERPOLATION_BILINEAR; - /** - * This hint controls rendering quality. - * The default value is VALUE_RENDER_QUALITY - */ - Object printRendering = RenderingHints.VALUE_RENDER_QUALITY; - /** - * This hint controls stroke quality. - * The default value is VALUE_STROKE_NORMALIZE - */ - Object printStrokeControl = RenderingHints.VALUE_STROKE_NORMALIZE; - /** - * This hints controls if the Page will paint a white background before drawing itself. - * The default value is Color.white - */ - Color printBackground = Color.white; - - // take care of Screen mode default values. The general ideal is to lower - // qality where possible to encresase drawing speed. - - /** - * This hint controls how partially-transparent drawing operations are - * composited. The default value is - * VALUE_ALPHA_INTERPOLATION_SPEED - */ - Object screenAlphaInterpolocation = RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED; - /** - * This hint controls if text and images will be drawn using anitialiasing. - * The default value is VALUE_ANTIALIAS_ON - */ - Object screenAntiAliasing = RenderingHints.VALUE_ANTIALIAS_ON; - /** - * This hint controls if text will be drawn using anitialiasing. This property - * can not set to ON unless printAntiAliasing is set to ON - * The default value is VALUE_ANTIALIAS_ON - */ - Object screenTextAntiAliasing = RenderingHints.VALUE_TEXT_ANTIALIAS_ON; - /** - * This hint controls colour rendering quality. - * The default value is VALUE_COLOR_RENDER_SPEED - */ - Object screenColorRendering = RenderingHints.VALUE_COLOR_RENDER_SPEED; - /** - * This hint controls dithering of an image. - * The default value is VALUE_DITHER_ENABLE - */ - Object screenDithering = RenderingHints.VALUE_DITHER_DEFAULT; - /** - * This hint controls fractional Metrics calculations for drawing text. - * The default value is VALUE_FRACTIONALMETRICS_ON - */ - Object screenFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_ON; - /** - * This hint controls image interpolation. - * The default value is VALUE_INTERPOLATION_BICUBIC - */ - Object screenInterPolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; - /** - * This hint controls rendering quality. - * The default value is VALUE_RENDER_QUALITY - */ - Object screenRendering = RenderingHints.VALUE_RENDER_SPEED; - /** - * This hint controls stroke quality. - * The default value is VALUE_STROKE_NORMALIZE - */ - Object screenStrokeControl = RenderingHints.VALUE_STROKE_PURE; - /** - * This hints controls if the Page will paint a white background before drawing itself. - * The default value is Color.white - */ - Color screenBackground = Color.white; - - private RenderingHints screenHints; - private RenderingHints printHints; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/HexDumper.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/HexDumper.java deleted file mode 100644 index 4ff80ad6f3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/HexDumper.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -import java.io.*; - -/** - * Utility class for formatting byte[] data in the nicely organized hex dump format. In a hex dump, - * each byte is represented as a two-digit hexadecimal number. Each row consists of 16 bytes separated - * by white space. Each row is also pre appended with the memory address and post appended with the ASCII - * text for bytes. - */ -public class HexDumper { - - public static final int BYTE_PER_ROW = 16; - - private PrintStream printStream; - private int currentLineLength; - private int currentByte; - private int offset; - private byte[] thisLine = new byte[BYTE_PER_ROW]; - - /** - * Dump the hex bytes for the given input. - * - * @param inputBytes bytes to format at a hex dump. - * @return hex dump formatted byte data. - */ - public String dump(byte[] inputBytes) { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - ByteArrayInputStream inputStream = new ByteArrayInputStream(inputBytes); - try { - this.dump(inputStream, outputStream); - } catch (Exception e) { - throw new IllegalStateException("Could not read input stream. "); - } - return outputStream.toString(); - } - - /** - * Dump the hex bytes for the given input to the specified out stream. - * - * @param inputBytes bytes to convert to hex dump format. - * @param outputStream output bytes where hex dump is written to. - * @throws IOException - */ - public void dump(InputStream inputBytes, OutputStream outputStream) throws IOException { - byte[] lineBytes = new byte[BYTE_PER_ROW]; - reset(outputStream); - int lineLength; - do { - lineLength = readFully(inputBytes, lineBytes); - if (lineLength == 0) { - break; - } - writeMemoryOffset(lineLength); - // write out the bytes. - for (int i = 0; i < lineLength; i++) { - writeHexBytes(lineBytes, i); - } - writeASCIISummary(); - } while (lineLength >= BYTE_PER_ROW); - } - - /** - * Reads a line of byte data, ~16 bytes. - * - * @param inputBytes input array > 16 bytes. - * @param lineBytes output data. - * @return length of bytes copied. - * @throws IOException - */ - private int readFully(InputStream inputBytes, byte[] lineBytes) throws IOException { - for (int i = 0; i < lineBytes.length; ++i) { - int j = inputBytes.read(); - if (j == -1) { - return i; - } - lineBytes[i] = (byte) j; - } - return lineBytes.length; - } - - private void reset(OutputStream var1) throws IOException { - offset = 0; - printStream = new PrintStream(var1); - } - - /** - * Write the memory offset to the start of each line. - * - * @param offsetLength line length. - * @throws IOException - */ - protected void writeMemoryOffset(int offsetLength) throws IOException { - convertByteToHex(printStream, (byte) (offset >>> 8 & 255)); - convertByteToHex(printStream, (byte) (offset & 255)); - printStream.print(": "); - currentByte = 0; - currentLineLength = offsetLength; - } - - /** - * Writes out the byte[] one byte at a time converted to hex. - * - * @param byteArray array of data - * @param length length of bytes of convert. - * @throws IOException - */ - private void writeHexBytes(byte[] byteArray, int length) throws IOException { - thisLine[this.currentByte] = byteArray[length]; - convertByteToHex(this.printStream, byteArray[length]); - printStream.print(" "); - currentByte++; - if (currentByte == 8) { - printStream.print(" "); - } - } - - /** - * Write ASCII data out to end of pritn stream. - * - * @throws IOException - */ - private void writeASCIISummary() throws IOException { - // add some column padding - if (currentLineLength < BYTE_PER_ROW) { - for (int i = currentLineLength; i < BYTE_PER_ROW; i++) { - printStream.print(" "); - if (i == 7) { - printStream.print(" "); - } - } - } - printStream.print(" "); - // write out he ASCII version of the bytes which may or may not having meaning to end user. - for (int i = 0; i < currentLineLength; i++) { - if (this.thisLine[i] >= 32 && this.thisLine[i] <= 122) { - printStream.write(this.thisLine[i]); - } else { - printStream.print("."); - } - } - printStream.println(); - offset += currentLineLength; - } - - /** - * Convert byteValue to a two char hex number. - * - * @param printStream output stream. - * @param byteValue byte value to convert. - */ - private void convertByteToHex(PrintStream printStream, byte byteValue) { - // convert the first 4 bites to hex - char hexChar = (char) (byteValue >> 4 & 15); - if (hexChar > 9) { - hexChar = (char) (hexChar - 10 + 65); - } else { - hexChar = (char) (hexChar + 48); - } - printStream.write(hexChar); - // covert next 4 bits to hex. - hexChar = (char) (byteValue & 15); - if (hexChar > 9) { - hexChar = (char) (hexChar - 10 + 65); - } else { - hexChar = (char) (hexChar + 48); - } - printStream.write(hexChar); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/LazyObjectLoader.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/LazyObjectLoader.java deleted file mode 100644 index 6499328768..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/LazyObjectLoader.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -import org.icepdf.core.io.SeekableInput; -import org.icepdf.core.pobjects.*; - -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * @author Mark Collette - * @since 2.0 - */ -public class LazyObjectLoader { - - private static final Logger logger = - Logger.getLogger(LazyObjectLoader.class.toString()); - - private Library library; - private SeekableInput seekableInput; - private CrossReference crossReference; - protected SoftLRUCache leastRecentlyUsed; - private final Object leastRectlyUsedLock = new Object(); - private final Object streamLock = new Object(); - - public LazyObjectLoader(Library lib, SeekableInput seekableInput, CrossReference xref) { - library = lib; - this.seekableInput = seekableInput; - crossReference = xref; - leastRecentlyUsed = new SoftLRUCache(256); - } - - /** - * Loads an object via it's reference. Stream object data is initialized - * so that we can release the file lock more quickly. - * - * @param reference object reference - * @return found object; dictionary, stream or pobject. - */ - public Object loadObject(Reference reference) { - if (reference == null || library == null || crossReference == null) - return null; - int objNum = reference.getObjectNumber(); - CrossReference.Entry entry = crossReference.getEntryForObject(objNum); - if (entry == null) - return null; - // base cross reference lookup. - - if (entry instanceof CrossReference.UsedEntry) { - try { - if (seekableInput != null) { - synchronized (streamLock) { - CrossReference.UsedEntry usedEntry = (CrossReference.UsedEntry) entry; - long position = usedEntry.getFilePositionOfObject(); - seekableInput.beginThreadAccess(); - long savedPosition = seekableInput.getAbsolutePosition(); - seekableInput.seekAbsolute(position); - Parser parser = new Parser(seekableInput); - Object ob = parser.getObject(library); - seekableInput.seekAbsolute(savedPosition); - return ob; - } - } - } catch (Exception e) { - logger.log(Level.SEVERE, - "Error loading object instance: " + reference.toString(), e); - } finally { - if (seekableInput != null) - seekableInput.endThreadAccess(); - } - } - // compressed cross reference. - else if (entry instanceof CrossReference.CompressedEntry) { - try { - CrossReference.CompressedEntry compressedEntry = (CrossReference.CompressedEntry) entry; - int objectStreamsObjectNumber = compressedEntry.getObjectNumberOfContainingObjectStream(); - int objectIndex = compressedEntry.getIndexWithinObjectStream(); - Reference objectStreamRef = new Reference(objectStreamsObjectNumber, 0); - ObjectStream objectStream; - synchronized (leastRectlyUsedLock) { - objectStream = leastRecentlyUsed.get(objectStreamRef); - } - - if (objectStream == null) { - synchronized (streamLock) { - objectStream = (ObjectStream) library.getObject(objectStreamRef); - } - if (objectStream != null) { - synchronized (leastRectlyUsedLock) { - leastRecentlyUsed.put(objectStreamRef, objectStream); - } - } - } - - if (objectStream != null) { - synchronized (streamLock) { - return objectStream.loadObject(library, objectIndex); - } - } - } catch (Exception e) { - logger.log(Level.SEVERE, - "Error loading object instance: " + reference.toString(), e); - } - } - - return null; - } - - public boolean haveEntry(Reference reference) { - if (reference == null || crossReference == null) - return false; - int objNum = reference.getObjectNumber(); - CrossReference.Entry entry = crossReference.getEntryForObject(objNum); - return (entry != null); - } - - public PTrailer loadTrailer(long position) { - PTrailer trailer = null; - try { - if (seekableInput != null) { - seekableInput.beginThreadAccess(); - long savedPosition = seekableInput.getAbsolutePosition(); - seekableInput.seekAbsolute(position); - Parser parser = new Parser(seekableInput); - Object obj = parser.getObject(library); - if (obj instanceof PObject) - obj = ((PObject) obj).getObject(); - trailer = (PTrailer) obj; - if (trailer != null) - trailer.setPosition(position); - seekableInput.seekAbsolute(savedPosition); - } - } catch (Exception e) { - logger.log(Level.FINE, - "Error loading PTrailer instance: " + position, e); - } finally { - if (seekableInput != null) - seekableInput.endThreadAccess(); - } - return trailer; - } - - /** - * Get the documents library object. - * - * @return documents library object. - */ - public Library getLibrary() { - return library; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Library.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Library.java deleted file mode 100644 index e934e55bc4..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Library.java +++ /dev/null @@ -1,806 +0,0 @@ -/* -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -import org.icepdf.core.io.SeekableInput; -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.acroform.InteractiveForm; -import org.icepdf.core.pobjects.acroform.SignatureHandler; -import org.icepdf.core.pobjects.fonts.Font; -import org.icepdf.core.pobjects.fonts.FontDescriptor; -import org.icepdf.core.pobjects.graphics.ICCBased; -import org.icepdf.core.pobjects.graphics.ImagePool; -import org.icepdf.core.pobjects.security.SecurityManager; - -import java.awt.geom.Rectangle2D; -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.List; -import java.util.Set; -import java.util.concurrent.*; -import java.util.logging.Logger; - -/** - *

      The Library class acts a central repository for the access - * of PDF objects in a document. The Library class has many utility methods - * which are designed to access PDF objects as easily as possible. The - * Library class has direct access to the PDF file and loads the - * needed objects from the file system when needed.

      - * - * @since 1.0 - */ -public class Library { - - private static final Logger log = - Logger.getLogger(Library.class.toString()); - - protected static ThreadPoolExecutor commonThreadPool; - protected static ThreadPoolExecutor imageThreadPool; - - protected static int commonPoolThreads; - protected static int imagePoolThreads; - private static final long KEEP_ALIVE_TIME = 90; - - static { - try { - commonPoolThreads = - Defs.intProperty("org.icepdf.core.library.threadPoolSize", 2); - if (commonPoolThreads < 1) { - commonPoolThreads = 2; - } - } catch (NumberFormatException e) { - log.warning("Error reading buffered scale factor"); - } - - try { - // todo make ImageReference call interruptible and then we can get rid of this pool. - imagePoolThreads = - Defs.intProperty("org.icepdf.core.library.imageThreadPoolSize", 2); - if (imagePoolThreads < 1) { - imagePoolThreads = 2; - } - } catch (NumberFormatException e) { - log.warning("Error reading buffered scale factor"); - } - - log.fine("Starting ICEpdf Thread Pools: " + - (commonPoolThreads + imagePoolThreads) + - " threads."); - initializeThreadPool(); - } - - // new incremental file loader class. - private LazyObjectLoader lazyObjectLoader; - private ConcurrentHashMap> refs = - new ConcurrentHashMap>(1024); - private ConcurrentHashMap> lookupReference2ICCBased = - new ConcurrentHashMap>(256); - // Instead of keeping Names names, Dictionary dests, we keep - // a reference to the Catalog, which actually owns them - private Catalog catalog; - - private SecurityManager securityManager; - - // handles signature validation and signing. - private SignatureHandler signatureHandler; - - // signature permissions - private Permissions permissions; - - private SeekableInput documentInput; - - - // state manager reference needed by most classes to properly managed state - // changes and new object creation - public StateManager stateManager; - - private boolean isEncrypted; - private boolean isLinearTraversal; - private ImagePool imagePool; - - /** - * Sets a document loader for the library. - * - * @param lol loader object. - */ - public void setLazyObjectLoader(LazyObjectLoader lol) { - lazyObjectLoader = lol; - } - - /** - * Gets the document's trailer. - * - * @param position byte offset of the trailer in the PDF file. - * @return trailer dictionary - */ - public PTrailer getTrailerByFilePosition(long position) { - if (lazyObjectLoader == null) - return null; - return lazyObjectLoader.loadTrailer(position); - } - - /** - * Gets the object specified by the reference. - * - * @param reference reference to a PDF object in the document structure. - * @return PDF object dictionary that the reference refers to. Null if the - * object reference can not be found. - */ - public Object getObject(Reference reference) { - Object ob; - while (true) { - WeakReference obRef = refs.get(reference); - // check stateManager first to allow for annotations to be injected - // from a separate file. - if (stateManager != null) { - if (stateManager.contains(reference)) { - ob = stateManager.getChange(reference); - if (ob instanceof PObject){ - return ((PObject) ob).getObject(); - } - return ob; - } - } - ob = obRef != null ? obRef.get() : null; - if (ob == null && lazyObjectLoader != null) { - ob = lazyObjectLoader.loadObject(reference); - } - if (ob instanceof PObject) { - return ((PObject) ob).getObject(); - } else if (ob instanceof Reference) { - reference = (Reference) ob; - } else { - break; - } - } - return ob; - } - - /** - * Utility method for displaying debug info related to PDF object loading. - * - * @param ob object to show debug information for - */ - private void printObjectDebug(Object ob) { - if (ob == null) { - log.finer("null object found"); - } else if (ob instanceof PObject) { - PObject tmp = (PObject) ob; - log.finer(tmp.getReference() + " " + tmp.toString()); - } else if (ob instanceof Dictionary) { - Dictionary tmp = (Dictionary) ob; - log.finer(tmp.getPObjectReference() + " " + tmp.toString()); - } else { - log.finer(ob.getClass() + " " + ob.toString()); - } - } - - /** - * Gets the PDF object specified by the key in the dictionary - * entries. If the key value is a reference, the object that the reference - * points to is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return PDF object that the key references. - * @see #getObjectReference(java.util.HashMap, Name) - */ - public Object getObject(HashMap dictionaryEntries, Name key) { - if (dictionaryEntries == null) { - return null; - } - Object o = dictionaryEntries.get(key); - if (o == null) - return null; - if (o instanceof Reference) { - o = getObject((Reference) o); - } - return o; - } - - /** - * Test to see if the given key is a reference and not an inline dictinary - * - * @param dictionaryEntries dictionary to test - * @param key dictionary key - * @return true if the key value exists and is a reference, false if the - * dictionaryEntries are null or the key references an inline dictionary - */ - public boolean isReference(HashMap dictionaryEntries, Name key) { - return dictionaryEntries != null && - dictionaryEntries.get(key) instanceof Reference; - - } - - /** - * Gets the reference association of the key if any. This method is usual - * used in combination with #isReference to get and assign the Reference - * for a given PObject. - * - * @param dictionaryEntries dictionary to search in. - * @param key key to search for in dictionary. - * @return reference of the object that key points if any. Null if the key - * points to an inline dictionary and not a reference. - */ - public Reference getReference(HashMap dictionaryEntries, Name key) { - Object ref = dictionaryEntries.get(key); - if (ref instanceof Reference) { - return (Reference) ref; - } else { - return null; - } - } - - /** - * Gets the state manager class which keeps track of changes PDF objects. - * - * @return document state manager - */ - public StateManager getStateManager() { - return stateManager; - } - - /** - * Sets the document state manager so that all object can access the - * state manager via the central library instance. - * - * @param stateManager reference to the state change class - */ - public void setStateManager(StateManager stateManager) { - this.stateManager = stateManager; - } - - /** - * Gets the PDF object that the referenceObject references. - * - * @param referenceObject reference object. - * @return PDF object that referenceObject references. If - * referenceObject is not an instance of a Reference, the - * origional referenceObject is returned. - */ - public Object getObject(Object referenceObject) { - if (referenceObject instanceof Reference) { - return getObject((Reference) referenceObject); - } - return referenceObject; - } - - /** - * Tests if the given key will return a non-null PDF object from the - * specified dictionary entries. A null PDF object would result if no - * PDF object could be found with the specified key. - * - * @param dictionaryEntries dictionary entries - * @param key dictionary key - * @return true, if the key's value is non-null PDF object; false, otherwise. - */ - public boolean isValidEntry(HashMap dictionaryEntries, Name key) { - if (dictionaryEntries == null) { - return false; - } - Object o = dictionaryEntries.get(key); - return o != null && (!(o instanceof Reference) || isValidEntry((Reference) o)); - } - - /** - * Tests if there exists a cross-reference entry for this reference. - * - * @param reference reference to a PDF object in the document structure. - * @return true, if a cross-reference entry exists for this reference; false, otherwise. - */ - public boolean isValidEntry(Reference reference) { - WeakReference ob = refs.get(reference); - return (ob != null && ob.get() != null) || - lazyObjectLoader != null && - lazyObjectLoader.haveEntry(reference); - } - - /** - * Gets a Number specified by the key in the dictionary - * entries. If the key value is a reference, the Number object that the - * reference points to is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return Number object if a valid key; null, if the key does not point - * to Number or is invalid. - */ - public Number getNumber(HashMap dictionaryEntries, Name key) { - Object o = getObject(dictionaryEntries, key); - if (o instanceof Number) - return (Number) o; - return null; - } - - /** - * Gets a Boolean specified by the key in the dictionary - * entries. If the key value is a reference, the Boolean object that the - * reference points to is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return Number object if a valid key; null, if the key does not point - * to Number or is invalid. - */ - public Boolean getBoolean(HashMap dictionaryEntries, Name key) { - Object o = getObject(dictionaryEntries, key); - if (o instanceof String) - return Boolean.valueOf((String) o); - else return o instanceof Boolean && (Boolean) o; - } - - /** - * Gets a float specified by the key in the dictionary - * entries. If the key value is a reference, the object that the - * reference points to is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return float value if a valid key; null, if the key does not point - * to a float or is invalid. - */ - public float getFloat(HashMap dictionaryEntries, Name key) { - Number n = getNumber(dictionaryEntries, key); - return (n != null) ? n.floatValue() : 0.0f; - } - - /** - * Gets an int specified by the key in the dictionary - * entries. If the key value is a reference, the object that the - * reference points to is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return int value if a valid key, null if the key does not point - * to an int or is invalid. - */ - public int getInt(HashMap dictionaryEntries, Name key) { - Number n = getNumber(dictionaryEntries, key); - return (n != null) ? n.intValue() : 0; - } - - /** - * Gets a float specified by the key in the dictionary - * entries. If the key value is a reference, the object that the - * reference points to is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return float value if a valid key; null, if the key does not point - * to a float or is invalid. - */ - public long getLong(HashMap dictionaryEntries, Name key) { - Number n = getNumber(dictionaryEntries, key); - return (n != null) ? n.longValue() : 0L; - } - - /** - * Gets a Name specified by the key in the dictionary - * entries. If the key value is a reference, the Name object that the - * reference points to is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return Name object if a valid key; null, if the key does not point - * to Name or is invalid. - */ - public Name getName(HashMap dictionaryEntries, Name key) { - Object o = getObject(dictionaryEntries, key); - if (o != null) { - if (o instanceof Name) { - return (Name) o; - } - } - return null; - } - - /** - * Gets a text string specified by the key in the dictionary - * entries. If the key value is a reference, the string object that the - * reference points to is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return string object if a valid key; null, if the key does not point - * to Name or is invalid. - */ - public String getString(HashMap dictionaryEntries, Name key) { - Object o = getObject(dictionaryEntries, key); - if (o != null) { - if (o instanceof String) { - return ((String) o); - } else if (o instanceof StringObject) { - return ((StringObject) o).getDecryptedLiteralString(securityManager); - } else if (o instanceof Name) { - return ((Name) o).getName(); - } - } - return null; - } - - /** - * Gets a dictionary specified by the key in the dictionary - * entries. If the key value is a reference, the dictionary object that the - * reference points to is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return dictionary object if a valid key; null, if the key does not point - * to dictionary or is invalid. - */ - @SuppressWarnings("unchecked") - public HashMap getDictionary(HashMap dictionaryEntries, Name key) { - Object o = getObject(dictionaryEntries, key); - if (o instanceof HashMap) { - return (HashMap) o; - } else if (o instanceof List) { - List v = (List) o; - HashMap h1 = new HashMap(); - for (Object o1 : v) { - if (o1 instanceof HashMap) { - h1.putAll((HashMap) o1); - } - } - return h1; - } - return null; - } - - public List getArray(HashMap dictionaryEntries, Name key) { - Object o = getObject(dictionaryEntries, key); - if (o instanceof List) { - return (List) o; - } - return null; - } - - /** - * Gets a rectangle specified by the key. The rectangle is already - * in the coordinate system of Java2D, and thus must be used carefully. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return rectangle in Java2D coordinate system. - */ - public Rectangle2D.Float getRectangle(HashMap dictionaryEntries, Name key) { - List v = (List) getObject(dictionaryEntries, key); - if (v != null) { - // s by default contains data in the Cartesian plain. - return new PRectangle(v).toJava2dCoordinates(); - } else { - return null; - } - } - - /** - * The Reference is to the Stream from which the ICC color space data - * is to be parsed. So, without this method, we would be making and - * initializing a new ICCBased object every time one was needed, since - * the Reference is not for the ICCBased object itself. - * - * @param ref Reference to Stream containing ICC color space data - * @return ICCBased color model object for the given reference - */ - public ICCBased getICCBased(Reference ref) { - ICCBased cs = null; - - WeakReference csRef = lookupReference2ICCBased.get(ref); - if (csRef != null) { - cs = csRef.get(); - } - - if (cs == null) { - Object obj = getObject(ref); - if (obj instanceof Stream) { - Stream stream = (Stream) obj; - cs = new ICCBased(this, stream); - lookupReference2ICCBased.put(ref, new WeakReference(cs)); - } - } - return cs; - } - - @SuppressWarnings("unchecked") - public Resources getResources(HashMap dictionaryEntries, Name key) { - if (dictionaryEntries == null) - return null; - Object ob = dictionaryEntries.get(key); - if (ob == null) - return null; - else if (ob instanceof Resources) - return (Resources) ob; - else if (ob instanceof Reference) { - Reference reference = (Reference) ob; - return getResources(reference); - } else if (ob instanceof HashMap) { - HashMap ht = (HashMap) ob; - Resources resources = new Resources(this, ht); - dictionaryEntries.put(key, resources); - return resources; - } - return null; - } - - public Resources getResources(Reference reference) { - Object object = getObject(reference); - if (object instanceof Resources) { - return (Resources) object; - } else if (object instanceof HashMap) { - HashMap ht = (HashMap) object; - Resources resources = new Resources(this, ht); - addObject(resources, reference); - return resources; - } - return null; - } - - /** - * Adds a PDF object and its respective object reference to the library. - * - * @param object PDF object to add. - * @param objectReference PDF object reference object. - */ - public void addObject(Object object, Reference objectReference) { - refs.put(objectReference, new WeakReference(object)); - } - - /** - * Removes an object from from the library. - * - * @param objetReference object reference to remove to library - */ - public void removeObject(Reference objetReference) { - if (objetReference != null) { - refs.remove(objetReference); - } - } - - /** - * Creates a new instance of a Library. - */ - public Library() { - // set Catalog memory Manager and cache manager. - imagePool = new ImagePool(); - signatureHandler = new SignatureHandler(); - } - - /** - * Sets a pointer to the orginal document input stream - * - * @param documentInput seekable inputstream. - */ - public void setDocumentInput(SeekableInput documentInput) { - this.documentInput = documentInput; - } - - /** - * Gets the SeekableInput of the document underlying bytes. - * - * @return document bytes. - */ - public SeekableInput getDocumentInput() { - return documentInput; - } - - /** - * Gets the PDF object specified by the key in the dictionary - * entries. If the key value is a reference it is returned. - * - * @param dictionaryEntries the dictionary entries to look up the key in. - * @param key string value representing the dictionary key. - * @return the Reference specified by the PDF key. If the key is invalid - * or does not reference a Reference object, null is returned. - * @see #getObject(java.util.HashMap, Name) - */ - public Reference getObjectReference(HashMap dictionaryEntries, - Name key) { - if (dictionaryEntries == null) { - return null; - } - Object o = dictionaryEntries.get(key); - if (o == null) - return null; - Reference currentRef = null; - while (o != null && (o instanceof Reference)) { - currentRef = (Reference) o; - o = getObject(currentRef); - } - return currentRef; - } - - /** - * Indicates that document is encrypted using Adobe Standard Encryption. - * - * @return true if the document is encrypted, false otherwise. - */ - public boolean isEncrypted() { - return isEncrypted; - } - - /** - * Gets the document's security manger. - * - * @return document's security manager if the document is encrypted, null - * otherwise. - */ - public SecurityManager getSecurityManager() { - return securityManager; - } - - public void setSecurityManager(SecurityManager securityManager) { - this.securityManager = securityManager; - } - - public SignatureHandler getSignatureHandler() { - return signatureHandler; - } - - /** - * Set a documents permissions for a given certificate of signature, optional. - * The permission should also be used with the encryption permissions if present - * to configure the viewer permissions. - * - * @return permission object if present, otherwise null. - */ - public Permissions getPermissions() { - return permissions; - } - - public void setPermissions(Permissions permissions) { - this.permissions = permissions; - } - - /** - * Set the document is encrypted flag. - * - * @param flag true, if the document is encrypted; false, otherwize. - */ - public void setEncrypted(boolean flag) { - isEncrypted = flag; - } - - /** - * When we fail to load the required xref tables or streams that are - * needed to access the objects in the PDF, then we simply go to the - * beginning of the file and read in all of the objects into memory, - * which we call linear traversal. - */ - public void setLinearTraversal() { - isLinearTraversal = true; - } - - /** - * There are several implications from using linear traversal, which - * affect how we parse the PDF objects, and maintain them in memory, - * so those sections of code need to check this flag here. - * - * @return If PDF was parsed via linear traversal - */ - public boolean isLinearTraversal() { - return isLinearTraversal; - } - - /** - * Gets the document's catalog. - * - * @return document's catalog. - */ - public Catalog getCatalog() { - return catalog; - } - - /** - * Sets the document's catalog. Normally only accessed by the document's parser. - * - * @param c document catalog object. - */ - public void setCatalog(Catalog c) { - catalog = c; - } - - /** - * Checks the Catalog for an interactive Forms dictionary and if found the resources object - * is used for a font lookup. - * - * @param fontName font name to look for. - * @return font font, null otherwise. - */ - public Font getInteractiveFormFont(String fontName) { - InteractiveForm form = getCatalog().getInteractiveForm(); - if (form != null && form.getResources() != null) { - Resources resources = form.getResources(); - return resources.getFont(new Name(fontName)); - } - return null; - } - - /** - * Utility/demo functionality to clear all font and font descriptor - * resources. The library will re-fetch the font resources in question - * when needed again. - */ - public void disposeFontResources() { - Set test = refs.keySet(); - for (Reference ref : test) { - WeakReference reference = refs.get(ref); - Object tmp = reference != null ? reference.get() : null; - if (tmp instanceof Font || tmp instanceof FontDescriptor) { - refs.remove(ref); - } - } - } - - public ImagePool getImagePool() { - return imagePool; - } - - public static void initializeThreadPool() { - - log.fine("Starting ICEpdf Thread Pool: " + commonPoolThreads + " threads."); - commonThreadPool = new ThreadPoolExecutor( - commonPoolThreads, commonPoolThreads, KEEP_ALIVE_TIME, TimeUnit.SECONDS, - new LinkedBlockingQueue()); - // set a lower thread priority - commonThreadPool.setThreadFactory(new ThreadFactory() { - public Thread newThread(java.lang.Runnable command) { - Thread newThread = new Thread(command); - newThread.setName("ICEpdf-thread-pool"); - newThread.setPriority(Thread.NORM_PRIORITY); - newThread.setDaemon(true); - return newThread; - } - }); - - imageThreadPool = new ThreadPoolExecutor( - imagePoolThreads, imagePoolThreads, KEEP_ALIVE_TIME, TimeUnit.SECONDS, - new LinkedBlockingQueue()); - // set a lower thread priority - imageThreadPool.setThreadFactory(new ThreadFactory() { - public Thread newThread(java.lang.Runnable command) { - Thread newThread = new Thread(command); - newThread.setName("ICEpdf-thread-image-pool"); - newThread.setPriority(Thread.NORM_PRIORITY); - newThread.setDaemon(true); - return newThread; - } - }); - } - - public static void shutdownThreadPool() { - // do a little clean up. - commonThreadPool.purge(); - commonThreadPool.shutdownNow(); - imageThreadPool.purge(); - imageThreadPool.shutdownNow(); - } - - public static void execute(Runnable runnable) { - try { - commonThreadPool.execute(runnable); - } catch (RejectedExecutionException e) { - log.severe("ICEpdf Common Thread Pool was shutdown!"); - } - } - - public static void executeImage(FutureTask callable) { - try { - imageThreadPool.execute(callable); - } catch (RejectedExecutionException e) { - log.severe("ICEpdf Common Thread Pool was shutdown!"); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Parser.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Parser.java deleted file mode 100644 index 993b4a9ae8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Parser.java +++ /dev/null @@ -1,1322 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -import org.icepdf.core.exceptions.PDFException; -import org.icepdf.core.io.*; -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.fonts.CMap; -import org.icepdf.core.pobjects.fonts.Font; -import org.icepdf.core.pobjects.fonts.FontDescriptor; -import org.icepdf.core.pobjects.fonts.FontFactory; -import org.icepdf.core.pobjects.graphics.TilingPattern; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Stack; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * put your documentation comment here - */ -public class Parser { - - private static final Logger logger = - Logger.getLogger(Parser.class.toString()); - - public static final int PARSE_MODE_NORMAL = 0; - public static final int PARSE_MODE_OBJECT_STREAM = 1; - - // InputStream has to support mark(), reset(), and markSupported() - // DO NOT close this, since we have two cases: read everything up front, and progressive reads -// private BufferedMarkedInputStream reader; - - private InputStream reader; - boolean lastTokenHString = false; - private Stack stack = new Stack(); - private int parseMode; - private boolean isTrailer; - private int linearTraversalOffset; - - public Parser(SeekableInput r) { - this(r, PARSE_MODE_NORMAL); - } - - public Parser(SeekableInput r, int pm) { -// reader = new BufferedMarkedInputStream(r.getInputStream()); - reader = r.getInputStream(); - parseMode = pm; - } - - public Parser(InputStream r) { - this(r, PARSE_MODE_NORMAL); - } - - public Parser(InputStream r, int pm) { - reader = new BufferedMarkedInputStream(r); - parseMode = pm; - } - - /** - * Get an object from the pdf input DataInputStream. - * - * @param library all found objects in the pdf document - * @return the next object in the DataInputStream. Null is returned - * if there are no more objects left in the DataInputStream or - * a I/O error is encountered. - * @throws PDFException error getting object from library - */ - public Object getObject(Library library) throws PDFException { - int deepnessCount = 0; - boolean inObject = false; // currently parsing tokens in an object - boolean complete = false; // flag used for do loop. - Object nextToken; - Reference objectReference = null; - try { - reader.mark(1); - // capture the byte offset of this object so we can rebuild - // the cross reference entries for lazy loading after CG. - if (library.isLinearTraversal() && reader instanceof BufferedMarkedInputStream) { - linearTraversalOffset = ((BufferedMarkedInputStream) reader).getMarkedPosition(); - } - do { //while (!complete); - // keep track of currently parsed objects reference - // get the next token inside the object stream - try { - nextToken = getToken(); - // commented out for performance reasons - //Thread.yield(); - } catch (IOException e) { - // eat it as it is what is expected -// logger.warning("IO reading error."); - return null; - } - - // check for specific primative object types returned by getToken() - if (nextToken instanceof StringObject - || nextToken instanceof Name - || nextToken instanceof Number) { - // Very Important, store the PDF object reference information, - // as it is needed when to decrypt an encrypted string. - if (nextToken instanceof StringObject) { - StringObject tmp = (StringObject) nextToken; - tmp.setReference(objectReference); - } - stack.push(nextToken); - } - // mark that we have entered a object declaration - else if (nextToken.equals("obj")) { - // a rare parsing error is that endobj is missing, so we need - // to make sure if an object has been parsed that we don't loose it. - if (inObject) { - // pop off the object and ref number - stack.pop(); - stack.pop(); - // return the passed over object on the stack. - return addPObject(library, objectReference); - } - // Since we can return objects on "endstream", then we can - // leave straggling "endobj", which would deepnessCount--, - // even though they're done in a separate method invocation - // Hence, "obj" does /deepnessCount = 1/ instead of /deepnessCount++/ - deepnessCount = 0; - inObject = true; - Number generationNumber = (Number) (stack.pop()); - Number objectNumber = (Number) (stack.pop()); - objectReference = new Reference(objectNumber, - generationNumber); - } - // mark that we have reached the end of the object - else if (nextToken.equals("endobj") || nextToken.equals("endobject") - || nextToken.equals("enbobj")) { - if (inObject) { - // set flag to false, as we are done parsing an Object - inObject = false; - // return PObject, - return addPObject(library, objectReference); - // else, we ignore as the endStream token also returns a - // PObject. - } else { -// return null; - } - } - // found endstream object, we will return the PObject containing - // the stream as there can be no further tokens. This addresses - // an incorrect a syntax error with OpenOffice document where - // the endobj tag is missing on some Stream objects. - else if (nextToken.equals("endstream")) { - deepnessCount--; - // do nothing, but don't add it to the stack - if (inObject) { - inObject = false; - // return PObject, - return addPObject(library, objectReference); - } - } - - // found a stream object, streams are allways defined inside - // of a object so we will always have a dictionary (hash) that - // has the length and filter definitions in it - else if (nextToken.equals("stream")) { - deepnessCount++; - // pop dictionary that defines the stream - Object tmp = stack.pop(); - HashMap streamHash; - if (tmp instanceof Dictionary) { - streamHash = ((Dictionary) tmp).getEntries(); - } else { - streamHash = (HashMap) tmp; - } - // find the length of the stream - int streamLength = library.getInt(streamHash, Dictionary.LENGTH_KEY); - - SeekableInputConstrainedWrapper streamInputWrapper; - try { - // a stream token's end of line marker can be either: - // - a carriage return and a line feed - // - just a line feed, and not by a carriage return alone. - - // check for carriage return and line feed, but reset if - // just a carriage return as it is a valid stream byte - reader.mark(2); - - // alway eat a 13,against the spec but we have several examples of this. - int curChar = reader.read(); - if (curChar == 13) { - reader.mark(1); - if (reader.read() != 10) { - reader.reset(); - } - } - // always eat a 10 - else if (curChar == 10) { - // eat the stream character - } - // reset the rest - else { - reader.reset(); - } - - if (reader instanceof SeekableInput) { - SeekableInput streamDataInput = (SeekableInput) reader; - long filePositionOfStreamData = streamDataInput.getAbsolutePosition(); - long lengthOfStreamData; - // If the stream has a length that we can currently use - // such as a R that has been parsed or an integer - if (streamLength > 0) { - lengthOfStreamData = streamLength; - streamDataInput.seekRelative(streamLength); - // Read any extraneous data coming after the length, but before endstream - lengthOfStreamData += skipUntilEndstream(null); - } else { - lengthOfStreamData = captureStreamData(null); - } - streamInputWrapper = new SeekableInputConstrainedWrapper( - streamDataInput, filePositionOfStreamData, lengthOfStreamData); - } else { // reader is just regular InputStream (BufferedInputStream) - // stream NOT SeekableInput - ConservativeSizingByteArrayOutputStream out; - // If the stream in from a regular InputStream, - // then the PDF was probably linearly traversed, - // in which case it doesn't matter if they have - // specified the stream length, because we can't - // trust that anyway - if (!library.isLinearTraversal() && streamLength > 0) { - byte[] buffer = new byte[streamLength]; - int totalRead = 0; - while (totalRead < buffer.length) { - int currRead = reader.read(buffer, totalRead, buffer.length - totalRead); - if (currRead <= 0) - break; - totalRead += currRead; - } - out = new ConservativeSizingByteArrayOutputStream( - buffer); - // Read any extraneous data coming after the length, but before endstream - skipUntilEndstream(out); - } - // if stream doesn't have a length, read the stream - // until end stream has been found - else { - // stream NOT SeekableInput No trusted streamLength"); - out = new ConservativeSizingByteArrayOutputStream( - 16 * 1024); - captureStreamData(out); - } - - int size = out.size(); - out.trim(); - byte[] buffer = out.relinquishByteArray(); - - SeekableInput streamDataInput = new SeekableByteArrayInputStream(buffer); - long filePositionOfStreamData = 0L; - streamInputWrapper = new SeekableInputConstrainedWrapper( - streamDataInput, filePositionOfStreamData, size); - } - } catch (IOException e) { - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, "Error getting next object", e); - } - return null; - } - PTrailer trailer = null; - // set the stream know objects if possible - Stream stream = null; - Name type = (Name) library.getObject(streamHash, Dictionary.TYPE_KEY); - Name subtype = (Name) library.getObject(streamHash, Dictionary.SUBTYPE_KEY); - if (type != null) { - // found a xref stream which is made up it's own entry format - // different then an standard xref table, mainly used to - // access cross-reference entries but also to compress xref tables. - if (type.equals("XRef")) { - stream = new Stream(library, streamHash, streamInputWrapper); - stream.init(); - InputStream in = stream.getDecodedByteArrayInputStream(); - CrossReference xrefStream = new CrossReference(); - if (in != null) { - try { - xrefStream.addXRefStreamEntries(library, streamHash, in); - } finally { - try { - in.close(); - } catch (Throwable e) { - logger.log(Level.WARNING, "Error appending stream entries.", e); - } - } - } - - // XRef dict is both Trailer dict and XRef stream dict. - // PTrailer alters its dict, so copy it to keep everything sane - HashMap trailerHash = (HashMap) streamHash.clone(); - trailer = new PTrailer(library, trailerHash, null, xrefStream); - } else if (type.equals("ObjStm")) { - stream = new ObjectStream(library, streamHash, streamInputWrapper); - } else if (type.equals("XObject") && subtype.equals("Image")) { - stream = new ImageStream(library, streamHash, streamInputWrapper); - } - // new Tiling Pattern Object, will have a stream. - else if (type.equals("Pattern")) { - stream = new TilingPattern(library, streamHash, streamInputWrapper); - } - } - if (stream == null && subtype != null) { - // new form object - if (subtype.equals("Image")) { - stream = new ImageStream(library, streamHash, streamInputWrapper); - } else if (subtype.equals("Form") && !"Pattern".equals(type)) { - stream = new Form(library, streamHash, streamInputWrapper); - } else if (subtype.equals("Form") && "Pattern".equals(type)) { - stream = new TilingPattern(library, streamHash, streamInputWrapper); - } - } - if (trailer != null) { - stack.push(trailer); - } else { - // finally create a generic stream object which will be parsed - // at a later time - if (stream == null) { - stream = new Stream(library, streamHash, streamInputWrapper); - } - stack.push(stream); - // forcing a object return just encase the length is wrong - // and we don't get to the endstream. - return addPObject(library, objectReference); - } - } - // end if (stream) - - // boolean objects are added to stack - else if (nextToken.equals("true")) { - stack.push(true); - } else if (nextToken.equals("false")) { - stack.push(false); - } - // Indirect Reference object found - else if (nextToken.equals("R")) { - // generationNumber number important for revisions - Number generationNumber = (Number) (stack.pop()); - Number objectNumber = (Number) (stack.pop()); - stack.push(new Reference(objectNumber, - generationNumber)); - } else if (nextToken.equals("[")) { - deepnessCount++; - stack.push(nextToken); - } - // Found an array - else if (nextToken.equals("]")) { - deepnessCount--; - final int searchPosition = stack.search("["); - int size = searchPosition - 1; - if (size < 0) { - logger.warning("Negative array size, a malformed content " + - "stream has likely been encountered."); - size = 0; - } - List v = new ArrayList(size); - Object[] tmp = new Object[size]; - if (searchPosition > 0) { - for (int i = size - 1; i >= 0; i--) { - tmp[i] = stack.pop(); - } - // we need a mutable array so copy into an arrayList - // so we can't use Arrays.asList(). - for (int i = 0; i < size; i++) { - v.add(tmp[i]); - } - stack.pop(); // "[" - } else { - stack.clear(); - } - stack.push(v); - } else if (nextToken.equals("<<")) { - deepnessCount++; - stack.push(nextToken); - } - // Found a Dictionary - else if (nextToken.equals(">>")) { - deepnessCount--; - // check for extra >> which we want to ignore - if (!isTrailer && deepnessCount >= 0) { - if (!stack.isEmpty()) { - HashMap hashMap = new HashMap(); - Object obj = stack.pop(); - // put all of the dictionary definistion into the - // the hashTabl - while (!((obj instanceof String) - && (obj.equals("<<"))) && !stack.isEmpty()) { - Object key = stack.pop(); - hashMap.put(key, obj); - if (!stack.isEmpty()) { - obj = stack.pop(); - } else { - break; - } - } - obj = hashMap.get(Dictionary.TYPE_KEY); - if (obj == null) { - // PDF-927, incorrect /type def. - obj = hashMap.get(new Name("type")); - } - // Process the know first level dictionaries. - if (obj != null && obj instanceof Name) { - Name n = (Name) obj; - if (n.equals(Catalog.TYPE)) { - stack.push(new Catalog(library, hashMap)); - } else if (n.equals(PageTree.TYPE)) { - stack.push(new PageTree(library, hashMap)); - } else if (n.equals(Page.TYPE)) { - stack.push(new Page(library, hashMap)); - } else if (n.equals(Font.TYPE)) { - // do a quick check to make sure we don't have a fontDescriptor - // FontFile is specific to font descriptors. - boolean fontDescriptor = hashMap.get(FontDescriptor.FONT_FILE) != null || - hashMap.get(FontDescriptor.FONT_FILE_2) != null || - hashMap.get(FontDescriptor.FONT_FILE_3) != null; - if (!fontDescriptor) { - stack.push(FontFactory.getInstance() - .getFont(library, hashMap)); - } else { - stack.push(new FontDescriptor(library, hashMap)); - } - } else if (n.equals(FontDescriptor.TYPE)) { - stack.push(new FontDescriptor(library, hashMap)); - } else if (n.equals(CMap.TYPE)) { - stack.push(hashMap); - } else if (n.equals(Annotation.TYPE)) { - stack.push(Annotation.buildAnnotation(library, hashMap)); - } else if (n.equals(OptionalContentGroup.TYPE)) { - stack.push(new OptionalContentGroup(library, hashMap)); - } else if (n.equals(OptionalContentMembership.TYPE)) { - stack.push(new OptionalContentMembership(library, hashMap)); - } else - stack.push(hashMap); - } - // everything else gets pushed onto the stack - else { - stack.push(hashMap); - } - } - } else if (isTrailer && deepnessCount == 0) { - // we have an xref entry - HashMap hashMap = new HashMap(); - Object obj = stack.pop(); - // put all of the dictionary definition into the - // the new map. - while (!((obj instanceof String) - && (obj.equals("<<"))) && !stack.isEmpty()) { - Object key = stack.pop(); - hashMap.put(key, obj); - if (!stack.isEmpty()) { - obj = stack.pop(); - } else { - break; - } - } - return hashMap; - } - } - // found traditional XrefTable found in all documents. - else if (nextToken.equals("xref")) { - // parse out hte traditional - CrossReference xrefTable = new CrossReference(); - xrefTable.addXRefTableEntries(this); - stack.push(xrefTable); - } else if (nextToken.equals("trailer")) { - CrossReference xrefTable = null; - if (stack.peek() instanceof CrossReference) - xrefTable = (CrossReference) stack.pop(); - stack.clear(); - isTrailer = true; - HashMap trailerDictionary = (HashMap) getObject(library); - isTrailer = false; - return new PTrailer(library, trailerDictionary, xrefTable, null); - } - // comments - else if (nextToken instanceof String && - ((String) nextToken).startsWith("%")) { - // Comment, ignored for now - } - // corner case for encoder error "endobjxref" - else if (nextToken instanceof String && - ((String) nextToken).startsWith("endobj")) { - if (inObject) { - // set flag to false, as we are done parsing an Object - inObject = false; - // return PObject, - return addPObject(library, objectReference); - } - } - // everything else gets pushed onto the stack - else { - stack.push(nextToken); - } - if (parseMode == PARSE_MODE_OBJECT_STREAM && deepnessCount == 0 && stack.size() > 0) { - return stack.pop(); - } - } - while (!complete); - } catch (Exception e) { - logger.log(Level.WARNING, "Fatal error parsing PDF file stream.", e); - return null; - } - // return the top of the stack - return stack.pop(); - } - - /** - * - */ - public String peek2() throws IOException { - reader.mark(2); - char c[] = new char[2]; - c[0] = (char) reader.read(); - c[1] = (char) reader.read(); - String s = new String(c); - reader.reset(); - return s; - } - - /** - * @return true if ate the ending EI delimiter - * @throws java.io.IOException - */ - public boolean readLineForInlineImage(OutputStream out) throws IOException { - // The encoder might not have put EI on its own line (as it should), - // but might just put it right after the data - final int STATE_PRE_E = 0; - final int STATE_PRE_I = 1; - final int STATE_PRE_WHITESPACE = 2; - int state = STATE_PRE_E; - - while (true) { - int c = reader.read(); - if (c < 0) - break; - if (state == STATE_PRE_E && c == 'E') { - state++; - } else if (state == STATE_PRE_I && c == 'I') { - state++; - } else if (state == STATE_PRE_WHITESPACE && isWhitespace((char) (0xFF & c))) { - // It's hard to tell if the EI + whitespace is part of the - // image data or not, given that many PDFs are mis-encoded, - // and don't give whitespace when necessary. So, instead of - // assuming the need for whitespace, we're going to assume - // that this is the real EI, and apply a heuristic to prove - // ourselves wrong. - boolean imageDataFound = isStillInlineImageData(reader, 32); - if (imageDataFound) { - out.write('E'); - out.write('I'); - out.write(c); - state = STATE_PRE_E; - - if (c == '\r' || c == '\n') { - break; - } - } else - return true; - } else { - // If we got a fragment of the EI sequence, then we withheld - // what we had so far. But if we're here, that fragment was incomplete, - // so that was actual embedded data, and not the delimiter, so we have - // to write it out. - if (state > STATE_PRE_E) - out.write('E'); - if (state > STATE_PRE_I) - out.write('I'); - state = STATE_PRE_E; - - out.write((byte) c); - if (c == '\r' || c == '\n') { - break; - } - } - } - // If the input ends right after the EI, but with no whitespace, - // then we're still done - return state == STATE_PRE_WHITESPACE; - } - - /** - * We want to be conservative in deciding that we're still in the inline - * image, since we haven't found any of these cases before now. - */ - private static boolean isStillInlineImageData( - InputStream reader, int numBytesToCheck) - throws IOException { - boolean imageDataFound = false; - boolean onlyWhitespaceSoFar = true; - reader.mark(numBytesToCheck); - byte[] toCheck = new byte[numBytesToCheck]; - int numReadToCheck = reader.read(toCheck); - for (int i = 0; i < numReadToCheck; i++) { - char charToCheck = (char) (((int) toCheck[i]) & 0xFF); - - // If the very first thing we read is a Q or S token - boolean typicalTextTokenInContentStream = - (charToCheck == 'Q' || charToCheck == 'q' || - charToCheck == 'S' || charToCheck == 's'); - if (onlyWhitespaceSoFar && - typicalTextTokenInContentStream && - (i + 1 < numReadToCheck) && - isWhitespace((char) (((int) toCheck[i + 1]) & 0xFF))) { - break; - } - if (!isWhitespace(charToCheck)) - onlyWhitespaceSoFar = false; - - // If we find some binary image data - if (!isExpectedInContentStream(charToCheck)) { - imageDataFound = true; - break; - } - } - reader.reset(); - return imageDataFound; - } - - /** - * This is not necessarily an exhaustive list of characters one would - * expect in a Content Stream, it's a heuristic for whether the data - * might still be part of an inline image, or the lattercontent stream - */ - private static boolean isExpectedInContentStream(char c) { - return ((c >= 'a' && c <= 'Z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - isWhitespace(c) || - isDelimiter(c) || - (c == '\\') || - (c == '\'') || - (c == '\"') || - (c == '*') || - (c == '.')); - } - - - /** - * Utility Method for getting a PObject from the stack and adding it to the - * library. The retrieved PObject has an ObjectReference added to it for - * decryption purposes. - * - * @param library HashMap of all objects in document - * @param objectReference PObjet indirect reference data - * @return a valid PObject. - */ - public PObject addPObject(Library library, Reference objectReference) { - Object o = stack.pop(); - - // Add the streams object reference which is needed for - // decrypting encrypted streams - if (o instanceof Stream) { - Stream tmp = (Stream) o; - tmp.setPObjectReference(objectReference); - } - - // Add the dictionary object reference which is needed for - // decrypting encrypted string contained in the dictionary - else if (o instanceof Dictionary) { - Dictionary tmp = (Dictionary) o; - tmp.setPObjectReference(objectReference); - } - - // the the object to the library - library.addObject(o, objectReference); - - return new PObject(o, objectReference); - } - - /** - * Returns the next object found in a content stream. - * - * @return next object in the input stream - * @throws java.io.IOException when the end of the InputStream - * has been encountered. - */ - public Object getStreamObject() throws IOException { - - Object o = getToken(); - if (o instanceof String) { - if (o.equals("<<")) { - HashMap h = new HashMap(); - Object o1 = getStreamObject(); - while (!o1.equals(">>")) { - h.put(o1, getStreamObject()); - o1 = getStreamObject(); - } - o = h; - } - // arrays are only used for CID mappings, the hex decoding is delayed - // as a result using the CID_STREAM flag - else if (o.equals("[")) { - List v = new ArrayList(); - Object o1 = getStreamObject(); - while (!o1.equals("]")) { - v.add(o1); - o1 = getStreamObject(); - } - o = v; - } - } - return o; - } - - /** - * Utility method used to parse a valid pdf token from an DataIinputStream. - * Each call to this method return one pdf token. The Reader object is - * used to "mark" the location of the last "read". - * - * @return the next token in the pdf data stream - * @throws java.io.IOException if an I/O error occurs. - */ - public Object getToken() throws IOException { - - int currentByte; - char currentChar; - boolean inString = false; // currently parsing a string - boolean hexString = false; - boolean inNumber = false; - lastTokenHString = false; - - // strip all white space characters - do { - currentByte = reader.read(); - // input stream interrupted - if (currentByte < 0) { - throw new IOException(); - } - currentChar = (char) currentByte; - } - while (isWhitespace(currentChar)); - - /** - * look the start of different primitive pdf objects - * ( - strints - * [ - arrays - * % - comments - * numbers. - */ - if (currentChar == '(') { - // mark that we are currrently processing a string - inString = true; - } else if (currentChar == ']') { - // fount end of an array - return "]"; - } else if (currentChar == '[') { - // fount begining of an array - return "["; - } else if (currentChar == '%') { - // ignore all the characters after a comment token until - // we get to the end of the line - StringBuilder stringBuffer = new StringBuilder(); - do { - stringBuffer.append(currentChar); - currentByte = reader.read(); - if (currentByte < 0) { - // Final %%EOF might not have CR LF afterwards - if (stringBuffer.length() > 0) - return stringBuffer.toString(); - throw new IOException(); - } - currentChar = (char) currentByte; - } - while (currentChar != 13 && currentChar != 10); - // return all the text that is in the comment - return stringBuffer.toString(); - } else if ((currentChar >= '0' && currentChar <= '9') || - currentChar == '-' || currentChar == '+' || currentChar == '.') { - inNumber = true; - } - - // mark this location in the input stream - reader.mark(1); - - // read the next char from the reader - char nextChar = (char) reader.read(); - - // Check for dictionaries, start '<<' and end '>>' - if (currentChar == '>' && nextChar == '>') { - return ">>"; - } - if (currentChar == '<') { - // if two "<<" then we have a dictionary - if (nextChar == '<') { - return "<<"; - } - // Otherwise we have a hex number - else { - inString = true; - hexString = true; - } - } - - // return to the previous mark - reader.reset(); - - // store the parsed char in the token buffer. - StringBuilder stringBuffer = new StringBuilder(); - - stringBuffer.append(currentChar); - - /** - * Finally parse the contents of a complex token - */ - - int parenthesisCount = 0; - boolean complete = false; - // indicates that the current char should be ignored and not added to - // the current string. - boolean ignoreChar = false; - - do { // while !complete - - // if we are not parsing a string mark the location - if (!inString) { - reader.mark(1); - } - - // get the next byte and corresponding char - currentByte = reader.read(); - if (currentByte >= 0) { - currentChar = (char) currentByte; - } else { - // if there are no more bytes (-1) then we must have reached the end of this token, - // though maybe without appropriate termination of a string object. We'll just treat - // them as if they were. - break; - } - - // if we are parsing a token that is a string, (...) - if (inString) { - if (hexString) { - // found the end of a dictionary - if (currentChar == '>') { - stringBuffer.append(currentChar); - break; - } - } else { - // look for embedded strings - if (currentChar == '(') { - parenthesisCount++; - } - if (currentChar == ')') { - if (parenthesisCount == 0) { - stringBuffer.append(currentChar); - break; - } else { - parenthesisCount--; - } - } - // look for "\" character - /** - * The escape sequences can be as follows: - * \n - line feed (LF) - * \r - Carriage return (CR) - * \t - Horizontal tab (HT) - * \b - backspace (BS) - * \f - form feed (FF) - * \( - left parenthesis - * \) - right parenthesis - * \\ - backslash - * \ddd - character code ddd (octal) - * - * Note: (\0053) denotes a string containing two characters, - * \005 (Control-E) followed by the digit 3. - */ - if (currentChar == '\\') { - // read next char - currentChar = (char) reader.read(); - - // check for a digit, if so we have an octal - // and we need to handle it correctly - if (Character.isDigit(currentChar)) { - // store the read digits - StringBuilder digit = new StringBuilder(); - digit.append(currentChar); - // octals have a max size of 3 digits, we already - // have one, so there can be up 2 more digits. - for (int i = 0; i < 2; i++) { - // mark the reader incase the next read is not - // a digit. - reader.mark(1); - // read next char - currentChar = (char) reader.read(); - if (Character.isDigit(currentChar)) { - digit.append(currentChar); - } else { - // back up the reader just incase - // thre is only 1 or 2 digits in the octal - reader.reset(); - break; - } - } - - // finally convert digit to a character - int charNumber = 0; - try { - charNumber = Integer.parseInt(digit.toString(), 8); - } catch (NumberFormatException e) { - logger.log(Level.FINE, "Integer parse error ", e); - } - // convert the interger from octal to dec. - currentChar = (char) charNumber; - } - // do nothing - else if (currentChar == '(' || currentChar == ')' - || currentChar == '\\') { - // do nothing - } - // capture the horizontal tab (HT), tab character is hard - // to find, only appears in files with font substitution and - // as a result we ahve better luck drawing a space character. - else if (currentChar == 't') { - currentChar = '\t'; - } - // capture the carriage return (CR) - else if (currentChar == 'r') { - currentChar = '\r'; - } - // capture the line feed (LF) - else if (currentChar == 'n') { - currentChar = '\n'; - } - // capture the backspace (BS) - else if (currentChar == 'b') { - currentChar = '\b'; - } - // capture the form feed (FF) - else if (currentChar == 'f') { - currentChar = '\f'; - } - // ignor CF, which indicate a '\' lone split line token - else if (currentChar == 13) { - ignoreChar = true; - } - // otherwise report the file format error - else { - if (logger.isLoggable(Level.FINE)) { - logger.warning("C=" + ((int) currentChar)); - } - } - } - } - } - // if we are not in a string definition we want to break - // and return the current token, as white spaces or other elements - // would mean that we are on the next token - else if (isWhitespace(currentChar)) { - // we need to return the CR LR, as it is need by stream parsing - if (currentByte == 13 || currentByte == 10) { - reader.reset(); - break; - } - // break on any whitespace - else { - // return stringBuffer.toString(); - break; - } - } else if (isDelimiter(currentChar)) { - // reset the reader so we start on this token on the next parse - reader.reset(); - break; - } - // append the current char and keep parsing if needed - // IgnoreChar is set by the the line split char '\' - if (!ignoreChar) { - if (inString) { - stringBuffer.append(currentChar); - } - // eat any junk characters - else if (currentChar < 128) { - stringBuffer.append(currentChar); - } - } - // reset the ignorChar flag - else { - ignoreChar = false; - } - } - while (!complete); - - /** - * Return what we found - */ - // if a hex string decode it as needed - if (hexString) { - lastTokenHString = true; - return new HexStringObject(stringBuffer); - } - - // do a little clean up for any object that may have been missed.. - // this mainly for the the document trailer information - // a orphaned string - if (inString) { - return new LiteralStringObject(stringBuffer); - } - // return a new name - else if (stringBuffer.charAt(0) == '/') { - return new Name(stringBuffer.deleteCharAt(0)); - } - // if a number try and parse it - else if (inNumber) { - return getNumber(stringBuffer); - } - return stringBuffer.toString(); - } - - public Object getNumberOrStringWithMark(int maxLength) throws IOException { - reader.mark(maxLength); - - StringBuilder sb = new StringBuilder(maxLength); - boolean readNonWhitespaceYet = false; - boolean foundDigit = false; - boolean foundDecimal = false; - - for (int i = 0; i < maxLength; i++) { - int curr = reader.read(); - if (curr < 0) - break; - char currChar = (char) curr; - if (isWhitespace(currChar)) { - if (readNonWhitespaceYet) - break; - } else if (isDelimiter(currChar)) { - // Number or string has delimiter immediately after it, - // which we'll have to unread. - // Had hoped it would be whitespace, so wouldn't have to unread - reader.reset(); - reader.mark(maxLength); - for (int j = 0; j < i; j++) { - reader.read(); - } - readNonWhitespaceYet = true; - break; - } else { - readNonWhitespaceYet = true; - if (currChar == '.') - foundDecimal = true; - else if (currChar >= '0' && curr <= '9') - foundDigit = true; - sb.append(currChar); - } - } - - // Only bother trying to interpret as a number if contains a digit somewhere, - // to reduce NumberFormatExceptions - if (foundDigit) { - return getNumber(sb); - } - - if (sb.length() > 0) - return sb.toString(); - return null; - } - - public void ungetNumberOrStringWithReset() throws IOException { - reader.reset(); - } - - public int getIntSurroundedByWhitespace() { - int num = 0; - boolean makeNegative = false; - boolean readNonWhitespace = false; - try { - while (true) { - int curr = reader.read(); - if (curr < 0) - break; - if (Character.isWhitespace((char) curr)) { - if (readNonWhitespace) - break; - } else if (curr == '-') { - makeNegative = true; - readNonWhitespace = true; - } else if (curr >= '0' && curr <= '9') { - num *= 10; - num += (curr - '0'); - readNonWhitespace = true; - } else { - // break as we've hit a none digit and should bail - break; - } - } - } catch (IOException e) { - logger.log(Level.FINE, "Error detecting int.", e); - } - if (makeNegative) - num = num * -1; - return num; - } - - public Number getNumber(StringBuilder value) { - int digit = 0; - float decimal = 0; - float divisor = 10; - boolean isDigit; - boolean isDecimal = false; - byte[] streamBytes = value.toString().getBytes(); - int startTokenPos = 0; - boolean singed = streamBytes[startTokenPos] == '-'; - boolean positive = streamBytes[startTokenPos] == '+'; - startTokenPos = singed || positive ? startTokenPos + 1 : startTokenPos; - // check for double sign, thanks oracle forms! - if (singed && streamBytes[startTokenPos] == '-') { - startTokenPos++; - } - int current; - for (int i = startTokenPos, max = streamBytes.length; i < max; i++) { - current = streamBytes[i] - 48; - isDigit = streamBytes[i] >= 48 && streamBytes[i] <= 57; - if (!isDecimal && isDigit) { - digit = (digit * 10) + current; - } else if (isDecimal && isDigit) { - decimal += (current / divisor); - divisor *= 10; - } else if (streamBytes[i] == 46) { - isDecimal = true; - } else { - // anything else we can assume malformed and should break. - break; - } - } - if (singed) { - if (isDecimal) { - return -(digit + decimal); - } else { - return -digit; - } - } else { - if (isDecimal) { - return digit + decimal; - } else { - return digit; - } - } - } - - public long getLongSurroundedByWhitespace() { - long num = 0L; - boolean makeNegative = false; - boolean readNonWhitespace = false; - try { - while (true) { - int curr = reader.read(); - if (curr < 0) - break; - if (Character.isWhitespace((char) curr)) { - if (readNonWhitespace) - break; - } else if (curr == '-') { - makeNegative = true; - readNonWhitespace = true; - } else if (curr >= '0' && curr <= '9') { - num *= 10L; - num += ((long) (curr - '0')); - readNonWhitespace = true; - } else { - break; - } - } - } catch (IOException e) { - logger.log(Level.FINER, "Error detecting long.", e); - } - if (makeNegative) - num = num * -1L; - return num; - } - - public int getLinearTraversalOffset() { - return linearTraversalOffset; - } - - public char getCharSurroundedByWhitespace() { - char alpha = 0; - try { - while (true) { - int curr = reader.read(); - if (curr < 0) - break; - char c = (char) curr; - if (!Character.isWhitespace(c)) { - alpha = c; - break; - } - } - } catch (IOException e) { - logger.log(Level.FINE, "Error detecting char.", e); - } - return alpha; - } - - - /** - * White space characters defined by ' ', '\t', '\r', '\n', '\f' - * - * @param c true if character is white space - */ - public static boolean isWhitespace(char c) { - return ((c == ' ') || (c == '\t') || (c == '\r') || - (c == '\n') || (c == '\f') || (c == 0)); - } - - private static boolean isDelimiter(char c) { - return ((c == '[') || (c == ']') || - (c == '(') || (c == ')') || - (c == '<') || (c == '>') || - (c == '{') || (c == '}') || - (c == '/') || (c == '%')); - } - - private long captureStreamData(OutputStream out) throws IOException { - long numBytes = 0; - while (true) { - // read bytes - int nextByte = reader.read(); - // look to see if we have the ending tag - if (nextByte == 'e') { - reader.mark(10); - if (reader.read() == 'n' && - reader.read() == 'd' && - reader.read() == 's' && - reader.read() == 't' && - reader.read() == 'r' && - reader.read() == 'e' && - reader.read() == 'a' && - reader.read() == 'm') { - break; - } else { - reader.reset(); - } - } else if (nextByte < 0) - break; - // write the bytes - if (out != null) - out.write(nextByte); - numBytes++; - } - return numBytes; - } - - private long skipUntilEndstream(OutputStream out) throws IOException { - long skipped = 0L; - while (true) { - reader.mark(10); - // read bytes - int nextByte = reader.read(); - if (nextByte == 'e' && - reader.read() == 'n' && - reader.read() == 'd' && - reader.read() == 's' && - reader.read() == 't' && - reader.read() == 'r' && - reader.read() == 'e' && - reader.read() == 'a' && - reader.read() == 'm') { - reader.reset(); - break; - } else if (nextByte < 0) - break; - else { - if (nextByte == 0x0A || nextByte == 0x0D || nextByte == 0x20) - continue; - if (out != null) - out.write(nextByte); - } - skipped++; - } - return skipped; - } - - private float parseNumber(StringBuilder stringBuilder) { - float digit = 0; - float divisor = 10; - boolean isDigit; - boolean isDecimal = false; - int startTokenPos = 0; - int length = stringBuilder.length(); - char[] streamBytes = new char[length]; - stringBuilder.getChars(0, length, streamBytes, 0); - boolean singed = streamBytes[startTokenPos] == '-'; - startTokenPos = singed ? startTokenPos + 1 : startTokenPos; - int current; - for (int i = startTokenPos; i < length; i++) { - current = streamBytes[i] - 48; - isDigit = streamBytes[i] >= 48 && streamBytes[i] <= 57; - if (!isDecimal && isDigit) { - digit = (digit * 10) + current; - } else if (isDecimal && isDigit) { - digit += (current / divisor); - divisor *= 10; - } else if (streamBytes[i] == 46) { - isDecimal = true; - } else { - // anything else we can assume malformed and should break. - break; - } - } - if (singed) { - return -digit; - } else { - return digit; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/PdfOps.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/PdfOps.java deleted file mode 100644 index 0a6098ee3c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/PdfOps.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -/** - * - */ -public final class PdfOps { - - // Path Tokens - public static final String m_TOKEN = "m"; - public static final String l_TOKEN = "l"; - public static final String c_TOKEN = "c"; - public static final String v_TOKEN = "v"; - public static final String y_TOKEN = "y"; - public static final String h_TOKEN = "h"; - public static final String re_TOKEN = "re"; - - // Path Painting - public static final String S_TOKEN = "S"; - public static final String s_TOKEN = "s"; - public static final String f_TOKEN = "f"; - public static final String F_TOKEN = "F"; - public static final String f_STAR_TOKEN = "f*"; - public static final String B_TOKEN = "B"; - public static final String b_TOKEN = "b"; - public static final String B_STAR_TOKEN = "B*"; - public static final String b_STAR_TOKEN = "b*"; - - // external object - public static final String Do_TOKEN = "Do"; - - // clipping - public static final String n_TOKEN = "n"; - public static final String W_TOKEN = "W"; - public static final String W_STAR_TOKEN = "W*"; - - // compatibility - public static final String BX_TOKEN = "BX"; - public static final String EX_TOKEN = "EX"; - - // Marked Content - public static final String BDC_TOKEN = "BDC"; - public static final String BMC_TOKEN = "BMC"; - public static final String EMC_TOKEN = "EMC"; - - // marked content - public static final String DP_TOKEN = "DP"; - public static final String MP_TOKEN = "MP"; - - // General Path Stats - public static final String ri_TOKEN = "ri"; - public static final String sh_TOKEN = "sh"; - public static final String d0_TOKEN = "d0"; - public static final String d1_TOKEN = "d1"; - - // text tokens - public static final String BT_TOKEN = "BT"; - public static final String ET_TOKEN = "ET"; - public static final String Tm_TOKEN = "Tm"; - public static final String Td_TOKEN = "Td"; - public static final String TD_TOKEN = "TD"; - public static final String T_STAR_TOKEN = "T*"; - public static final String Tj_TOKEN = "Tj"; - public static final String Tc_TOKEN = "Tc"; - public static final String Tz_TOKEN = "Tz"; - public static final String Tw_TOKEN = "Tw"; - public static final String Tr_TOKEN = "Tr"; - public static final String TL_TOKEN = "TL"; - public static final String Ts_TOKEN = "Ts"; - public static final String TJ_TOKEN = "TJ"; - public static final String Tf_TOKEN = "Tf"; - public static final String SINGLE_QUOTE_TOKEN = "'"; - public static final String DOUBLE_QUOTE__TOKEN = "\""; - - // Color State - public static final String G_TOKEN = "G"; - public static final String g_TOKEN = "g"; - public static final String RG_TOKEN = "RG"; - public static final String rg_TOKEN = "rg"; - public static final String K_TOKEN = "K"; - public static final String k_TOKEN = "k"; - public static final String CS_TOKEN = "CS"; - public static final String cs_TOKEN = "cs"; - public static final String SC_TOKEN = "SC"; - public static final String SCN_TOKEN = "SCN"; - public static final String sc_TOKEN = "sc"; - public static final String scn_TOKEN = "scn"; - - // Graphics STate - public static final String q_TOKEN = "q"; - public static final String Q_TOKEN = "Q"; - public static final String cm_TOKEN = "cm"; - public static final String i_TOKEN = "i"; - public static final String J_TOKEN = "J"; - public static final String j_TOKEN = "j"; - public static final String d_TOKEN = "d"; - public static final String w_TOKEN = "w"; - public static final String LW_TOKEN = "LW"; - public static final String M_TOKEN = "M"; - public static final String gs_TOKEN = "gs"; - - // Inline Images - public static final String BI_TOKEN = "BI"; - public static final String ID_TOKEN = "ID"; - public static final String BPC_TOKEN = "BPC"; - public static final String BPC_NAME = "BitsPerComponent"; - public static final String CS_NAME = "ColorSpace"; - public static final String D_TOKEN = "D"; - public static final String D_NAME = "Decode"; - public static final String DP_NAME = "DecodeParms"; - public static final String F_NAME = "Filter"; - public static final String H_TOKEN = "H"; - public static final String H_NAME = "Height"; - public static final String IM_TOKEN = "IM"; - public static final String IM_NAME = "ImageMask"; - public static final String I_TOKEN = "I"; - public static final String I_NAME = "Indexed"; - public static final String W_NAME = "Width"; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/PropertyConstants.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/PropertyConstants.java deleted file mode 100644 index bc520cf4a8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/PropertyConstants.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -public class PropertyConstants { - - // property change event names - - public final static String - DOCUMENT_CURRENT_PAGE = "documentCurrentPage", - - DOCUMENT_VIEW_ZOOM_CHANGE = "documentViewZoomChange", - DOCUMENT_VIEW_ROTATION_CHANGE = "documentViewRotationChange", - DOCUMENT_VIEW_REFRESH_CHANGE = "documentViewRefreshChange", - DOCUMENT_VIEW_DEMO_MODE_CHANGE = "documentViewDemoChange", - - DOCUMENT_TOOL_PAN = "documentToolRotation", - DOCUMENT_TOOL_ZOOM_IN = "documentToolZoomIn", - DOCUMENT_TOOL_ZOOM_OUT = "documentToolZoomOut", -// DOCUMENT_TOOL_DYNAMIC_ROTATION = "documentToolDynamicRotation", -// DOCUMENT_TOOL_DYNAMIC_ZOOM = "documentToolDynamicZoom", - - DOCUMENT_TOOL_NONE = "documentToolNone", - DOCUMENT_TOOL_TEXT_SELECTION = "documentToolTextSelect", - DOCUMENT_TOOL_ANNOTATION_SELECTION = "documentToolAnnotationSelect", - - DOCUMENT_INITIALIZING_PAGE = "documentPageInitialization", - DOCUMENT_PAINTING_PAGE = "documentPagePainting", - - TEXT_DESELECTED = "textDeselected", - TEXT_SELECTED = "textSelected", - TEXT_SELECT_ALL = "textSelectAll", - - ANNOTATION_SELECTED = "annotationSelected", - ANNOTATION_DESELECTED = "annotationDeselected", - - ANNOTATION_DELETED = "annotationDeleted", - - ANNOTATION_BOUNDS = "annotationBounds", - - ANNOTATION_FOCUS_GAINED = "annotationFocusGained", - ANNOTATION_FOCUS_LOST = "annotationFocusLost", - - // not in use - ANNOTATION_NEW_LINK = "annotationNewLink"; - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/SoftLRUCache.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/SoftLRUCache.java deleted file mode 100644 index 6c1dda4997..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/SoftLRUCache.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.util.LinkedHashMap; - -/** - * Least recently used cache using SoftReferences. - * - * @since 5.0 - */ -public class SoftLRUCache { - private LinkedHashMap> lruCache; - private ReferenceQueue reqQueue; - - public SoftLRUCache(int aInitialSize) { - lruCache = new LinkedHashMap>( - aInitialSize, - 0.75f, - true - ); - reqQueue = new ReferenceQueue(); - } - - public V get(K aKey) { - diposeStaleEntries(); - SoftReference ref = lruCache.get(aKey); - if (ref != null) { - return ref.get(); - } else { - return null; - } - } - - public V put(K aKey, V aValue) { - diposeStaleEntries(); - SoftReference oldValue = lruCache.put(aKey, new KeyReference(aKey, aValue, reqQueue)); - if (oldValue != null) { - return oldValue.get(); - } else { - return null; - } - } - - @SuppressWarnings("unchecked") - private void diposeStaleEntries() { - KeyReference ref; - while ((ref = (KeyReference) reqQueue.poll()) != null) { - lruCache.remove(ref.getKey()); - } - } - - public void clear() { - lruCache.clear(); - } - - private static class KeyReference extends SoftReference { - private K key; - - public KeyReference(K key, V value, ReferenceQueue refQueue) { - super(value, refQueue); - this.key = key; - } - - public K getKey() { - return key; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Utils.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Utils.java deleted file mode 100644 index 125ed98d09..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/Utils.java +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util; - -import org.icepdf.core.io.SeekableByteArrayInputStream; -import org.icepdf.core.io.SeekableInput; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.pobjects.fonts.ofont.Encoding; - -import java.io.*; -import java.lang.reflect.Method; -import java.nio.ByteBuffer; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * @author Mark Collette - * Date: 18-Feb-2005 - * Time: 3:53:40 PM - */ -public class Utils { - - private static final Logger logger = - Logger.getLogger(Utils.class.toString()); - - /** - * Sets the value into the buffer, at the designated offset, using big-endian rules - * Callers is responsible to ensure that value will fit into buffer, starting at offset - * - * @param value to be set into buffer - * @param buffer into which value is to be set - * @param offset into buffer which value is to be set - */ - public static void setIntIntoByteArrayBE(int value, byte[] buffer, int offset) { - buffer[offset] = (byte) ((value >>> 24) & 0xff); - buffer[offset + 1] = (byte) ((value >>> 16) & 0xff); - buffer[offset + 2] = (byte) ((value >>> 8) & 0xff); - buffer[offset + 3] = (byte) ((value) & 0xff); - } - - /** - * Sets the value into the buffer, at the designated offset, using big-endian rules - * Callers is responsible to ensure that value will fit into buffer, starting at offset - * - * @param value to be set into buffer - * @param buffer into which value is to be set - * @param offset into buffer which value is to be set - */ - public static void setShortIntoByteArrayBE(short value, byte[] buffer, int offset) { - buffer[offset] = (byte) ((value >>> 8) & 0xff); - buffer[offset + 1] = (byte) ((value) & 0xff); - } - - /** - * @param in InputStream to read from - * @param numBytes number of bytes to read to make integral value from [0, 8] - * @return Integral value, which is composed of numBytes bytes, read using big-endian rules from in - * @throws IOException - */ - public static long readLongWithVaryingBytesBE(InputStream in, int numBytes) throws IOException { -//System.out.println("Utils.readLongWithVaryingBytesBE() numBytes: " + numBytes); - long val = 0; - for (int i = 0; i < numBytes; i++) { - int curr = in.read(); - if (curr < 0) - throw new EOFException(); - val <<= 8; - val |= (((long) curr) & ((long) 0xFF)); - } - return val; - } - - /** - * @param in InputStream to read from - * @param numBytes number of bytes to read to make integral value from [0, 4] - * @return Integral value, which is composed of numBytes bytes, read using big-endian rules from in - * @throws IOException - */ - public static int readIntWithVaryingBytesBE(InputStream in, int numBytes) throws IOException { -//System.out.println("Utils.readIntWithVaryingBytesBE() numBytes: " + numBytes); - int val = 0; - for (int i = 0; i < numBytes; i++) { - int curr = in.read(); - if (curr < 0) - throw new EOFException(); - val <<= 8; - val |= (curr & 0xFF); - } - return val; - } - - /** - * Write the given int as a 4 byte integer to the given outputStream. - * - * @param in stream to write byte data to. - * @param i integer to convert to bytes. - * @throws IOException write error. - */ - public static void writeInteger(OutputStream in, int i) throws IOException { - ByteBuffer bb = ByteBuffer.allocate(4); - bb.putInt(i); - in.write(bb.array()); - } - - /** - * Write the given int as a 8 byte long to the given outputStream. - * - * @param in stream to write byte data to. - * @param i long to convert to bytes. - * @throws IOException write error. - */ - public static void writeLong(OutputStream in, long i) throws IOException { - ByteBuffer bb = ByteBuffer.allocate(8); - bb.putLong(i); - in.write(bb.array()); - } - - public static String convertByteArrayToHexString(byte[] buffer, boolean addSpaceSeparator) { - return convertByteArrayToHexString( - buffer, 0, buffer.length, addSpaceSeparator, -1, (char) 0); - } - - public static String convertByteArrayToHexString(byte[] buffer, boolean addSpaceSeparator, int addDelimiterEverNBytes, char delimiter) { - return convertByteArrayToHexString( - buffer, 0, buffer.length, addSpaceSeparator, addDelimiterEverNBytes, delimiter); - } - - public static String byteFormatter(long bytes, boolean si) { - int unit = si ? 1000 : 1024; - if (bytes < unit) return bytes + " B"; - int exp = (int) (Math.log(bytes) / Math.log(unit)); - String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); - return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); - } - - public static String convertByteArrayToHexString( - byte[] buffer, int offset, int length, - boolean addSpaceSeparator, int addDelimiterEverNBytes, char delimiter) { - int presize = length * (addSpaceSeparator ? 3 : 2); - if (addDelimiterEverNBytes > 0) - presize += (length / addDelimiterEverNBytes); - StringBuilder sb = new StringBuilder(presize); - int delimiterCount = 0; - int end = offset + length; - for (int index = offset; index < end; index++) { - int currValue = 0; - currValue |= (0xff & ((int) buffer[index])); - String s = Integer.toHexString(currValue); - for (int i = s.length(); i < 2; i++) - sb.append('0'); - sb.append(s); - if (addSpaceSeparator) - sb.append(' '); - delimiterCount++; - if (addDelimiterEverNBytes > 0 && delimiterCount == addDelimiterEverNBytes) { - delimiterCount = 0; - sb.append(delimiter); - } - } - return sb.toString(); - } - - /** - * boolean java.awt.GraphicsEnvironment.isHeadless() does not exist in Java 1.3, - * since it was introduced in Java 1.4, so we use reflection to call it, - * if it exists. - * In the event of not being able to call graphicsEnvironment.isHeadless(), - * instead of throwing an Exception, we simply return defaultReturnIfNoMethod - * - * @param graphicsEnvironment java.awt.GraphicsEnvironment to call isHeadless() on - * @param defaultReturnIfNoMethod Value to return if could not call graphicsEnvironment.isHeadless() - */ - public static boolean reflectGraphicsEnvironmentISHeadlessInstance(Object graphicsEnvironment, boolean defaultReturnIfNoMethod) { - try { - Class clazz = graphicsEnvironment.getClass(); - Method isHeadlessInstanceMethod = clazz.getMethod("isHeadlessInstance", new Class[]{}); - if (isHeadlessInstanceMethod != null) { - Object ret = isHeadlessInstanceMethod.invoke( - graphicsEnvironment); - if (ret instanceof Boolean) - return (Boolean) ret; - } - } catch (Throwable t) { - logger.log(Level.FINE, - "ImageCache: Java 1.4 Headless support not found."); - } - return defaultReturnIfNoMethod; - } - - public static String getContentAndReplaceInputStream(InputStream[] inArray, boolean convertToHex) { - String content = null; - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(1024); - InputStream in = inArray[0]; - - byte[] buf = new byte[1024]; - while (true) { - int read = in.read(buf, 0, buf.length); - if (read < 0) - break; - out.write(buf, 0, read); - } - -// while( true ) { -// int read = in.read(); -// if( read < 0 ) -// break; -// out.write( read ); -// } - - if (!(in instanceof SeekableInput)) - in.close(); - out.flush(); - out.close(); - byte[] data = out.toByteArray(); - inArray[0] = new ByteArrayInputStream(data); - if (convertToHex) - content = Utils.convertByteArrayToHexString(data, true); - else - content = new String(data); - } catch (IOException ioe) { - logger.log(Level.FINE, "Problem getting debug string", ioe); - } catch (Throwable e) { - logger.log(Level.FINE, "Problem getting content stream, skipping"); - } - return content; - } - - public static String getContentFromSeekableInput(SeekableInput in, boolean convertToHex) { - String content = null; - try { - in.beginThreadAccess(); - - long position = in.getAbsolutePosition(); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - - /* - byte[] buf = new byte[1024]; - while( true ) { - int read = in.read( buf, 0, buf.length ); - if( read < 0 ) - break; - out.write( buf, 0, read ); - } - */ - - while (true) { - int read = in.getInputStream().read(); - if (read < 0) - break; - out.write(read); - } - - in.seekAbsolute(position); - - out.flush(); - out.close(); - byte[] data = out.toByteArray(); - if (convertToHex) - content = Utils.convertByteArrayToHexString(data, true); - else - content = new String(data); - } catch (IOException ioe) { - logger.log(Level.FINE, "Problem getting debug string"); - } finally { - in.endThreadAccess(); - } - return content; - } - - public static SeekableInput replaceInputStreamWithSeekableInput(InputStream in) { - if (in instanceof SeekableInput) - return (SeekableInput) in; - - SeekableInput sin = null; - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(1024); - - /* - byte[] buf = new byte[1024]; - while( true ) { - int read = in.read( buf, 0, buf.length ); - if( read < 0 ) - break; - out.write( buf, 0, read ); - } - */ - - while (true) { - int read = in.read(); - if (read < 0) - break; - out.write(read); - } - - in.close(); - out.flush(); - out.close(); - byte[] data = out.toByteArray(); - sin = new SeekableByteArrayInputStream(data); - } catch (IOException ioe) { - logger.log(Level.FINE, "Problem getting debug string"); - } - return sin; - } - - public static void printMemory(String str) { - long total = Runtime.getRuntime().totalMemory(); - long free = Runtime.getRuntime().freeMemory(); - long used = total - free; - System.out.println("MEM " + str + " used: " + (used / 1024) + " KB delta: " + ((used - lastMemUsed) / 1024) + " KB"); - lastMemUsed = used; - } - - private static long lastMemUsed = 0; - - public static int numBytesToHoldBits(int numBits) { - int numBytes = (numBits / 8); - if ((numBits % 8) > 0) - numBytes++; - return numBytes; - } - - /** - * When converting between String chars and bytes, there's an implied - * encoding to be used, dependent on the context and platform. If - * none is specified, then String(byte[]) will use the platform's - * default encoding. This method is for when encoding is not relevant, - * when the String simply holds byte values in each char. - * - * @see org.icepdf.core.pobjects.LiteralStringObject - * @see org.icepdf.core.pobjects.HexStringObject - * @see org.icepdf.core.pobjects.security.StandardEncryption - */ - public static byte[] convertByteCharSequenceToByteArray(CharSequence string) { - final int max = string.length(); - byte[] bytes = new byte[max]; - for (int i = 0; i < max; i++) { - bytes[i] = (byte) string.charAt(i); - } - return bytes; - } - - /** - * When converting between String chars and bytes, there's an implied - * encoding to be used, dependent on the context and platform. If - * none is specified, then String(byte[]) will use the platform's - * default encoding. This method is for when encoding is not relevant, - * when the String simply holds byte values in each char. - * - * @see org.icepdf.core.pobjects.LiteralStringObject - * @see org.icepdf.core.pobjects.HexStringObject - * @see org.icepdf.core.pobjects.security.StandardEncryption - */ - public static String convertByteArrayToByteString(byte[] bytes) { - final int max = bytes.length; - StringBuilder sb = new StringBuilder(max); - for (byte aByte : bytes) { - int b = ((int) aByte) & 0xFF; - sb.append((char) b); - } - return sb.toString(); - } - - /** - * Utility method for decrypting a String object found in a dictionary - * as a plaing text. The string can be encrypted as well as octal encoded, - * which is handle by this method. - * - * @param library document library used for encryption handling. - * @param stringObject string object to convert to string - * @return converted string. - */ - public static String convertStringObject(Library library, StringObject stringObject) { - String convertedStringObject = null; - String titleText = stringObject.getDecryptedLiteralString(library.getSecurityManager()); - // If the title begins with 254 and 255 we are working with - // Octal encoded strings. Check first to make sure that the - // title string is not null, or is at least of length 2. - if (titleText != null && titleText.length() >= 2 && - ((int) titleText.charAt(0)) == 254 && - ((int) titleText.charAt(1)) == 255) { - - StringBuilder sb1 = new StringBuilder(); - - // convert teh unicode to characters. - for (int i = 2; i < titleText.length(); i += 2) { - try { - int b1 = ((((int) titleText.charAt(i)) & 0xFF) << 8 ) | - ((int) titleText.charAt(i + 1)) & 0xFF; - //System.err.println(b1 + " " + b2); - sb1.append((char) (b1)); - } catch (Exception ex) { - // intentionally left blank. - } - } - convertedStringObject = sb1.toString(); - } else if (titleText != null) { - StringBuilder sb = new StringBuilder(); - Encoding enc = Encoding.getPDFDoc(); - for (int i = 0; i < titleText.length(); i++) { -// sb.append(titleText.charAt(i)); - // pdf encoding maps char < 24 to '?' or 63. so we'll skip this map. - char character = titleText.charAt(i); - if (character > 23) { - sb.append(enc.get(character)); - } else { - sb.append(titleText.charAt(i)); - } - } - convertedStringObject = sb.toString(); - } - return convertedStringObject; - } - - /** - * Convert a utf-8 encoded string into into an octal enocded byte[] array. - * - * @param literalString string to convert. - * @return converted string value. - */ - public static String convertStringToOctal(String literalString) { - // scan string ot see if we have any unicode. - int length = literalString.length(); - boolean foundExtendedAscii = false; - for (int i = 0; i < length; i++) { - if (literalString.charAt(i) >= 255) { - foundExtendedAscii = true; - break; - } - } - if (foundExtendedAscii) { - char[] octalEncoded = new char[length * 2 + 2]; - octalEncoded[0] = 254; - octalEncoded[1] = 255; - for (int i = 0, j = 2; i < length; i++, j += 2) { - octalEncoded[j] = (char) ((literalString.charAt(i) >> 8) & 0xFF); - octalEncoded[j + 1] = (char) (literalString.charAt(i) & 0xFF); - } - return new String(octalEncoded); - } else { - return literalString; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/AbstractContentParser.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/AbstractContentParser.java deleted file mode 100644 index beb3f15948..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/AbstractContentParser.java +++ /dev/null @@ -1,2027 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util.content; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.fonts.FontFile; -import org.icepdf.core.pobjects.fonts.FontManager; -import org.icepdf.core.pobjects.graphics.*; -import org.icepdf.core.pobjects.graphics.commands.*; -import org.icepdf.core.pobjects.graphics.text.GlyphText; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; - -import java.awt.*; -import java.awt.geom.*; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Stack; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * AbstractContentParser contains all base operand implementations for the - * Post Script operand set. - * - * @since 5.0 - */ -public abstract class AbstractContentParser implements ContentParser { - private static final Logger logger = - Logger.getLogger(AbstractContentParser.class.toString()); - private static boolean disableTransparencyGroups; - private static boolean enabledOverPrint; - private static boolean enabledFontFallback; - - static { - // decide if large images will be scaled - disableTransparencyGroups = - Defs.sysPropertyBoolean("org.icepdf.core.disableTransparencyGroup", - false); - - // decide if basic over print support will be enabled. - enabledOverPrint = - Defs.sysPropertyBoolean("org.icepdf.core.enabledOverPrint", - true); - - enabledFontFallback = - Defs.sysPropertyBoolean("org.icepdf.core.enabledFontFallback", - false); - } - - public static final float OVERPAINT_ALPHA = 0.4f; - - private static ClipDrawCmd clipDrawCmd = new ClipDrawCmd(); - private static NoClipDrawCmd noClipDrawCmd = new NoClipDrawCmd(); - - protected GraphicsState graphicState; - protected Library library; - protected Resources resources; - - protected Shapes shapes; - // keep track of embedded marked content - protected LinkedList oCGs; - - // represents a geometric path constructed from straight lines, and - // quadratic and cubic (Beauctezier) curves. It can contain - // multiple sub paths. - protected GeneralPath geometricPath; - - // flag to handle none text based coordinate operand "cm" inside of a text block - protected boolean inTextBlock; - - // TextBlock affine transform can be altered by the "cm" operand an thus - // the text base affine transform must be accessible outside the parsTtext method - protected AffineTransform textBlockBase; - - // when parsing a type3 font we need to keep track of the the scale factor - // of the device space ctm. - protected float glyph2UserSpaceScale = 1.0f; - - // xObject image count; - protected AtomicInteger imageIndex = new AtomicInteger(1); - - // stack to help with the parse - protected Stack stack = new Stack(); - - /** - * @param l PDF library master object. - * @param r resources - */ - public AbstractContentParser(Library l, Resources r) { - library = l; - resources = r; - } - - /** - * Returns the Shapes that have accumulated turing multiple calls to - * parse(). - * - * @return resultant shapes object of all processed content streams. - */ - public Shapes getShapes() { - shapes.contract(); - return shapes; - } - - /** - * Returns the stack of object used to parse content streams. If parse - * was successful the stack should be empty. - * - * @return stack of objects accumulated during a cotent stream parse. - */ - public Stack getStack() { - return stack; - } - - /** - * Returns the current graphics state object being used by this content - * stream. - * - * @return current graphics context of content stream. May be null if - * parse method has not been previously called. - */ - public GraphicsState getGraphicsState() { - return graphicState; - } - - /** - * Sets the graphics state object which will be used for the current content - * parsing. This method must be called before the parse method is called - * otherwise it will not have an effect on the state of the draw operands. - * - * @param graphicState graphics state of this content stream - */ - public void setGraphicsState(GraphicsState graphicState) { - this.graphicState = graphicState; - } - - /** - * Parse a pages content stream. - * - * @param streamBytes byte stream containing page content - * @return a Shapes Object containing all the pages text and images shapes. - * @throws InterruptedException if current parse thread is interrupted. - * @throws java.io.IOException unexpected end of content stream. - */ - public abstract ContentParser parse(byte[][] streamBytes, Page page) - throws InterruptedException, IOException; - - /** - * Specialized method for extracting text from documents. - * - * @param source content stream source. - * @return vector where each entry is the text extracted from a text block. - */ - public abstract Shapes parseTextBlocks(byte[][] source) throws UnsupportedEncodingException, InterruptedException; - - protected static void consume_G(GraphicsState graphicState, Stack stack, - Library library) { - float gray = ((Number) stack.pop()).floatValue(); - // Stroke Color Gray - graphicState.setStrokeColorSpace( - PColorSpace.getColorSpace(library, DeviceGray.DEVICEGRAY_KEY)); - graphicState.setStrokeColor(new Color(gray, gray, gray)); - } - - protected static void consume_g(GraphicsState graphicState, Stack stack, - Library library) { - float gray = Math.abs(((Number) stack.pop()).floatValue()); - // Fill Color Gray - graphicState.setFillColorSpace( - PColorSpace.getColorSpace(library, DeviceGray.DEVICEGRAY_KEY)); - graphicState.setFillColor(new Color(gray, gray, gray)); - } - - protected static void consume_RG(GraphicsState graphicState, Stack stack, - Library library) { - float b = ((Number) stack.pop()).floatValue(); - float gg = ((Number) stack.pop()).floatValue(); - float r = ((Number) stack.pop()).floatValue(); - b = Math.max(0.0f, Math.min(1.0f, b)); - gg = Math.max(0.0f, Math.min(1.0f, gg)); - r = Math.max(0.0f, Math.min(1.0f, r)); - // set stoke colour - graphicState.setStrokeColorSpace( - PColorSpace.getColorSpace(library, DeviceRGB.DEVICERGB_KEY)); - graphicState.setStrokeColor(new Color(r, gg, b)); - } - - protected static void consume_rg(GraphicsState graphicState, Stack stack, - Library library) { - if (stack.size() >= 3) { - float b = ((Number) stack.pop()).floatValue(); - float gg = ((Number) stack.pop()).floatValue(); - float r = ((Number) stack.pop()).floatValue(); - b = Math.max(0.0f, Math.min(1.0f, b)); - gg = Math.max(0.0f, Math.min(1.0f, gg)); - r = Math.max(0.0f, Math.min(1.0f, r)); - // set fill colour - graphicState.setFillColorSpace( - PColorSpace.getColorSpace(library, DeviceRGB.DEVICERGB_KEY)); - graphicState.setFillColor(new Color(r, gg, b)); - } - } - - protected static void consume_K(GraphicsState graphicState, Stack stack, - Library library) { - if (stack.size() >= 4) { - float k = ((Number) stack.pop()).floatValue(); - float y = ((Number) stack.pop()).floatValue(); - float m = ((Number) stack.pop()).floatValue(); - float c = ((Number) stack.pop()).floatValue(); - - PColorSpace pColorSpace = - PColorSpace.getColorSpace(library, DeviceCMYK.DEVICECMYK_KEY); - // set stroke colour - graphicState.setStrokeColorSpace(pColorSpace); - graphicState.setStrokeColor(pColorSpace.getColor( - new float[]{k, y, m, c}, true)); - } - } - - protected static void consume_k(GraphicsState graphicState, Stack stack, - Library library) { - float k = ((Number) stack.pop()).floatValue(); - float y = ((Number) stack.pop()).floatValue(); - float m = ((Number) stack.pop()).floatValue(); - float c = ((Number) stack.pop()).floatValue(); - // build a colour space. - PColorSpace pColorSpace = - PColorSpace.getColorSpace(library, DeviceCMYK.DEVICECMYK_KEY); - // set fill colour - graphicState.setFillColorSpace(pColorSpace); - graphicState.setFillColor(pColorSpace.getColor( - new float[]{k, y, m, c}, true)); - } - - protected static void consume_CS(GraphicsState graphicState, Stack stack, Resources resources) { - Name n = (Name) stack.pop(); - // Fill Color ColorSpace, resources call uses factory call to PColorSpace.getColorSpace - // which returns an colour space including a pattern - graphicState.setStrokeColorSpace(resources.getColorSpace(n)); - } - - protected static void consume_cs(GraphicsState graphicState, Stack stack, Resources resources) { - Name n = (Name) stack.pop(); - // Fill Color ColorSpace, resources call uses factory call to PColorSpace.getColorSpace - // which returns an colour space including a pattern - graphicState.setFillColorSpace(resources.getColorSpace(n)); - } - - protected static void consume_ri(Stack stack) { - stack.pop(); - } - - protected static void consume_SC(GraphicsState graphicState, Stack stack, - Library library, Resources resources, - boolean isTint) { - Object o = stack.peek(); - // if a name then we are dealing with a pattern - if (o instanceof Name) { - Name patternName = (Name) stack.pop(); - Pattern pattern = resources.getPattern(patternName); - // Create or update the current PatternColorSpace with an instance - // of the current pattern. These object will be used later during - // fill, show text and Do with image masks. - if (graphicState.getStrokeColorSpace() instanceof PatternColor) { - PatternColor pc = (PatternColor) graphicState.getStrokeColorSpace(); - pc.setPattern(pattern); - } else { - PatternColor pc = new PatternColor(null, null); - pc.setPattern(pattern); - graphicState.setStrokeColorSpace(pc); - } - - // two cases to take into account: - // for none coloured tiling patterns we must parse the component - // values that specify colour. otherwise we just use the name - // for all other pattern types. - if (pattern instanceof TilingPattern) { - TilingPattern tilingPattern = (TilingPattern) pattern; - if (tilingPattern.getPaintType() == - TilingPattern.PAINTING_TYPE_UNCOLORED_TILING_PATTERN) { - // parsing is of the form 'C1...Cn name scn' - // first find out colour space specified by name - int compLength = graphicState.getStrokeColorSpace().getNumComponents(); - // peek and then pop until a none Float is found - int nCount = 0; - // next calculate the colour based ont he space and c1..Cn - float colour[] = new float[compLength]; - // peek and pop all of the colour floats - while (!stack.isEmpty() && stack.peek() instanceof Number && - nCount < compLength) { - colour[nCount] = ((Number) stack.pop()).floatValue(); - nCount++; - } - Color color = graphicState.getStrokeColorSpace().getColor(colour, isTint); - graphicState.setStrokeColor(color); - tilingPattern.setUnColored(color); - } - } - } else if (o instanceof Number) { - - // some pdfs encoding do not explicitly change the default colour - // space from the default DeviceGrey. The following code checks - // how many n values are available and if different then current - // graphicState.strokeColorSpace it is changed as needed - - // first get assumed number of components - int colorSpaceN = graphicState.getStrokeColorSpace().getNumComponents(); - - // peek and then pop until a none Float is found - int nCount = 0; - // set colour to max of 4 which is cymk, - int compLength = 4; - float colour[] = new float[compLength]; - // peek and pop all of the colour floats - while (!stack.isEmpty() && stack.peek() instanceof Number && - nCount < compLength) { - colour[nCount] = ((Number) stack.pop()).floatValue(); - nCount++; - } - - // check to see if nCount and colorSpaceN are the same - if (nCount != colorSpaceN) { - // change the colour state to nCount equivalent - graphicState.setStrokeColorSpace( - PColorSpace.getColorSpace(library, nCount)); - } - // shrink the array to the correct length - float[] f = new float[nCount]; - System.arraycopy(colour, 0, f, 0, nCount); - graphicState.setStrokeColor(graphicState.getStrokeColorSpace().getColor(f, isTint)); - } - } - - protected static void consume_sc(GraphicsState graphicState, Stack stack, - Library library, Resources resources, boolean isTint) { - Object o = null; - if (!stack.isEmpty()) { - o = stack.peek(); - } - // if a name then we are dealing with a pattern. - if (o instanceof Name) { - Name patternName = (Name) stack.pop(); - Pattern pattern = resources.getPattern(patternName); - // Create or update the current PatternColorSpace with an instance - // of the current pattern. These object will be used later during - // fill, show text and Do with image masks. - if (graphicState.getFillColorSpace() instanceof PatternColor) { - PatternColor pc = (PatternColor) graphicState.getFillColorSpace(); - pc.setPattern(pattern); - } else { - PatternColor pc = new PatternColor(library, null); - pc.setPattern(pattern); - graphicState.setFillColorSpace(pc); - } - - // two cases to take into account: - // for none coloured tiling patterns we must parse the component - // values that specify colour. otherwise we just use the name - // for all other pattern types. - if (pattern instanceof TilingPattern) { - TilingPattern tilingPattern = (TilingPattern) pattern; - if (tilingPattern.getPaintType() == - TilingPattern.PAINTING_TYPE_UNCOLORED_TILING_PATTERN) { - // parsing is of the form 'C1...Cn name scn' - // first find out colour space specified by name - int compLength = graphicState.getFillColorSpace().getNumComponents(); - // peek and then pop until a none Float is found - int nCount = 0; - // next calculate the colour based ont he space and c1..Cn - float colour[] = new float[compLength]; - // peek and pop all of the colour floats - while (!stack.isEmpty() && stack.peek() instanceof Number && - nCount < compLength) { - colour[nCount] = ((Number) stack.pop()).floatValue(); - nCount++; - } - // fill colour to be used when painting. - Color color = graphicState.getFillColorSpace().getColor(colour, isTint); - graphicState.setFillColor(color); - tilingPattern.setUnColored(color); - } - } - } else if (o instanceof Number) { - // some PDFs encoding do not explicitly change the default colour - // space from the default DeviceGrey. The following code checks - // how many n values are available and if different then current - // graphicState.fillColorSpace it is changed as needed - - // first get assumed number of components - int colorSpaceN = graphicState.getFillColorSpace().getNumComponents(); - - // peek and then pop until a none Float is found - int nCount = 0; - // set colour to max of 4 which is cymk, - // we have a corner case where 5 components are defined and once - // pushed throw the function produce a valid color. - int compLength = 5; - float colour[] = new float[compLength]; - // peek and pop all of the colour floats - while (!stack.isEmpty() && stack.peek() instanceof Number && - nCount < compLength) { - colour[nCount] = ((Number) stack.pop()).floatValue(); - nCount++; - } - - // check to see if nCount and colorSpaceN are the same - if (nCount != colorSpaceN) { - // change the colour state to nCount equivalent - graphicState.setFillColorSpace( - PColorSpace.getColorSpace(library, nCount)); - } - // shrink the array to the correct length - float[] f = new float[nCount]; - System.arraycopy(colour, 0, f, 0, nCount); - graphicState.setFillColor(graphicState.getFillColorSpace().getColor(f, true)); - } - } - - protected static GraphicsState consume_q(GraphicsState graphicState) { - return graphicState.save(); - } - - protected GraphicsState consume_Q(GraphicsState graphicState, Shapes shapes) { - GraphicsState gs1 = graphicState.restore(); - // point returned stack - if (gs1 != null) { - graphicState = gs1; - } - // otherwise start a new stack - else { - graphicState = new GraphicsState(shapes); - graphicState.set(new AffineTransform()); - shapes.add(noClipDrawCmd); - } - - return graphicState; - } - - protected static void consume_cm(GraphicsState graphicState, Stack stack, - boolean inTextBlock, AffineTransform textBlockBase) { - float f = ((Number) stack.pop()).floatValue(); - float e = ((Number) stack.pop()).floatValue(); - float d = ((Number) stack.pop()).floatValue(); - float c = ((Number) stack.pop()).floatValue(); - float b = ((Number) stack.pop()).floatValue(); - float a = ((Number) stack.pop()).floatValue(); - // get the current CTM - AffineTransform af = new AffineTransform(graphicState.getCTM()); - // do the matrix concatenation math - af.concatenate(new AffineTransform(a, b, c, d, e, f)); - // add the transformation to the graphics state - graphicState.set(af); - // update the clip, translate by this CM - graphicState.updateClipCM(new AffineTransform(a, b, c, d, e, f)); - // apply the cm just as we would a tm - if (inTextBlock) { - // update the textBlockBase with the cm matrix - af = new AffineTransform(textBlockBase); - // apply the transform - graphicState.getTextState().tmatrix = new AffineTransform(a, b, c, d, e, f); - af.concatenate(graphicState.getTextState().tmatrix); - graphicState.set(af); - // update the textBlockBase as the tm was specified in the BT block - // and we still need to keep the offset. - textBlockBase.setTransform(new AffineTransform(graphicState.getCTM())); - } - } - - protected static void consume_i(Stack stack) { - if (stack.size() >= 1) { - stack.pop(); - } - } - - protected static void consume_J(GraphicsState graphicState, Stack stack, Shapes shapes) { -// collectTokenFrequency(PdfOps.J_TOKEN); - // get the value from the stack - graphicState.setLineCap((int) (((Number) stack.pop()).floatValue())); - // Butt cap, stroke is squared off at the endpoint of the path - // there is no projection beyond the end of the path - if (graphicState.getLineCap() == 0) { - graphicState.setLineCap(BasicStroke.CAP_BUTT); - } - // Round cap, a semicircular arc with a diameter equal to the line - // width is drawn around the endpoint and filled in - else if (graphicState.getLineCap() == 1) { - graphicState.setLineCap(BasicStroke.CAP_ROUND); - } - // Projecting square cap. The stroke continues beyond the endpoint - // of the path for a distance equal to half the line width and is - // then squared off. - else if (graphicState.getLineCap() == 2) { - graphicState.setLineCap(BasicStroke.CAP_SQUARE); - } - // Mark the stroke as being changed and store state in the - // shapes object - setStroke(shapes, graphicState); - } - - /** - * Process the xObject content. - * - * @param graphicState graphic state to appent - * @param stack stack of object being parsed. - * @param shapes shapes object. - * @param resources associated resources. - * @param viewParse true indicates parsing is for a normal view. If false - * the consumption of Do will skip Image based xObjects for performance. - */ - protected static GraphicsState consume_Do(GraphicsState graphicState, Stack stack, - Shapes shapes, Resources resources, - boolean viewParse, // events - AtomicInteger imageIndex, Page page) { - Name xobjectName = (Name) stack.pop(); - if (resources == null) return graphicState; - // Form XObject - Object xObject = resources.getXObject(xobjectName); - if (xObject instanceof Form) { - // Do operator steps: - // 1.)save the graphics context - graphicState = graphicState.save(); - // Try and find the named reference 'xobjectName', pass in a copy - // of the current graphics state for the new content stream - Form formXObject = (Form) xObject; - if (formXObject != null) { - // check if the form is an optional content group. - Object oc = formXObject.getObject(OptionalContent.OC_KEY); - if (oc != null) { - OptionalContent optionalContent = resources.getLibrary().getCatalog().getOptionalContent(); - optionalContent.init(); - if (!optionalContent.isVisible(oc)) { - return graphicState; - } - } - // init form XObject with current gs state but we need to keep the original state for blending - GraphicsState xformGraphicsState = - new GraphicsState(graphicState); - formXObject.setGraphicsState(xformGraphicsState); - if (formXObject.isTransparencyGroup()) { - // assign the state to the graphic state for later - // processing during the paint - xformGraphicsState.setTransparencyGroup(formXObject.isTransparencyGroup()); - xformGraphicsState.setIsolated(formXObject.isIsolated()); - xformGraphicsState.setKnockOut(formXObject.isKnockOut()); - } - // according to spec the formXObject might not have - // resources reference as a result we pass in the current - // one in the hope that any resources can be found. - formXObject.setParentResources(resources); - formXObject.init(); - // 2.) concatenate matrix entry with the current CTM - AffineTransform af = - new AffineTransform(graphicState.getCTM()); - af.concatenate(formXObject.getMatrix()); - shapes.add(new TransformDrawCmd(af)); - // 3.) Clip according to the form BBox entry - if (graphicState.getClip() != null) { - AffineTransform matrix = formXObject.getMatrix(); - Area bbox = new Area(formXObject.getBBox()); - Area clip = graphicState.getClip(); - // create inverse of matrix so we can transform - // the clip to form space. - try { - matrix = matrix.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.warning("Error create xObject matrix inverse"); - } - // apply the new clip now that they are in the - // same space. - Shape shape = matrix.createTransformedShape(clip); - bbox.intersect(new Area(shape)); - shapes.add(new ShapeDrawCmd(bbox)); - } else { - shapes.add(new ShapeDrawCmd(formXObject.getBBox())); - } - shapes.add(clipDrawCmd); - // 4.) Paint the graphics objects in font stream. - // still some work to do do here with regards to BM vs. alpha comp. - if ((formXObject.getExtGState() != null && - (formXObject.getExtGState().getBlendingMode() == null || - formXObject.getExtGState().getBlendingMode().equals(BlendComposite.NORMAL_VALUE)))) { - setAlpha(formXObject.getShapes(), graphicState, graphicState.getAlphaRule(), - graphicState.getFillAlpha()); - setAlpha(shapes, graphicState, graphicState.getAlphaRule(), - graphicState.getFillAlpha()); - } - // If we have a transparency group we paint it - // slightly different then a regular xObject as we - // need to capture the alpha which is only possible - // by paint the xObject to an image. - if (!disableTransparencyGroups && - ((formXObject.getBBox().getWidth() < FormDrawCmd.MAX_IMAGE_SIZE && formXObject.getBBox().getWidth() > 1) && - (formXObject.getBBox().getHeight() < FormDrawCmd.MAX_IMAGE_SIZE && formXObject.getBBox().getHeight() > 1) - && (formXObject.getExtGState() != null && - (formXObject.getExtGState().getSMask() != null || formXObject.getExtGState().getBlendingMode() != null - || (formXObject.getExtGState().getNonStrokingAlphConstant() < 1 - && formXObject.getExtGState().getNonStrokingAlphConstant() > 0))) - )) { - // add the hold form for further processing. - shapes.add(new FormDrawCmd(formXObject)); - } - // the down side of painting to an image is that we - // lose quality if there is a affine transform, so - // if it isn't a group transparency we paint old way - // by just adding the objects to the shapes stack. - else { - shapes.add(new ShapesDrawCmd(formXObject.getShapes())); - } - // update text sprites with geometric path state - if (formXObject.getShapes() != null && - formXObject.getShapes().getPageText() != null) { - // normalize each sprite. - AffineTransform pageSpace = graphicState.getCTM(); - pageSpace.concatenate(formXObject.getMatrix()); - formXObject.getShapes().getPageText() - .applyXObjectTransform(pageSpace); - // add the text to the current shapes for extraction and - // selection purposes. - PageText pageText = formXObject.getShapes().getPageText(); - if (pageText != null && pageText.getPageLines() != null) { - shapes.getPageText().addPageLines( - pageText.getPageLines()); - } - } - shapes.add(new NoClipDrawCmd()); - } - // 5.) Restore the saved graphics state - graphicState = graphicState.restore(); - } - // Image XObject - else if (viewParse) { - ImageStream imageStream = (ImageStream) xObject; - if (imageStream != null) { - Object oc = imageStream.getObject(OptionalContent.OC_KEY); - if (oc != null) { - OptionalContent optionalContent = resources.getLibrary().getCatalog().getOptionalContent(); - optionalContent.init(); - // avoid loading the image if oc is not visible - // may have to add this logic to the stack for dynamic content - // if we get an example. - if (!optionalContent.isEmptyDefinition() && !optionalContent.isVisible(oc)) { - return graphicState; - } - } - - // create an ImageReference for future decoding - ImageReference imageReference = ImageReferenceFactory.getImageReference( - imageStream, resources, graphicState, - imageIndex.get(), page); - imageIndex.incrementAndGet(); - - if (imageReference != null) { - AffineTransform af = - new AffineTransform(graphicState.getCTM()); - graphicState.scale(1, -1); - graphicState.translate(0, -1); - // add the image - shapes.add(new ImageDrawCmd(imageReference)); - graphicState.set(af); - } - } - } - return graphicState; - } - - protected static void consume_d(GraphicsState graphicState, Stack stack, Shapes shapes) { - float dashPhase; - float[] dashArray; - try { - // pop dashPhase off the stack - dashPhase = Math.abs(((Number) stack.pop()).floatValue()); - // pop the dashVector of the stack - java.util.List dashVector = (java.util.List) stack.pop(); - // if the dash vector size is zero we have a default none dashed - // line and thus we skip out - if (!dashVector.isEmpty() && dashVector.get(0) != null) { - // convert dash vector to a array of floats - final int sz = dashVector.size(); - dashArray = new float[sz]; - Object tmp; - boolean nullArray = false; - for (int i = 0; i < sz; i++) { - tmp = dashVector.get(i); - float dash; - if (tmp != null && tmp instanceof Number) { - dash = Math.abs(((Number) dashVector.get(i)).floatValue()); - // java has a hard time with painting dash array with values < 0.05. - // null the dash array as we can't pain it PDF-966. - if (dash < 0.05f) nullArray = true; - dashArray[i] = dash; - } - } - // corner case check to see if the dash array contains a first element - // that is very different then second which is likely the result of - // a itext/MS office bug where a dash element of the array isn't scaled to - // user space. - if (dashArray.length > 1 && dashArray[0] != 0) { - boolean isOffice = false; - int spread = 10000; - for (int i = 0, max = dashArray.length - 1; i < max; i++) { - float diff = dashArray[i] - dashArray[i + 1]; - if (diff > spread || diff < -spread) { - isOffice = true; - break; - } - } - if (isOffice) { - for (int i = 0, max = dashArray.length; i < max; i++) { - if (dashArray[i] < 10) { - // scale to PDF space. - dashArray[i] = dashArray[i] * 1000; - } - } - } - } - // null the dash array if one of the dash values was less then 0.05. - if (nullArray) { - dashArray = null; - } - } - // default to standard black line - else { - dashPhase = 0; - dashArray = null; - } - // assign state now that everything is assumed good - // from a class cast exception point of view. - graphicState.setDashArray(dashArray); - graphicState.setDashPhase(dashPhase); - } catch (ClassCastException e) { - logger.log(Level.FINE, "Dash pattern syntax error: ", e); - } - // update stroke state with possibly new dash data. - setStroke(shapes, graphicState); - } - - protected static void consume_j(GraphicsState graphicState, Stack stack, Shapes shapes) { - // grab the value - graphicState.setLineJoin((int) (((Number) stack.pop()).floatValue())); - // Miter Join - the outer edges of the strokes for the two - // segments are extended until they meet at an angle, like a picture - // frame - if (graphicState.getLineJoin() == 0) { - graphicState.setLineJoin(BasicStroke.JOIN_MITER); - } - // Round join - an arc of a circle with a diameter equal to the line - // width is drawn around the point where the two segments meet, - // connecting the outer edges of the strokes for the two segments - else if (graphicState.getLineJoin() == 1) { - graphicState.setLineJoin(BasicStroke.JOIN_ROUND); - } - // Bevel join - The two segments are finished with butt caps and the - // ends of the segments is filled with a triangle - else if (graphicState.getLineJoin() == 2) { - graphicState.setLineJoin(BasicStroke.JOIN_BEVEL); - } - // updates shapes with with the new stroke type - setStroke(shapes, graphicState); - } - - protected static void consume_w(GraphicsState graphicState, Stack stack, - Shapes shapes, float glyph2UserSpaceScale) { - // apply any type3 font scalling which is set via the glyph2User space affine transform. - if (!stack.isEmpty()) { - float scale = ((Number) stack.pop()).floatValue() * glyph2UserSpaceScale; - graphicState.setLineWidth(scale); - setStroke(shapes, graphicState); - } - } - - protected static void consume_M(GraphicsState graphicState, Stack stack, Shapes shapes) { - graphicState.setMiterLimit(((Number) stack.pop()).floatValue()); - setStroke(shapes, graphicState); - } - - protected static void consume_gs(GraphicsState graphicState, Stack stack, Resources resources, Shapes shapes) { - Object gs = stack.pop(); - if (gs instanceof Name && resources != null) { - // Get ExtGState and merge it with - ExtGState extGState = - resources.getExtGState((Name) gs); - if (extGState != null) { - graphicState.concatenate(extGState); - } - float alpha = graphicState.getFillAlpha(); - if (graphicState.getExtGState() != null - && graphicState.getExtGState().getBlendingMode() != null // && graphicState.getExtGState().getOverprintMode() == 1 - ) { - // BlendComposite is still having trouble with alpha values < 1.0. - shapes.add(new BlendCompositeDrawCmd(graphicState.getExtGState().getBlendingMode(), alpha)); - } - // apply the alpha as it's own composite - if (alpha > 0 && alpha < 1.0) - setAlpha(shapes, graphicState, graphicState.getAlphaRule(), graphicState.getFillAlpha()); - } - } - - protected static void consume_Tf(GraphicsState graphicState, Stack stack, Resources resources) { - float size = ((Number) stack.pop()).floatValue(); - Name name2 = (Name) stack.pop(); - // build the new font and initialize it. - graphicState.getTextState().tsize = size; - graphicState.getTextState().fontName = name2; - graphicState.getTextState().font = resources.getFont(name2); - // in the rare case that the font can't be found then we try and build - // one so the document can be rendered in some shape or form. - if (graphicState.getTextState().font == null || - graphicState.getTextState().font.getFont() == null) { - // turn on the old awt font engine, as we have a null font -// FontFactory fontFactory = FontFactory.getInstance(); -// boolean awtState = fontFactory.isAwtFontSubstitution(); -// fontFactory.setAwtFontSubstitution(true); - try { - // this should almost never happen but of course we have a few - // corner cases: - // get the first pages resources, no need to lock the page, already locked. - Page page = resources.getLibrary().getCatalog().getPageTree().getPage(0); - page.initPageResources(); - Resources res = page.getResources(); - // try and get a font off the first page. - Object pageFonts = res.getEntries().get(Resources.FONT_KEY); - // check for an indirect reference - if (pageFonts instanceof Reference) { - pageFonts = resources.getLibrary().getObject((Reference) pageFonts); - } - if (pageFonts instanceof HashMap) { - // get first font - Reference fontRef = (Reference) ((HashMap) pageFonts).get(name2); - if (fontRef != null) { - graphicState.getTextState().font = - (org.icepdf.core.pobjects.fonts.Font) resources.getLibrary() - .getObject(fontRef); - graphicState.getTextState().font.init(); - } - } - } catch (Throwable throwable) { - // keep block protected as we don't want to accidentally turn off - // the font engine. - logger.warning("Warning could not find font by named resource " + name2); - } - // return factory to original state. -// fontFactory.setAwtFontSubstitution(awtState); - // if no fonts found then we just bail and accept the null pointer - } - if (graphicState.getTextState().font != null) { - graphicState.getTextState().currentfont = - graphicState.getTextState().font.getFont().deriveFont(size); - } else { - // not font found which is a problem, so we need to check for interactive form dictionary - graphicState.getTextState().font = resources.getLibrary().getInteractiveFormFont(name2.getName()); - if (graphicState.getTextState().font != null) { - graphicState.getTextState().currentfont = graphicState.getTextState().font.getFont(); - graphicState.getTextState().currentfont = - graphicState.getTextState().font.getFont().deriveFont(size); - } - } - } - - protected static void consume_Tc(GraphicsState graphicState, Stack stack) { - graphicState.getTextState().cspace = ((Number) stack.pop()).floatValue(); - } - - protected static void consume_tm(GraphicsState graphicState, Stack stack, - TextMetrics textMetrics, - PageText pageText, - double previousBTStart, - AffineTransform textBlockBase, - LinkedList oCGs) { - textMetrics.setShift(0); - textMetrics.setPreviousAdvance(0); - textMetrics.getAdvance().setLocation(0, 0); - // pop carefully, as there are few corner cases where - // the af is split up with a BT or other token - Object next; - // initialize an identity matrix, add parse out the - // numbers we have working from f6 down to f1. - float[] tm = new float[]{1f, 0, 0, 1f, 0, 0}; - for (int i = 0, hits = 5, max = stack.size(); hits != -1 && i < max; i++) { - next = stack.pop(); - if (next instanceof Number) { - tm[hits] = ((Number) next).floatValue(); - hits--; - } - } - AffineTransform af = new AffineTransform(textBlockBase); - - // grab old values. -// double oldTransY = graphicState.getCTM().getTranslateY(); -// double oldScaleY = graphicState.getCTM().getScaleY(); - - // apply the transform - graphicState.getTextState().tmatrix = new AffineTransform(tm); - af.concatenate(graphicState.getTextState().tmatrix); - graphicState.set(af); - graphicState.scale(1, -1); - - // text extraction logic - // capture x coord of BT y offset, tm, Td, TD. - if (textMetrics.isYstart()) { - textMetrics.setyBTStart(tm[5]); - textMetrics.setYstart(false); - } - - // update the extract text - pageText.setTextTransform(new AffineTransform(tm)); - - } - - protected static void consume_T_star(GraphicsState graphicState, - TextMetrics textMetrics, PageText pageText, - LinkedList oCGs) { - graphicState.translate(-textMetrics.getShift(), 0); - textMetrics.setShift(0); - textMetrics.setPreviousAdvance(0); - textMetrics.getAdvance().setLocation(0, 0); - graphicState.translate(0, graphicState.getTextState().leading); - // always indicates a new line - pageText.newLine(oCGs); - } - - protected static void consume_TD(GraphicsState graphicState, Stack stack, - TextMetrics textMetrics, - PageText pageText, - LinkedList oCGs) { - float y = ((Number) stack.pop()).floatValue(); - float x = ((Number) stack.pop()).floatValue(); - graphicState.translate(-textMetrics.getShift(), 0); - textMetrics.setShift(0); - textMetrics.setPreviousAdvance(0); - textMetrics.getAdvance().setLocation(0, 0); - graphicState.translate(x, -y); - graphicState.getTextState().leading = -y; - - // capture x coord of BT y offset, tm, Td, TD. - if (textMetrics.isYstart()) { - textMetrics.setyBTStart(y); - textMetrics.setYstart(false); - } - } - - protected static void consume_double_quote(GraphicsState graphicState, Stack stack, - Shapes shapes, - TextMetrics textMetrics, - GlyphOutlineClip glyphOutlineClip, - LinkedList oCGs) { - StringObject stringObject = (StringObject) stack.pop(); - graphicState.getTextState().cspace = ((Number) stack.pop()).floatValue(); - graphicState.getTextState().wspace = ((Number) stack.pop()).floatValue(); - graphicState.translate(-textMetrics.getShift(), graphicState.getTextState().leading); - - // apply transparency - setAlpha(shapes, graphicState, graphicState.getAlphaRule(), graphicState.getFillAlpha()); - - textMetrics.setShift(0); - textMetrics.setPreviousAdvance(0); - textMetrics.getAdvance().setLocation(0, 0); - TextState textState = graphicState.getTextState(); - - AffineTransform tmp = applyTextScaling(graphicState); - drawString(stringObject.getLiteralStringBuffer( - textState.font.getSubTypeFormat(), - textState.font.getFont()), - textMetrics, graphicState.getTextState(), - shapes, glyphOutlineClip, graphicState, oCGs); - graphicState.set(tmp); - graphicState.translate(textMetrics.getAdvance().x, 0); - float shift = textMetrics.getShift(); - shift += textMetrics.getAdvance().x; - textMetrics.setShift(shift); - } - - protected static void consume_single_quote(GraphicsState graphicState, Stack stack, - Shapes shapes, - TextMetrics textMetrics, - GlyphOutlineClip glyphOutlineClip, - LinkedList oCGs) { - // ' = T* + Tj, who knew? - consume_T_star(graphicState, textMetrics, shapes.getPageText(), oCGs); - consume_Tj(graphicState, stack, shapes, textMetrics, glyphOutlineClip, oCGs); - } - - protected static void consume_Td(GraphicsState graphicState, Stack stack, - TextMetrics textMetrics, - PageText pageText, - double previousBTStart, - LinkedList oCGs) { - float y = ((Number) stack.pop()).floatValue(); - float x = ((Number) stack.pop()).floatValue(); - graphicState.translate(-textMetrics.getShift(), 0); - textMetrics.setShift(0); - textMetrics.setPreviousAdvance(0); - textMetrics.getAdvance().setLocation(0, 0); - // x,y are expressed in unscaled but we don't scale until - // a text showing operator is called. - graphicState.translate(x, -y); - // capture x coord of BT y offset, tm, Td, TD. - if (textMetrics.isYstart()) { - float newY = (float) graphicState.getCTM().getTranslateY(); - textMetrics.setyBTStart(newY); - textMetrics.setYstart(false); - } - } - - protected static void consume_Tz(GraphicsState graphicState, Stack stack) { - Object ob = stack.pop(); - if (ob instanceof Number) { - float hScaling = ((Number) ob).floatValue(); - // store the scaled value, but not apply the state operator at this time - graphicState.getTextState().hScalling = hScaling / 100.0f; - } - } - - protected static void consume_Tw(GraphicsState graphicState, Stack stack) { - graphicState.getTextState().wspace = ((Number) stack.pop()).floatValue(); - } - - protected static void consume_Tr(GraphicsState graphicState, Stack stack) { - graphicState.getTextState().rmode = (int) ((Number) stack.pop()).floatValue(); - } - - protected static void consume_TL(GraphicsState graphicState, Stack stack) { - graphicState.getTextState().leading = ((Number) stack.pop()).floatValue(); - } - - protected static void consume_Ts(GraphicsState graphicState, Stack stack) { - graphicState.getTextState().trise = ((Number) stack.pop()).floatValue(); - } - - protected static GeneralPath consume_L(Stack stack, - GeneralPath geometricPath) { - float y = ((Number) stack.pop()).floatValue(); - float x = ((Number) stack.pop()).floatValue(); - if (geometricPath == null) { - geometricPath = new GeneralPath(); - } - geometricPath.lineTo(x, y); - return geometricPath; - } - - protected static GeneralPath consume_m(Stack stack, - GeneralPath geometricPath) { - if (geometricPath == null) { - geometricPath = new GeneralPath(); - } - if (stack.size() >= 2) { - float y = ((Number) stack.pop()).floatValue(); - float x = ((Number) stack.pop()).floatValue(); - geometricPath.moveTo(x, y); - } - return geometricPath; - } - - protected static GeneralPath consume_c(Stack stack, - GeneralPath geometricPath) { - if (!stack.isEmpty()) { - float y3 = ((Number) stack.pop()).floatValue(); - float x3 = ((Number) stack.pop()).floatValue(); - float y2 = ((Number) stack.pop()).floatValue(); - float x2 = ((Number) stack.pop()).floatValue(); - float y1 = ((Number) stack.pop()).floatValue(); - float x1 = ((Number) stack.pop()).floatValue(); - if (geometricPath == null) { - geometricPath = new GeneralPath(); - } - geometricPath.curveTo(x1, y1, x2, y2, x3, y3); - } - return geometricPath; - } - - protected static GeneralPath consume_S(GraphicsState graphicState, - Shapes shapes, - GeneralPath geometricPath) throws InterruptedException { - if (geometricPath != null) { - commonStroke(graphicState, shapes, geometricPath); - geometricPath = null; - } - return geometricPath; - } - - protected static GeneralPath consume_F(GraphicsState graphicState, - Shapes shapes, - GeneralPath geometricPath) - throws NoninvertibleTransformException, InterruptedException { - if (geometricPath != null) { - geometricPath.setWindingRule(GeneralPath.WIND_NON_ZERO); - commonFill(shapes, graphicState, geometricPath); - } - geometricPath = null; - return geometricPath; - } - - protected static GeneralPath consume_f(GraphicsState graphicState, - Shapes shapes, - GeneralPath geometricPath) - throws NoninvertibleTransformException, InterruptedException { - if (geometricPath != null) { - geometricPath.setWindingRule(GeneralPath.WIND_NON_ZERO); - commonFill(shapes, graphicState, geometricPath); - } - geometricPath = null; - return geometricPath; - } - - protected static GeneralPath consume_re(Stack stack, - GeneralPath geometricPath) { - if (geometricPath == null) { - geometricPath = new GeneralPath(); - } - float h = ((Number) stack.pop()).floatValue(); - float w = ((Number) stack.pop()).floatValue(); - float y = ((Number) stack.pop()).floatValue(); - float x = ((Number) stack.pop()).floatValue(); - geometricPath.moveTo(x, y); - geometricPath.lineTo(x + w, y); - geometricPath.lineTo(x + w, y + h); - geometricPath.lineTo(x, y + h); - geometricPath.lineTo(x, y); - return geometricPath; - } - - protected static void consume_h(GeneralPath geometricPath) { - if (geometricPath != null) { - geometricPath.closePath(); - } - } - - protected static void consume_BDC(Stack stack, - Shapes shapes, - LinkedList oCGs, - Resources resources) throws InterruptedException { - Object properties = stack.pop();// properties - Name tag = (Name) stack.pop();// tag - OptionalContents optionalContents = null; - // try and process the Optional content. - if (tag.equals(OptionalContent.OC_KEY)) { - if (properties instanceof Name) { - optionalContents = - resources.getPropertyEntry((Name) properties); - // make sure the reference is valid, no point - // jumping through all the hopes if we don't have too. - if (optionalContents != null) { - optionalContents.init(); - // valid OC, add a marker command to the stack. - shapes.add(new OCGStartDrawCmd(optionalContents)); - } - } - } - if (optionalContents == null) { - // create a temporary optional object. - Name tmp = OptionalContent.NONE_OC_FLAG; - if (properties instanceof Name) { - tmp = (Name) properties; - } - optionalContents = new OptionalContentGroup(tmp.getName(), true); - } - if (oCGs != null) { - oCGs.add(optionalContents); - } - } - - protected static void consume_EMC(Shapes shapes, - LinkedList oCGs) { - // add the new draw command to the stack. - // restore the main stack. - if (oCGs != null && !oCGs.isEmpty()) { - OptionalContents optionalContents = oCGs.removeLast(); - // mark the end of an OCG. - if (optionalContents.isOCG()) { - // push the OC end command on the shapes - shapes.add(new OCGEndDrawCmd()); - } - } - } - - protected static void consume_BMC(Stack stack, - Shapes shapes, - LinkedList oCGs, - Resources resources) throws InterruptedException { - Object properties = stack.pop();// properties - // try and process the Optional content. - if (properties instanceof Name && resources != null) { - OptionalContents optionalContents = - resources.getPropertyEntry((Name) properties); - // make sure the reference is valid, no point - // jumping through all the hopes if we don't have too. - if (optionalContents != null) { - optionalContents.init(); - shapes.add(new OCGStartDrawCmd(optionalContents)); - } else { - Name tmp = (Name) properties; - optionalContents = - new OptionalContentGroup(tmp.getName(), true); - } - if (oCGs != null) { - oCGs.add(optionalContents); - } - } - } - - protected static GeneralPath consume_f_star(GraphicsState graphicState, - Shapes shapes, - GeneralPath geometricPath) - throws NoninvertibleTransformException, InterruptedException { - if (geometricPath != null) { - // need to apply pattern.. - geometricPath.setWindingRule(GeneralPath.WIND_EVEN_ODD); - commonFill(shapes, graphicState, geometricPath); - } - geometricPath = null; - return geometricPath; - } - - protected static GeneralPath consume_b(GraphicsState graphicState, - Shapes shapes, - GeneralPath geometricPath) - throws NoninvertibleTransformException, InterruptedException { - if (geometricPath != null) { - geometricPath.setWindingRule(GeneralPath.WIND_NON_ZERO); - geometricPath.closePath(); - commonFill(shapes, graphicState, geometricPath); - commonStroke(graphicState, shapes, geometricPath); - } - geometricPath = null; - return geometricPath; - } - - protected static GeneralPath consume_n(GeneralPath geometricPath) - throws NoninvertibleTransformException { - geometricPath = null; - return geometricPath; - } - - protected static void consume_W(GraphicsState graphicState, GeneralPath geometricPath) - throws NoninvertibleTransformException { - if (geometricPath != null) { - geometricPath.setWindingRule(GeneralPath.WIND_NON_ZERO); - geometricPath.closePath(); - graphicState.setClip(geometricPath); - } - } - - protected static void consume_v(Stack stack, - GeneralPath geometricPath) { - float y3 = ((Number) stack.pop()).floatValue(); - float x3 = ((Number) stack.pop()).floatValue(); - float y2 = ((Number) stack.pop()).floatValue(); - float x2 = ((Number) stack.pop()).floatValue(); - geometricPath.curveTo( - (float) geometricPath.getCurrentPoint().getX(), - (float) geometricPath.getCurrentPoint().getY(), - x2, - y2, - x3, - y3); - } - - protected static void consume_y(Stack stack, - GeneralPath geometricPath) { - float y3 = ((Number) stack.pop()).floatValue(); - float x3 = ((Number) stack.pop()).floatValue(); - float y1 = ((Number) stack.pop()).floatValue(); - float x1 = ((Number) stack.pop()).floatValue(); - geometricPath.curveTo(x1, y1, x3, y3, x3, y3); - } - - protected static GeneralPath consume_B(GraphicsState graphicState, - Shapes shapes, - GeneralPath geometricPath) - throws NoninvertibleTransformException, InterruptedException { - if (geometricPath != null) { - geometricPath.setWindingRule(GeneralPath.WIND_NON_ZERO); - commonFill(shapes, graphicState, geometricPath); - commonStroke(graphicState, shapes, geometricPath); - } - geometricPath = null; - return geometricPath; - } - - protected static GraphicsState consume_d0(GraphicsState graphicState, Stack stack) { - // save the stack - graphicState = graphicState.save(); - // need two pops to get Wx and Wy data - float y = ((Number) stack.pop()).floatValue(); - float x = ((Number) stack.pop()).floatValue(); - TextState textState = graphicState.getTextState(); - textState.setType3HorizontalDisplacement(new Point.Float(x, y)); - return graphicState; - } - - protected static GeneralPath consume_s(GraphicsState graphicState, - Shapes shapes, - GeneralPath geometricPath) throws InterruptedException { - if (geometricPath != null) { - geometricPath.closePath(); - commonStroke(graphicState, shapes, geometricPath); - geometricPath = null; - } - return geometricPath; - } - - protected static GeneralPath consume_b_star(GraphicsState graphicState, - Shapes shapes, - GeneralPath geometricPath) - throws NoninvertibleTransformException, InterruptedException { - if (geometricPath != null) { - geometricPath.setWindingRule(GeneralPath.WIND_EVEN_ODD); - geometricPath.closePath(); - commonStroke(graphicState, shapes, geometricPath); - commonFill(shapes, graphicState, geometricPath); - } - geometricPath = null; - return geometricPath; - } - - protected static GraphicsState consume_d1(GraphicsState graphicState, Stack stack) { - // save the stack - graphicState = graphicState.save(); - // need two pops to get Wx and Wy data - float x2 = ((Number) stack.pop()).floatValue(); - float y2 = ((Number) stack.pop()).floatValue(); - float x1 = ((Number) stack.pop()).floatValue(); - float y1 = ((Number) stack.pop()).floatValue(); - float y = ((Number) stack.pop()).floatValue(); - float x = ((Number) stack.pop()).floatValue(); - TextState textState = graphicState.getTextState(); - textState.setType3HorizontalDisplacement( - new Point2D.Float(x, y)); - textState.setType3BBox(new PRectangle( - new Point2D.Float(x1, y1), - new Point2D.Float(x2, y2))); - return graphicState; - } - - protected static GeneralPath consume_B_star(GraphicsState graphicState, - Shapes shapes, - GeneralPath geometricPath) - throws NoninvertibleTransformException, InterruptedException { - if (geometricPath != null) { - geometricPath.setWindingRule(GeneralPath.WIND_EVEN_ODD); - commonStroke(graphicState, shapes, geometricPath); - commonFill(shapes, graphicState, geometricPath); - } - geometricPath = null; - return geometricPath; - } - - public static void consume_W_star(GraphicsState graphicState, - GeneralPath geometricPath) { - if (geometricPath != null) { - geometricPath.setWindingRule(GeneralPath.WIND_EVEN_ODD); - geometricPath.closePath(); - graphicState.setClip(geometricPath); - } - } - - public static void consume_DP(Stack stack) { - stack.pop(); // properties - stack.pop(); // name - } - - public static void consume_MP(Stack stack) { - stack.pop(); - } - - public static void consume_sh(GraphicsState graphicState, Stack stack, - Shapes shapes, - Resources resources) throws InterruptedException { - Object o = stack.peek(); - // if a name then we are dealing with a pattern. - if (o instanceof Name) { - Name patternName = (Name) stack.pop(); - Pattern pattern = resources.getShading(patternName); - if (pattern != null) { - pattern.init(graphicState); - // we paint the shape and color shading as defined - // by the pattern dictionary and respect the current clip - // TODO further work is needed here to build out the pattern fill. - if (graphicState.getExtGState() != null && - graphicState.getExtGState().getSMask() != null) { - setAlpha(shapes, graphicState, - graphicState.getAlphaRule(), - 0.50f); - } else { - setAlpha(shapes, graphicState, - graphicState.getAlphaRule(), - graphicState.getFillAlpha()); - } - shapes.add(new PaintDrawCmd(pattern.getPaint())); - shapes.add(new ShapeDrawCmd(graphicState.getClip())); - shapes.add(new FillDrawCmd()); - } else { - // apply the current fill color along ith a little alpha - // to at least try to paint a colour for an unsupported mesh - // type pattern. - setAlpha(shapes, graphicState, - graphicState.getAlphaRule(), - 0.50f); - shapes.add(new PaintDrawCmd(graphicState.getFillColor())); - shapes.add(new ShapeDrawCmd(graphicState.getClip())); - shapes.add(new FillDrawCmd()); - } - } - } - - protected static void consume_TJ(GraphicsState graphicState, Stack stack, - Shapes shapes, - TextMetrics textMetrics, - GlyphOutlineClip glyphOutlineClip, - LinkedList oCGs) { - // apply scaling - AffineTransform tmp = applyTextScaling(graphicState); - // apply transparency - setAlpha(shapes, graphicState, graphicState.getAlphaRule(), graphicState.getFillAlpha()); - java.util.List v = (java.util.List) stack.pop(); - Number f; - StringObject stringObject; - TextState textState; - for (Object currentObject : v) { - if (currentObject instanceof StringObject) { - stringObject = (StringObject) currentObject; - textState = graphicState.getTextState(); - // draw string takes care of PageText extraction - drawString(stringObject.getLiteralStringBuffer( - textState.font.getSubTypeFormat(), - textState.font.getFont()), - textMetrics, - graphicState.getTextState(), shapes, glyphOutlineClip, - graphicState, oCGs); - } else if (currentObject instanceof Number) { - f = (Number) currentObject; - textMetrics.getAdvance().x -= (f.floatValue() / 1000f) * - graphicState.getTextState().currentfont.getSize(); - } - textMetrics.setPreviousAdvance(textMetrics.getAdvance().x); - } - graphicState.set(tmp); - } - - protected static void consume_Tj(GraphicsState graphicState, Stack stack, - Shapes shapes, - TextMetrics textMetrics, - GlyphOutlineClip glyphOutlineClip, - LinkedList oCGs) { - if (stack.size() != 0) { - Object tjValue = stack.pop(); - StringObject stringObject; - TextState textState; - if (tjValue instanceof StringObject) { - stringObject = (StringObject) tjValue; - textState = graphicState.getTextState(); - // apply scaling - AffineTransform tmp = applyTextScaling(graphicState); - // apply transparency - setAlpha(shapes, graphicState, graphicState.getAlphaRule(), graphicState.getFillAlpha()); - // draw string will take care of text pageText construction - drawString(stringObject.getLiteralStringBuffer( - textState.font.getSubTypeFormat(), - textState.font.getFont()), - textMetrics, - graphicState.getTextState(), - shapes, - glyphOutlineClip, - graphicState, oCGs); - graphicState.set(tmp); - } - } - } - - /** - * Utility method for calculating the advanceX need for the - * displayText given the strings parsed textState. Each of - * displayText glyphs and respective, text state is added to - * the shapes collection. - * - * @param displayText text that will be drawn to the screen - * @param textMetrics current advanceX of last drawn string, - * last advance of where the string should be drawn - * @param textState formating properties associated with displayText - * @param shapes collection of all shapes for page content being parsed. - */ - protected static void drawString( - StringBuilder displayText, - TextMetrics textMetrics, - TextState textState, - Shapes shapes, - GlyphOutlineClip glyphOutlineClip, - GraphicsState graphicState, - LinkedList oCGs) { - - float advanceX = textMetrics.getAdvance().x; - float advanceY = textMetrics.getAdvance().y; - - if (displayText.length() == 0) { - textMetrics.getAdvance().setLocation(textMetrics.getPreviousAdvance(), 0f); - return; - } - - // Postion of previous Glyph, all relative to text block - float lastx = 0, lasty = 0; - // Make sure that the previous advanceX is greater then then where we - // are going to place the next glyph, see not 57 in 1.6 spec for more - // information. - char currentChar = displayText.charAt(0); - // Position of the specified glyph relative to the origin of glyphVector - float firstCharWidth = (float) textState.currentfont.echarAdvance(currentChar).getX(); - - if ((advanceX + firstCharWidth) < textMetrics.getPreviousAdvance()) { - advanceX = textMetrics.getPreviousAdvance(); - } - - // Data need on font - FontFile currentFont = textState.currentfont; - boolean isVerticalWriting = textState.font.isVerticalWriting(); - // int spaceCharacter = currentFont.getSpaceEchar(); - - // font metrics data - float textRise = textState.trise; - float characterSpace = textState.cspace * textState.hScalling; - float whiteSpace = textState.wspace * textState.hScalling; - int textLength = displayText.length(); - - // create a new sprite to hold the text objects - TextSprite textSprites = - new TextSprite(currentFont, - textLength, - new AffineTransform(graphicState.getCTM()), - new AffineTransform(textState.tmatrix)); - - // glyph placement params - float currentX, currentY; - float newAdvanceX, newAdvanceY; - // Iterate through displayText to calculate the the new advanceX value - for (int i = 0; i < textLength; i++) { - currentChar = displayText.charAt(i); - - if (enabledFontFallback) { - boolean display = currentFont.canDisplayEchar(currentChar); - // slow display test, but allows us to fall back on a different font if needed. - if (!display) { - FontFile fontFile = FontManager.getInstance().getInstance(currentFont.getName(), 0); - textSprites.setFont(fontFile); - } - } - - // Position of the specified glyph relative to the origin of glyphVector - // advance is handled by the particular font implementation. - newAdvanceX = (float) currentFont.echarAdvance(currentChar).getX(); - - newAdvanceY = newAdvanceX; - if (!isVerticalWriting) { - // add fonts rise to the to glyph position (sup,sub scripts) - currentX = advanceX + lastx; - currentY = lasty - textRise; - lastx += newAdvanceX; - // store the pre Tc and Tw dimension. - textMetrics.setPreviousAdvance(lastx); - lastx += characterSpace; - // lastly add space widths, no funny corner case yet for this one. - if (displayText.charAt(i) == 32) { // currently to unreliable currentFont.getSpaceEchar() - lastx += whiteSpace; - } - } else { - // add fonts rise to the to glyph position (sup,sub scripts) - lasty += (newAdvanceY - textRise); - currentX = advanceX - (newAdvanceX / 2.0f); - currentY = advanceY + lasty; - } - - // get normalized from from text sprite - GlyphText glyphText = textSprites.addText( - String.valueOf(currentChar), // cid - textState.currentfont.toUnicode(currentChar), // unicode value - currentX, currentY, newAdvanceX); - shapes.getPageText().addGlyph(glyphText, oCGs); - - } - // append the finally offset of the with of the character - advanceX += lastx; - advanceY += lasty; - - /** - * The text rendering mode, Tmode, determines whether showing text - * causes glyph outlines to be stroked, filled, used as a clipping - * boundary, or some combination of the three. - * - * No Support for 4, 5, 6 and 7. - * - * 0 - Fill text - * 1 - Stroke text - * 2 - fill, then stroke text - * 3 - Neither fill nor stroke text (invisible) - * 4 - Fill text and add to path for clipping - * 5 - Stroke text and add to path for clipping. - * 6 - Fill, then stroke text and add to path for clipping. - * 7 - Add text to path for clipping. - */ - - int rmode = textState.rmode; - switch (rmode) { - // fill text: 0 - case TextState.MODE_FILL: - drawModeFill(graphicState, textSprites, shapes, rmode); - break; - // Stroke text: 1 - case TextState.MODE_STROKE: - drawModeStroke(graphicState, textSprites, textState, shapes, rmode); - break; - // Fill, then stroke text: 2 - case TextState.MODE_FILL_STROKE: - drawModeFillStroke(graphicState, textSprites, textState, shapes, rmode); - break; - // Neither fill nor stroke text (invisible): 3 - case TextState.MODE_INVISIBLE: - // do nothing - break; - // Fill text and add to path for clipping: 4 - case TextState.MODE_FILL_ADD: - drawModeFill(graphicState, textSprites, shapes, rmode); - glyphOutlineClip.addTextSprite(textSprites); - break; - // Stroke Text and add to path for clipping: 5 - case TextState.MODE_STROKE_ADD: - drawModeStroke(graphicState, textSprites, textState, shapes, rmode); - glyphOutlineClip.addTextSprite(textSprites); - break; - // Fill, then stroke text adn add to path for clipping: 6 - case TextState.MODE_FILL_STROKE_ADD: - drawModeFillStroke(graphicState, textSprites, textState, shapes, rmode); - glyphOutlineClip.addTextSprite(textSprites); - break; - // Add text to path for clipping: 7 - case TextState.MODE_ADD: - glyphOutlineClip.addTextSprite(textSprites); - break; - } - textMetrics.getAdvance().setLocation(advanceX, advanceY); - } - - /** - * Utility Method for adding a text sprites to the Shapes stack, given the - * specified rmode. - * - * @param textSprites text to add to shapes stack - * @param shapes shapes stack - * @param rmode write mode - */ - protected static void drawModeFill(GraphicsState graphicState, - TextSprite textSprites, Shapes shapes, int rmode) { - textSprites.setRMode(rmode); - textSprites.setStrokeColor(graphicState.getFillColor()); - shapes.add(new ColorDrawCmd(graphicState.getFillColor())); - shapes.add(new TextSpriteDrawCmd(textSprites)); - } - - /** - * Utility Method for adding a text sprites to the Shapes stack, given the - * specifed rmode. - * - * @param textSprites text to add to shapes stack - * @param shapes shapes stack - * @param textState text state used to build new stroke - * @param rmode write mode - */ - protected static void drawModeStroke(GraphicsState graphicState, - TextSprite textSprites, TextState textState, - Shapes shapes, int rmode) { - // setup textSprite with a strokeColor and the correct rmode - textSprites.setRMode(rmode); - textSprites.setStrokeColor(graphicState.getStrokeColor()); - // save the old line width - float old = graphicState.getLineWidth(); - - // set the line width for the glyph - float lineWidth = graphicState.getLineWidth(); - double scale = textState.tmatrix.getScaleX(); - // double check for a near zero value as it will really mess up the division result, zero is just fine. - if (scale > 0.001 || scale == 0) { - lineWidth /= scale; - graphicState.setLineWidth(lineWidth); - } else { - // corner case stroke adjustment, still can't find anything in spec about this. - lineWidth *= scale * 100; - graphicState.setLineWidth(lineWidth); - } - // update the stroke and add the text to shapes - setStroke(shapes, graphicState); - shapes.add(new ColorDrawCmd(graphicState.getStrokeColor())); - shapes.add(new TextSpriteDrawCmd(textSprites)); - - // restore graphics state - graphicState.setLineWidth(old); - setStroke(shapes, graphicState); - } - - /** - * Utility Method for adding a text sprites to the Shapes stack, given the - * specifed rmode. - * - * @param textSprites text to add to shapes stack - * @param textState text state used to build new stroke - * @param shapes shapes stack - * @param rmode write mode - */ - protected static void drawModeFillStroke(GraphicsState graphicState, - TextSprite textSprites, TextState textState, - Shapes shapes, int rmode) { - // setup textSprite with a strokeColor and the correct rmode - textSprites.setRMode(rmode); - textSprites.setStrokeColor(graphicState.getStrokeColor()); - // save the old line width - float old = graphicState.getLineWidth(); - - // set the line width for the glyph - float lineWidth = graphicState.getLineWidth(); - double scale = textState.tmatrix.getScaleX(); - // double check for a near zero value as it will really mess up the division result, zero is just fine. - if (scale > 0.0001 || scale == 0) { - lineWidth /= scale; - graphicState.setLineWidth(lineWidth); - } - // update the stroke and add the text to shapes - setStroke(shapes, graphicState); - shapes.add(new ColorDrawCmd(graphicState.getFillColor())); - shapes.add(new TextSpriteDrawCmd(textSprites)); - - // restore graphics state - graphicState.setLineWidth(old); - setStroke(shapes, graphicState); - } - - /** - * Common stroke operations used by S and s. Takes into - * account patternColour and regular old fill colour. - * - * @param shapes current shapes stack - * @param geometricPath current path. - */ - protected static void commonStroke(GraphicsState graphicState, Shapes shapes, GeneralPath geometricPath) - throws InterruptedException { - - // get current fill alpha and concatenate with overprinting if present - if (graphicState.isOverprintStroking()) { - setAlpha(shapes, graphicState, graphicState.getAlphaRule(), - commonOverPrintAlpha(graphicState.getStrokeAlpha(), - graphicState.getStrokeColorSpace())); - } - // The knockout effect can only be achieved by changing the alpha - // composite to source. I don't have a test case for this for stroke - // but what we do for stroke is usually what we do for fill... - else if (graphicState.isKnockOut()) { - setAlpha(shapes, graphicState, AlphaComposite.SRC, graphicState.getStrokeAlpha()); - } - - // found a PatternColor - if (graphicState.getStrokeColorSpace() instanceof PatternColor) { - // Create a pointer to the pattern colour - PatternColor patternColor = (PatternColor) graphicState.getStrokeColorSpace(); - // grab the pattern from the colour - Pattern pattern = patternColor.getPattern(); - // Start processing tiling pattern - if (pattern != null && - pattern.getPatternType() == Pattern.PATTERN_TYPE_TILING) { - // currently not doing any special handling for colour or uncoloured - // paint, as it done when the scn or sc tokens are parsed. - TilingPattern tilingPattern = (TilingPattern) pattern; - // 1.)save the graphics context - graphicState = graphicState.save(); - // 2.) install the graphic state - tilingPattern.setParentGraphicState(graphicState); - tilingPattern.init(graphicState); - // 4.) Restore the saved graphics state - graphicState = graphicState.restore(); - // 1x1 tiles don't seem to paint so we'll resort to using the - // first pattern colour or the uncolour. - if ((tilingPattern.getbBoxMod() != null && - (tilingPattern.getbBoxMod().getWidth() > 1 || - tilingPattern.getbBoxMod().getHeight() > 1))) { - shapes.add(new TilingPatternDrawCmd(tilingPattern)); - } else { - // draw partial fill colour - if (tilingPattern.getPaintType() == - TilingPattern.PAINTING_TYPE_UNCOLORED_TILING_PATTERN) { - shapes.add(new ColorDrawCmd(tilingPattern.getUnColored())); - } else { - shapes.add(new ColorDrawCmd(tilingPattern.getFirstColor())); - } - } - shapes.add(new ShapeDrawCmd(geometricPath)); - shapes.add(new DrawDrawCmd()); - } else if (pattern != null && - pattern.getPatternType() == Pattern.PATTERN_TYPE_SHADING) { - pattern.init(graphicState); - shapes.add(new PaintDrawCmd(pattern.getPaint())); - shapes.add(new ShapeDrawCmd(geometricPath)); - shapes.add(new DrawDrawCmd()); - } - } else { - setAlpha(shapes, graphicState, graphicState.getAlphaRule(), graphicState.getStrokeAlpha()); - shapes.add(new ColorDrawCmd(graphicState.getStrokeColor())); - shapes.add(new ShapeDrawCmd(geometricPath)); - shapes.add(new DrawDrawCmd()); - } - // set alpha back to original value. -// if (graphicState.isOverprintStroking()) { -// setAlpha(shapes, graphicState, AlphaComposite.SRC_OVER, graphicState.getFillAlpha()); -// } - } - - /** - * Utility method for fudging overprinting calculation for screen - * representation. This feature is optional an off by default. - *

      - * Can be enable with -Dorg.icepdf.core.enabledOverPrint=true - * - * @param alpha alph constant - * @return tweaked over printing alpha - */ - protected static float commonOverPrintAlpha(float alpha, PColorSpace colorSpace) { - if (!enabledOverPrint) { - return alpha; - } - if (colorSpace instanceof DeviceN) {// || colorSpace instanceof Separation) { - // if alpha is already present we reduce it and we minimize - // it if it is already lower then our over paint. This an approximation - // only for improved screen representation. - if (alpha != 1.0f && alpha > OVERPAINT_ALPHA) { - alpha -= OVERPAINT_ALPHA; - } else if (alpha < OVERPAINT_ALPHA) { - // alpha = 0.1f; - } else { - alpha = OVERPAINT_ALPHA; - } - return alpha; - } - return alpha; - } - - /** - * Common fill operations used by f, F, F*, b, b*, B, B*. Takes into - * account patternColour and regular old fill colour. - * - * @param shapes current shapes stack - * @param graphicState current graphics state. - * @param geometricPath current path. - */ - protected static void commonFill(Shapes shapes, GraphicsState graphicState, GeneralPath geometricPath) - throws NoninvertibleTransformException, InterruptedException { - - // get current fill alpha and concatenate with overprinting if present - if (graphicState.isOverprintOther()) { - setAlpha(shapes, graphicState, graphicState.getAlphaRule(), - commonOverPrintAlpha(graphicState.getFillAlpha(), - graphicState.getFillColorSpace())); - } - // avoid doing fill, as we likely have blending mode that will obfuscate the underlying - // content. - if (graphicState.getExtGState() != null && - graphicState.getExtGState().getSMask() != null) { - return; - } - // The knockout effect can only be achieved by changing the alpha - // composite to source. - else if (graphicState.isKnockOut()) { - setAlpha(shapes, graphicState, AlphaComposite.SRC, graphicState.getFillAlpha()); - } else if (graphicState.getExtGState() == null || graphicState.getExtGState().getBlendingMode() == null) { - setAlpha(shapes, graphicState, graphicState.getAlphaRule(), graphicState.getFillAlpha()); - } - - // found a PatternColor - if (graphicState.getFillColorSpace() instanceof PatternColor) { - // Create a pointer to the pattern colour - PatternColor patternColor = (PatternColor) graphicState.getFillColorSpace(); - // grab the pattern from the colour - Pattern pattern = patternColor.getPattern(); - // Start processing tiling pattern - if (pattern != null && - pattern.getPatternType() == Pattern.PATTERN_TYPE_TILING) { - // currently not doing any special handling for colour or uncoloured - // paint, as it done when the scn or sc tokens are parsed. - TilingPattern tilingPattern = (TilingPattern) pattern; - // 1.)save the graphics context - graphicState = graphicState.save(); - // 2.) install the graphic state - tilingPattern.setParentGraphicState(graphicState); - tilingPattern.init(graphicState); - // 4.) Restore the saved graphics state - graphicState = graphicState.restore(); - // tiles nee to be 1x1 or larger to paint so we'll resort to using the - // first pattern colour or the uncolour. - if (tilingPattern.getbBoxMod() != null && - (tilingPattern.getbBoxMod().getWidth() >= 0.5 || - tilingPattern.getbBoxMod().getHeight() >= 0.5)) { - shapes.add(new TilingPatternDrawCmd(tilingPattern)); - } else { - // draw partial fill colour - if (tilingPattern.getPaintType() == - TilingPattern.PAINTING_TYPE_UNCOLORED_TILING_PATTERN) { - shapes.add(new ColorDrawCmd(tilingPattern.getUnColored())); - } else { - shapes.add(new ColorDrawCmd(tilingPattern.getFirstColor())); - } - } - shapes.add(new ShapeDrawCmd(geometricPath)); - shapes.add(new FillDrawCmd()); - } else if (pattern != null && - pattern.getPatternType() == Pattern.PATTERN_TYPE_SHADING) { - pattern.init(graphicState); - shapes.add(new PaintDrawCmd(pattern.getPaint())); - shapes.add(new ShapeDrawCmd(geometricPath)); - shapes.add(new FillDrawCmd()); - } - - } else { -// if (graphicState.getExtGState() != null -// && graphicState.getExtGState().getBlendingMode() != null -// && graphicState.getExtGState().getOverprintMode() == 1 ) { -// shapes.add(new BlendCompositeDrawCmd(graphicState.getExtGState().getBlendingMode(), -// graphicState.getFillAlpha())); -// } - shapes.add(new ColorDrawCmd(graphicState.getFillColor())); - shapes.add(new ShapeDrawCmd(geometricPath)); - shapes.add(new FillDrawCmd()); - } - // add old alpha back to stack -// if (graphicState.isOverprintOther()) { -// setAlpha(shapes, graphicState, graphicState.getAlphaRule(), graphicState.getFillAlpha()); -// } - } - - /** - * Sets the state of the BasicStrok with the latest values from the - * graphicSate instance value: - * graphicState.lineWidth - line width - * graphicState.lineCap - line cap type - * graphicState.lineJoin - line join type - * graphicState.miterLimit - miter limit - * - * @param shapes current Shapes object for the page being parsed - * @param graphicState graphic state used to build this stroke instance. - */ - protected static void setStroke(Shapes shapes, GraphicsState graphicState) { - shapes.add(new StrokeDrawCmd(new BasicStroke(graphicState.getLineWidth(), - graphicState.getLineCap(), - graphicState.getLineJoin(), - graphicState.getMiterLimit(), - graphicState.getDashArray(), - graphicState.getDashPhase()))); - } - - /** - * Text scaling must be applied to the main graphic state. It can not - * be applied to the Text Matrix. We only have two test cases for its - * use but it appears that the scaling has to bee applied before a text - * write operand occurs, otherwise a call to Tm seems to break text - * positioning. - *

      - * Scaling is special as it can be negative and thus apply a horizontal - * flip on the graphic state. - * - * @param graphicState current graphics state. - */ - protected static AffineTransform applyTextScaling(GraphicsState graphicState) { - // get the current CTM - AffineTransform af = new AffineTransform(graphicState.getCTM()); - // the mystery continues, it appears that only the negative or positive - // value of tz is actually used. If the original non 1 number is used the - // layout will be messed up. - AffineTransform oldHScaling = new AffineTransform(graphicState.getCTM()); - float hScaling = graphicState.getTextState().hScalling; - AffineTransform horizontalScalingTransform = - new AffineTransform( - af.getScaleX() * hScaling, - af.getShearY(), - af.getShearX(), - af.getScaleY(), - af.getTranslateX(), af.getTranslateY()); - // add the transformation to the graphics state - graphicState.set(horizontalScalingTransform); - - return oldHScaling; - } - - /** - * Adds a new Alpha Composite object ot the shapes stack. - * - * @param shapes - current shapes vector to add Alpha Composite to - * @param rule - rule to apply to the alphaComposite. - * @param alpha - alpha value, opaque = 1.0f. - */ - protected static void setAlpha(Shapes shapes, GraphicsState graphicsState, int rule, float alpha) { - // Build the alpha composite object and add it to the shapes but only - // if it hash changed. - if (shapes != null && (shapes.getAlpha() != alpha || shapes.getRule() != rule)) { - AlphaComposite alphaComposite = - AlphaComposite.getInstance(rule, - alpha); - shapes.add(new AlphaDrawCmd(alphaComposite)); - shapes.setAlpha(alpha); - shapes.setRule(rule); - } - } - - public void setGlyph2UserSpaceScale(float scale) { - glyph2UserSpaceScale = scale; - } - -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/ContentParser.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/ContentParser.java deleted file mode 100644 index 3e543e69e0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/ContentParser.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util.content; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.GraphicsState; -import org.icepdf.core.pobjects.graphics.Shapes; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.Stack; - -/** - * ContentParser interface for content streams. - * - * @since 5.0 - */ -public interface ContentParser { - - /** - * Gets the shapes parsed by the last run of {@see parse}. - * - * @return Shapes associated with the content parser. - */ - Shapes getShapes(); - - /** - * Gets the stack used by the content parser. Under normal execution the - * stack should be empty. If the stack has elements remaining then is - * generally means that a content parsing error has taken place. - * - * @return object stack. - */ - Stack getStack(); - - /** - * Gets the graphic state object associated with the parser. Needed by - * the Type3 font program. - * - * @return graphic state of the parsed content stream. - */ - GraphicsState getGraphicsState(); - - /** - * Sets the external graphics state object associated with Form's and - * Tiling Patterns. - * - * @param graphicState graphic state to pass to parser. - */ - void setGraphicsState(GraphicsState graphicState); - - /** - * Parse the given stream bytes. - * - * @param streamBytes bytes that make of one or more content streams. - * @return an instance of this content parser. - * @throws InterruptedException thread was interrupted. - * @throws IOException io exception during the pars. - */ - ContentParser parse(byte[][] streamBytes, Page page) - throws InterruptedException, IOException; - - /** - * Optimized text parsing call which will ignore any instructions that - * are not related to text extraction. Images and other operands are - * ignored speeding up the extraction process. - * - * @param source byte source to parse. - * @return Shapes object which contains the extract PageText object. - * @throws UnsupportedEncodingException encoding error. - */ - Shapes parseTextBlocks(byte[][] source) throws UnsupportedEncodingException, InterruptedException; - - /** - * Sets the scale factor used by some graphic state parameters so that the - * to users space CTM scale factor can be applied. In particular some - * Type3 glyphs need to take into account this scaling factor. - * - * @param scale scale factor to apply to various graphic state parameters. - */ - void setGlyph2UserSpaceScale(float scale); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/ContentParserFactory.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/ContentParserFactory.java deleted file mode 100644 index 13edd42586..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/ContentParserFactory.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util.content; - -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.util.Library; - -import java.lang.reflect.Constructor; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * ContentParserFactory will reflectively load the PRO parsing engine - * if found on the class path. - * - * @since 5.0 - */ -public class ContentParserFactory { - - private static final Logger logger = - Logger.getLogger(ContentParserFactory.class.toString()); - - private static ContentParserFactory contentParserFactory; - - private static final String N_CONTENT_PARSER = - "org.icepdf.core.util.content.NContentParser"; - - private static boolean foundPro; - - static { - // check class bath for NFont library, and declare results. - try { - Class.forName(N_CONTENT_PARSER); - foundPro = true; - } catch (ClassNotFoundException e) { - logger.log(Level.FINE, "ICEpdf PRO was not found on the class path"); - } - } - - private ContentParserFactory() { - } - - /** - *

      Returns a static instance of the ContentParserclass.

      - * - * @return instance of the ContentParser. - */ - public static ContentParserFactory getInstance() { - // make sure we have initialized the manager - if (contentParserFactory == null) { - contentParserFactory = new ContentParserFactory(); - } - return contentParserFactory; - } - - /** - * Factory call to return the content parser associated with the given - * product version. - * - * @param library document library - * @param resources page's parent resource object. - * @return implementation of the ContentParser interface. - */ - public ContentParser getContentParser(Library library, Resources resources) { - if (foundPro) { - // load each know file type reflectively. - try { - Class contentParserClass = Class.forName(N_CONTENT_PARSER); - Class[] parserArgs = {Library.class, Resources.class}; - Constructor fontClassConstructor = - contentParserClass.getDeclaredConstructor(parserArgs); - Object[] args = {library, resources}; - return (ContentParser) fontClassConstructor.newInstance(args); - } catch (Throwable e) { - logger.log(Level.FINE, "Could not load font dictionary class", e); - } - } - return new OContentParser(library, resources); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/OContentParser.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/OContentParser.java deleted file mode 100644 index d841240f34..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/OContentParser.java +++ /dev/null @@ -1,1133 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util.content; - -import org.icepdf.core.io.ByteDoubleArrayInputStream; -import org.icepdf.core.io.SequenceInputStream; -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.graphics.*; -import org.icepdf.core.pobjects.graphics.commands.GlyphOutlineDrawCmd; -import org.icepdf.core.pobjects.graphics.commands.ImageDrawCmd; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Parser; -import org.icepdf.core.util.PdfOps; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.io.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Stack; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * The ContentParser is responsible for parsing a page's content streams. The - * parsed text, image and other PDF object types are added the pages Shapes - * object for later drawing and display. - */ -public class OContentParser extends AbstractContentParser { - - private static final Logger logger = - Logger.getLogger(OContentParser.class.toString()); - - - /** - * @param l PDF library master object. - * @param r resources - */ - public OContentParser(Library l, Resources r) { - super(l, r); - } - - /** - * Parse a pages content stream. - * - * @param streamBytes byte stream containing page content - * @return a Shapes Object containing all the pages text and images shapes. - * @throws InterruptedException if current parse thread is interrupted. - * @throws IOException unexpected end of content stream. - */ - public ContentParser parse(byte[][] streamBytes, Page page) - throws InterruptedException, IOException { - if (shapes == null) { - shapes = new Shapes(); - // Normal, clean content parse where graphics state is null - if (graphicState == null) { - graphicState = new GraphicsState(shapes); - } - // If not null we have an Form XObject that contains a content stream - // and we must copy the previous graphics states draw settings in order - // preserve colour and fill data for the XOjbects content stream. - else { - // the graphics state gets a new coordinate system. - graphicState.setCTM(new AffineTransform()); - // reset the clipping area. - graphicState.setClip(null); - // copy previous stroke info - setStroke(shapes, graphicState); - // assign new shapes to the new graphics state - graphicState.setShapes(shapes); - } - } - - if (oCGs == null && library.getCatalog().getOptionalContent() != null) { - oCGs = new LinkedList(); - } - - if (logger.isLoggable(Level.FINER)) { - logger.fine("Parsing page content streams: " + streamBytes.length); - // print all the stream byte chunks. - for (byte[] streamByte : streamBytes) { - if (streamByte != null) { - String tmp = new String(streamByte, "ISO-8859-1"); - logger.finer("Content = " + tmp); - } - } - } - - // great a parser to get tokens for stream - Parser parser; - - // test case for progress bar - java.util.List in = new ArrayList(); - for (int i = 0; i < streamBytes.length; i++) { - in.add(new ByteArrayInputStream(streamBytes[i])); - } - parser = new Parser(new SequenceInputStream(in, ' ')); - - // text block y offset. - float yBTstart = 0; - -// long startTime = System.currentTimeMillis(); - try { - - // loop through each token returned form the parser - Object tok; - while (true) { - - if (Thread.currentThread().isInterrupted()) { - throw new InterruptedException("ContentParser thread interrupted"); - } - - tok = parser.getStreamObject(); - - // add any names and numbers and every thing else on the - // stack for future reference - if (!(tok instanceof String)) { - stack.push(tok); - } else { - - // Append a straight line segment from the current point to the - // point (x, y). The new current point is (x, y). - if (tok.equals(PdfOps.l_TOKEN)) { -// collectTokenFrequency(PdfOps.l_TOKEN); - geometricPath = consume_L(stack, geometricPath); - } - - // Begin a new subpath by moving the current point to - // coordinates (x, y), omitting any connecting line segment. If - // the previous path construction operator in the current path - // was also m, the new m overrides it; no vestige of the - // previous m operation remains in the path. - else if (tok.equals(PdfOps.m_TOKEN)) { -// collectTokenFrequency(PdfOps.m_TOKEN); - geometricPath = consume_m(stack, geometricPath); - } - - // Append a cubic Bezier curve to the current path. The curve - // extends from the current point to the point (x3, y3), using - // (x1, y1) and (x2, y2) as the Bezier control points. - // The new current point is (x3, y3). - else if (tok.equals(PdfOps.c_TOKEN)) { -// collectTokenFrequency(PdfOps.c_TOKEN); - geometricPath = consume_c(stack, geometricPath); - } - - // Stroke the path - else if (tok.equals(PdfOps.S_TOKEN)) { -// collectTokenFrequency(PdfOps.S_TOKEN); - geometricPath = consume_S(graphicState, shapes, geometricPath); - } - - // Font selection - else if (tok.equals(PdfOps.Tf_TOKEN)) { - consume_Tf(graphicState, stack, resources); - } - - // Begin a text object, initializing the text matrix, Tm, and - // the text line matrix, Tlm, to the identity matrix. Text - // objects cannot be nested; a second BT cannot appear before - // an ET. - else if (tok.equals(PdfOps.BT_TOKEN)) { -// collectTokenFrequency(PdfOps.BT_TOKEN); - // start parseText, which parses until ET is reached - try { - yBTstart = parseText(parser, shapes, yBTstart); - } catch (Exception e) { - logger.log(Level.FINEST, "Error parsing text block", e); - } - } - - // Fill the path, using the nonzero winding number rule to - // determine the region to fill (see "Nonzero Winding - // Number Rule" ). Any subpaths that are open are implicitly - // closed before being filled. f or F - else if (tok.equals(PdfOps.F_TOKEN) || - tok.equals(PdfOps.f_TOKEN)) { -// collectTokenFrequency(PdfOps.F_TOKEN); -// collectTokenFrequency(PdfOps.f_TOKEN); - geometricPath = consume_F(graphicState, shapes, geometricPath); - } - - // Saves Graphics State, should copy the entire graphics state onto - // the graphicsState object's stack - else if (tok.equals(PdfOps.q_TOKEN)) { - graphicState = consume_q(graphicState); - } - // Restore Graphics State, should restore the entire graphics state - // to its former value by popping it from the stack - else if (tok.equals(PdfOps.Q_TOKEN)) { - graphicState = consume_Q(graphicState, shapes); - } - - // Append a rectangle to the current path as a complete subpath, - // with lower-left corner (x, y) and dimensions width and height - // in user space. The operation x y width height re is equivalent to - // x y m - // (x + width) y l - // (x + width) (y + height) l - // x (y + height) l - // h - else if (tok.equals(PdfOps.re_TOKEN)) { -// collectTokenFrequency(PdfOps.re_TOKEN); - geometricPath = consume_re(stack, geometricPath); - } - - // Modify the current transformation matrix (CTM) by concatenating the - // specified matrix - else if (tok.equals(PdfOps.cm_TOKEN)) { - consume_cm(graphicState, stack, inTextBlock, textBlockBase); - } - - // Close the current sub path by appending a straight line segment - // from the current point to the starting point of the sub path. - // This operator terminates the current sub path; appending - // another segment to the current path will begin a new subpath, - // even if the new segment begins at the endpoint reached by the - // h operation. If the current subpath is already closed, - // h does nothing. - else if (tok.equals(PdfOps.h_TOKEN)) { -// collectTokenFrequency(PdfOps.h_TOKEN); - consume_h(geometricPath); - } - - // Begin a marked-content sequence with an associated property - // list, terminated by a balancing EMC operator. tag is a name - // object indicating the role or significance of the sequence; - // properties is either an inline dictionary containing the - // property list or a name object associated with it in the - // Properties sub dictionary of the current resource dictionary - else if (tok.equals(PdfOps.BDC_TOKEN)) { -// collectTokenFrequency(PdfOps.BDC_TOKEN); - consume_BDC(stack, shapes, - oCGs, resources); - } - - // End a marked-content sequence begun by a BMC or BDC operator. - else if (tok.equals(PdfOps.EMC_TOKEN)) { - consume_EMC(shapes, oCGs); - } - - /** - * External Object (XObject) a graphics object whose contents - * are defined by a self-contained content stream, separate - * from the content stream in which it is used. There are three - * types of external object: - * - * - An image XObject (Section 4.8.4, "Image Dictionaries") - * represents a sampled visual image such as a photograph. - * - A form XObject (Section 4.9, "Form XObjects") is a - * self-contained description of an arbitrary sequence of - * graphics objects. - * - A PostScript XObject (Section 4.7.1, "PostScript XObjects") - * contains a fragment of code expressed in the PostScript - * page description language. PostScript XObjects are no - * longer recommended to be used. (NOT SUPPORTED) - */ - // Paint the specified XObject. The operand name must appear as - // a key in the XObject subdictionary of the current resource - // dictionary (see Section 3.7.2, "Resource Dictionaries"); the - // associated value must be a stream whose Type entry, if - // present, is XObject. The effect of Do depends on the value of - // the XObject's Subtype entry, which may be Image , Form, or PS - else if (tok.equals(PdfOps.Do_TOKEN)) { -// collectTokenFrequency(PdfOps.Do_TOKEN); - graphicState = consume_Do(graphicState, stack, shapes, - resources, true, imageIndex, page); - } - - // Fill the path, using the even-odd rule to determine the - // region to fill - else if (tok.equals(PdfOps.f_STAR_TOKEN)) { -// collectTokenFrequency(PdfOps.f_STAR_TOKEN); - geometricPath = consume_f_star(graphicState, shapes, geometricPath); - } - - // Sets the specified parameters in the graphics state. The gs operand - // points to a name resource which should be a an ExtGState object. - // The graphics state parameters in the ExtGState must be concatenated - // with the the current graphics state. - else if (tok.equals(PdfOps.gs_TOKEN)) { - consume_gs(graphicState, stack, resources, shapes); - } - - // End the path object without filling or stroking it. This - // operator is a "path-painting no-op," used primarily for the - // side effect of changing the current clipping path - else if (tok.equals(PdfOps.n_TOKEN)) { -// collectTokenFrequency(PdfOps.n_TOKEN); - geometricPath = consume_n(geometricPath); - } - - // Set the line width in the graphics state - else if (tok.equals(PdfOps.w_TOKEN) || - tok.equals(PdfOps.LW_TOKEN)) { - consume_w(graphicState, stack, shapes, glyph2UserSpaceScale); - } - - // Modify the current clipping path by intersecting it with the - // current path, using the nonzero winding number rule to - // determine which regions lie inside the clipping path. - else if (tok.equals(PdfOps.W_TOKEN)) { -// collectTokenFrequency(PdfOps.W_TOKEN); - consume_W(graphicState, geometricPath); - } - - // Fill Color with ColorSpace - else if (tok.equals(PdfOps.sc_TOKEN)) { - consume_sc(graphicState, stack, library, resources, false); - } else if (tok.equals(PdfOps.scn_TOKEN)) { - consume_sc(graphicState, stack, library, resources, true); - } - - // Close, fill, and then stroke the path, using the nonzero - // winding number rule to determine the region to fill. This - // operator has the same effect as the sequence h B. See also - // "Special Path-Painting Considerations" - else if (tok.equals(PdfOps.b_TOKEN)) { -// collectTokenFrequency(PdfOps.b_TOKEN); - geometricPath = consume_b(graphicState, shapes, geometricPath); - } - - // Same as K, but for non-stroking operations. - else if (tok.equals(PdfOps.k_TOKEN)) { // Fill Color CMYK - consume_k(graphicState, stack, library); - } - - // Same as g but for none stroking operations - else if (tok.equals(PdfOps.g_TOKEN)) { - consume_g(graphicState, stack, library); - } - - // Sets the flatness tolerance in the graphics state, NOT SUPPORTED - // flatness is a number in the range 0 to 100, a value of 0 specifies - // the default tolerance - else if (tok.equals(PdfOps.i_TOKEN)) { - consume_i(stack); - } - - // Miter Limit - else if (tok.equals(PdfOps.M_TOKEN)) { - consume_M(graphicState, stack, shapes); - } - - // Set the line cap style of the graphic state, related to Line Join - // style - else if (tok.equals(PdfOps.J_TOKEN)) { - consume_J(graphicState, stack, shapes); - } - - // Same as RG, but for non-stroking operations. - else if (tok.equals(PdfOps.rg_TOKEN)) { // Fill Color RGB - consume_rg(graphicState, stack, library); - } - - // Sets the line dash pattern in the graphics state. A normal line - // is [] 0. See Graphics State -> Line dash patter for more information - // in the PDF Reference. Java 2d uses the same notation so there - // is not much work to be done other then parsing the data. - else if (tok.equals(PdfOps.d_TOKEN)) { - consume_d(graphicState, stack, shapes); - } - - // Append a cubic Bezier curve to the current path. The curve - // extends from the current point to the point (x3, y3), using - // the current point and (x2, y2) as the Bezier control points. - // The new current point is (x3, y3). - else if (tok.equals(PdfOps.v_TOKEN)) { -// collectTokenFrequency(PdfOps.v_TOKEN); - consume_v(stack, geometricPath); - } - - // Set the line join style in the graphics state - else if (tok.equals(PdfOps.j_TOKEN)) { - consume_j(graphicState, stack, shapes); - } - - // Append a cubic Bezier curve to the current path. The curve - // extends from the current point to the point (x3, y3), using - // (x1, y1) and (x3, y3) as the Bezier control points. - // The new current point is (x3, y3). - else if (tok.equals(PdfOps.y_TOKEN)) { -// collectTokenFrequency(PdfOps.y_TOKEN); - consume_y(stack, geometricPath); - } - - // Same as CS, but for nonstroking operations. - else if (tok.equals(PdfOps.cs_TOKEN)) { - consume_cs(graphicState, stack, resources); - } - - // Color rendering intent in the graphics state - else if (tok.equals(PdfOps.ri_TOKEN)) { -// collectTokenFrequency(PdfOps.ri_TOKEN); - stack.pop(); - } - - // Set the color to use for stroking operations in a device, CIE-based - // (other than ICCBased), or Indexed color space. The number of operands - // required and their interpretation depends on the current stroking color space: - // - For DeviceGray, CalGray, and Indexed color spaces, one operand - // is required (n = 1). - // - For DeviceRGB, CalRGB, and Lab color spaces, three operands are - // required (n = 3). - // - For DeviceCMYK, four operands are required (n = 4). - else if (tok.equals(PdfOps.SC_TOKEN)) { // Stroke Color with ColorSpace - consume_SC(graphicState, stack, library, resources, false); - } else if (tok.equals(PdfOps.SCN_TOKEN)) { // Stroke Color with ColorSpace - consume_SC(graphicState, stack, library, resources, true); - } - - // Fill and then stroke the path, using the nonzero winding - // number rule to determine the region to fill. This produces - // the same result as constructing two identical path objects, - // painting the first with f and the second with S. Note, - // however, that the filling and stroking portions of the - // operation consult different values of several graphics state - // parameters, such as the current color. - else if (tok.equals(PdfOps.B_TOKEN)) { -// collectTokenFrequency(PdfOps.B_TOKEN); - geometricPath = consume_B(graphicState, shapes, - geometricPath); - } - - // Set the stroking color space to DeviceCMYK (or the DefaultCMYK color - // space; see "Default Color Spaces" on page 227) and set the color to - // use for stroking operations. Each operand must be a number between - // 0.0 (zero concentration) and 1.0 (maximum concentration). The - // behavior of this operator is affected by the overprint mode - // (see Section 4.5.6, "Overprint Control"). - else if (tok.equals(PdfOps.K_TOKEN)) { // Stroke Color CMYK - consume_K(graphicState, stack, library); - } - - /** - * Type3 operators, update the text state with data from these operands - */ - else if (tok.equals(PdfOps.d0_TOKEN)) { -// collectTokenFrequency(PdfOps.d0_TOKEN); - graphicState = consume_d0(graphicState, stack); - } - - // Close and stroke the path. This operator has the same effect - // as the sequence h S. - else if (tok.equals(PdfOps.s_TOKEN)) { -// collectTokenFrequency(PdfOps.s_TOKEN); - geometricPath = consume_s(graphicState, shapes, geometricPath); - } - - // Set the stroking color space to DeviceGray (or the DefaultGray color - // space; see "Default Color Spaces" ) and set the gray level to use for - // stroking operations. gray is a number between 0.0 (black) - // and 1.0 (white). - else if (tok.equals(PdfOps.G_TOKEN)) { - consume_G(graphicState, stack, library); - } - - // Close, fill, and then stroke the path, using the even-odd - // rule to determine the region to fill. This operator has the - // same effect as the sequence h B*. See also "Special - // Path-Painting Considerations" - else if (tok.equals(PdfOps.b_STAR_TOKEN)) { -// collectTokenFrequency(PdfOps.b_STAR_TOKEN); - geometricPath = consume_b_star(graphicState, - shapes, geometricPath); - } - - // Set the stroking color space to DeviceRGB (or the DefaultRGB color - // space; see "Default Color Spaces" on page 227) and set the color to - // use for stroking operations. Each operand must be a number between - // 0.0 (minimum intensity) and 1.0 (maximum intensity). - else if (tok.equals(PdfOps.RG_TOKEN)) { // Stroke Color RGB - consume_RG(graphicState, stack, library); - } - - // Set the current color space to use for stroking operations. The - // operand name must be a name object. If the color space is one that - // can be specified by a name and no additional parameters (DeviceGray, - // DeviceRGB, DeviceCMYK, and certain cases of Pattern), the name may be - // specified directly. Otherwise, it must be a name defined in the - // ColorSpace sub dictionary of the current resource dictionary; the - // associated value is an array describing the color space. - // Note: - // The names DeviceGray, DeviceRGB, DeviceCMYK, and Pattern always - // identify the corresponding color spaces directly; they never refer to - // resources in the ColorSpace sub dictionary. The CS operator also sets - // the current stroking color to its initial value, which depends on the - // color space: - //
    • In a DeviceGray, DeviceRGB, CalGray, or CalRGB color space, the - // initial color has all components equal to 0.0.
    • - //
    • In a DeviceCMYK color space, the initial color is - // [0.0 0.0 0.0 1.0].
    • - //
    • In a Lab or ICCBased color space, the initial color has all - // components equal to 0.0 unless that falls outside the intervals - // specified by the space's Range entry, in which case the nearest - // valid value is substituted.
    • - //
    • In an Indexed color space, the initial color value is 0.
    • - //
    • In a Separation or DeviceN color space, the initial tint value is - // 1.0 for all colorants.
    • - //
    • In a Pattern color space, the initial color is a pattern object - // that causes nothing to be painted.
    • - else if (tok.equals(PdfOps.CS_TOKEN)) { - consume_CS(graphicState, stack, resources); - } else if (tok.equals(PdfOps.d1_TOKEN)) { -// collectTokenFrequency(PdfOps.d1_TOKEN); - graphicState = consume_d1(graphicState, stack - ); - } - - // Fill and then stroke the path, using the even-odd rule to - // determine the region to fill. This operator produces the same - // result as B, except that the path is filled as if with f* - // instead of f. See also "Special Path-Painting Considerations" - else if (tok.equals(PdfOps.B_STAR_TOKEN)) { -// collectTokenFrequency(PdfOps.B_STAR_TOKEN); - geometricPath = consume_B_star(graphicState, shapes, geometricPath); - } - - // Begin a marked-content sequence terminated by a balancing EMC - // operator.tag is a name object indicating the role or - // significance of the sequence. - else if (tok.equals(PdfOps.BMC_TOKEN)) { - consume_BMC(stack, shapes, oCGs, resources); - } - - // Begin an inline image object - else if (tok.equals(PdfOps.BI_TOKEN)) { -// collectTokenFrequency(PdfOps.BI_TOKEN); - // start parsing image object, which leads to ID and EI - // tokends. - // ID - Begin in the image data for an inline image object - // EI - End an inline image object - parseInlineImage(parser, shapes); - } - - // Begin a compatibility section. Unrecognized operators - // (along with their operands) will be ignored without error - // until the balancing EX operator is encountered. - else if (tok.equals(PdfOps.BX_TOKEN)) { -// collectTokenFrequency(PdfOps.BX_TOKEN); - } - // End a compatibility section begun by a balancing BX operator. - else if (tok.equals(PdfOps.EX_TOKEN)) { -// collectTokenFrequency(PdfOps.EX_TOKEN); - } - - // Modify the current clipping path by intersecting it with the - // current path, using the even-odd rule to determine which - // regions lie inside the clipping path. - else if (tok.equals(PdfOps.W_STAR_TOKEN)) { - consume_W_star(graphicState, geometricPath); - } - - /** - * Single marked-content point - */ - // Designate a marked-content point with an associated property - // list. tag is a name object indicating the role or significance - // of the point; properties is either an in line dictionary - // containing the property list or a name object associated with - // it in the Properties sub dictionary of the current resource - // dictionary. - else if (tok.equals(PdfOps.DP_TOKEN)) { -// collectTokenFrequency(PdfOps.DP_TOKEN); - consume_DP(stack); - } - // Designate a marked-content point. tag is a name object - // indicating the role or significance of the point. - else if (tok.equals(PdfOps.MP_TOKEN)) { -// collectTokenFrequency(PdfOps.MP_TOKEN); - consume_MP(stack); - } - - // shading operator. - else if (tok.equals(PdfOps.sh_TOKEN)) { -// collectTokenFrequency(PdfOps.sh_TOKEN); - consume_sh(graphicState, stack, shapes, - resources); - } - - /** - * We've seen a couple cases when the text state parameters are written - * outside of text blocks, this should cover these cases. - */ - // Character Spacing - else if (tok.equals(PdfOps.Tc_TOKEN)) { - consume_Tc(graphicState, stack); - } - // Word spacing - else if (tok.equals(PdfOps.Tw_TOKEN)) { - consume_Tw(graphicState, stack); - } - // Text leading - else if (tok.equals(PdfOps.TL_TOKEN)) { - consume_TL(graphicState, stack); - } - // Rendering mode - else if (tok.equals(PdfOps.Tr_TOKEN)) { - consume_Tr(graphicState, stack); - } - // Horizontal scaling - else if (tok.equals(PdfOps.Tz_TOKEN)) { - consume_Tz(graphicState, stack); - } - // Text rise - else if (tok.equals(PdfOps.Ts_TOKEN)) { - consume_Ts(graphicState, stack); - } - } - } - } catch (IOException e) { - // eat the result as it a normal occurrence - logger.finer("End of Content Stream"); - } catch (NoninvertibleTransformException e) { - logger.log(Level.WARNING, "Error creating inverse transform:", e); - } catch (InterruptedException e){ - throw new InterruptedException(e.getMessage()); - } finally { - // End of stream set alpha state back to 1.0f, so that other - // streams aren't applied an incorrect alpha value. - setAlpha(shapes, graphicState, AlphaComposite.SRC_OVER, 1.0f); - } -// long endTime = System.currentTimeMillis(); -// System.out.println("Paring Duration " + (endTime - startTime)); -// printTokenFrequency(); - - // Print off anything left on the stack, any "Stack" traces should - // indicate a parsing problem or a not supported operand - while (!stack.isEmpty()) { - String tmp = stack.pop().toString(); - if (logger.isLoggable(Level.FINE)) { - logger.fine("STACK=" + tmp); - } - } - -// shapes.contract(); - return this; - } - - - /** - * Specialized method for extracting text from documents. - * - * @param source content stream source. - * @return vector where each entry is the text extracted from a text block. - */ - public Shapes parseTextBlocks(byte[][] source) throws UnsupportedEncodingException, InterruptedException { - - // great a parser to get tokens for stream - Parser parser = new Parser(new ByteDoubleArrayInputStream(source)); - Shapes shapes = new Shapes(); - - if (graphicState == null) { - graphicState = new GraphicsState(shapes); - } - -// long startTime = System.currentTimeMillis(); - try { - - // loop through each token returned form the parser - Object tok = parser.getStreamObject(); - Stack stack = new Stack(); - double yBTstart = 0; - while (tok != null) { - - // add any names and numbers and every thing else on the - // stack for future reference - if (tok instanceof String) { - - if (tok.equals(PdfOps.BT_TOKEN)) { - // start parseText, which parses until ET is reached - yBTstart = parseText(parser, shapes, yBTstart); - // free up some memory along the way. we don't need - // a full stack consume Tf tokens. - stack.clear(); - } - // for malformed core docs we need to consume any font - // to ensure we can result toUnicode values. - else if (tok.equals(PdfOps.Tf_TOKEN)) { - consume_Tf(graphicState, stack, resources); - stack.clear(); - } - // pick up on xObject content streams. - else if (tok.equals(PdfOps.Do_TOKEN)) { - consume_Do(graphicState, stack, shapes, resources, false, new AtomicInteger(0), null); - stack.clear(); - } - } else { - stack.push(tok); - } - tok = parser.getStreamObject(); - } - // clear our temporary stack. - stack.clear(); - } catch (IOException e) { - // eat the result as it a normal occurrence - logger.finer("End of Content Stream"); - } -// long endTime = System.currentTimeMillis(); -// System.out.println("Extraction Duration " + (endTime - startTime)); - shapes.contract(); - return shapes; - } - - /** - * Parses Text found with in a BT block. - * - * @param parser parser containging BT tokens - * @param shapes container of all shapes for the page content being parsed - * @param previousBTStart y offset of previous BT definition. - * @return y offset of the this BT definition. - * @throws java.io.IOException end of content stream is found - */ - float parseText(Parser parser, Shapes shapes, double previousBTStart) - throws IOException, InterruptedException { - Object nextToken; - inTextBlock = true; - // keeps track of previous text placement so that Compatibility and - // implementation note 57 is respected. That is text drawn after a TJ - // must not be less then the previous glyphs coords. - TextMetrics textMetrics = new TextMetrics(); - textBlockBase = new AffineTransform(graphicState.getCTM()); - - // transformation matrix used to cMap core space to drawing space - graphicState.getTextState().tmatrix = new AffineTransform(); - graphicState.getTextState().tlmatrix = new AffineTransform(); - graphicState.scale(1, -1); - - // get reference to PageText. - PageText pageText = shapes.getPageText(); - - // glyphOutline to support text clipping modes, life span is BT->ET. - GlyphOutlineClip glyphOutlineClip = new GlyphOutlineClip(); - - // start parsing of the BT block - nextToken = parser.getStreamObject(); - while (!nextToken.equals(PdfOps.ET_TOKEN)) { // ET - end text object - // add names to the stack, save for later parsing, colour state - // and graphics state (includes font). - - if (nextToken instanceof String) { - - // Normal text token, string, hex - if (nextToken.equals(PdfOps.Tj_TOKEN)) { -// collectTokenFrequency(PdfOps.Tj_TOKEN); - consume_Tj(graphicState, stack, shapes, - textMetrics, glyphOutlineClip, oCGs); - } - - // Character Spacing - else if (nextToken.equals(PdfOps.Tc_TOKEN)) { -// collectTokenFrequency(PdfOps.Tc_TOKEN); - consume_Tc(graphicState, stack); - } - - // Word spacing - else if (nextToken.equals(PdfOps.Tw_TOKEN)) { -// collectTokenFrequency(PdfOps.Tw_TOKEN); - consume_Tw(graphicState, stack); - } - - // move to the start of he next line, offset from the start of the - // current line by (tx,ty)*tx - else if (nextToken.equals(PdfOps.Td_TOKEN)) { -// collectTokenFrequency(PdfOps.Td_TOKEN); - consume_Td(graphicState, stack, textMetrics, pageText, - previousBTStart, oCGs); - } - - /** - * Tranformation matrix - * tm = |f1 f2 0| - * |f3 f4 0| - * |f5 f6 0| - */ - else if (nextToken.equals(PdfOps.Tm_TOKEN)) { -// collectTokenFrequency(PdfOps.Tm_TOKEN); - consume_tm(graphicState, stack, textMetrics, pageText, - previousBTStart, textBlockBase, oCGs); - } - - // Font selection - else if (nextToken.equals(PdfOps.Tf_TOKEN)) { - consume_Tf(graphicState, stack, resources); - } - - // TJ marks a vector, where....... - else if (nextToken.equals(PdfOps.TJ_TOKEN)) { -// collectTokenFrequency(PdfOps.TJ_TOKEN); - consume_TJ(graphicState, stack, shapes, - textMetrics, glyphOutlineClip, oCGs); - } - - // Move to the start of the next line, offset from the start of the - // current line by (tx,ty) - else if (nextToken.equals(PdfOps.TD_TOKEN)) { -// collectTokenFrequency(PdfOps.TD_TOKEN); - consume_TD(graphicState, stack, textMetrics, pageText, oCGs); - } - - // Text leading - else if (nextToken.equals(PdfOps.TL_TOKEN)) { -// collectTokenFrequency(PdfOps.TL_TOKEN); - consume_TL(graphicState, stack); - } - - // Saves Graphics State, should copy the entire graphics state onto - // the graphicsState object's stack - else if (nextToken.equals(PdfOps.q_TOKEN)) { - graphicState = consume_q(graphicState); - } - // Restore Graphics State, should restore the entire graphics state - // to its former value by popping it from the stack - else if (nextToken.equals(PdfOps.Q_TOKEN)) { - graphicState = consume_Q(graphicState, shapes); - } - - // Modify the current transformation matrix (CTM) by concatenating the - // specified matrix - else if (nextToken.equals(PdfOps.cm_TOKEN)) { - consume_cm(graphicState, stack, inTextBlock, textBlockBase); - } - - // Move to the start of the next line - else if (nextToken.equals(PdfOps.T_STAR_TOKEN)) { -// collectTokenFrequency(PdfOps.T_STAR_TOKEN); - consume_T_star(graphicState, textMetrics, pageText, oCGs); - } else if (nextToken.equals(PdfOps.BDC_TOKEN)) { -// collectTokenFrequency(PdfOps.BDC_TOKEN); - consume_BDC(stack, shapes, - oCGs, resources); - } else if (nextToken.equals(PdfOps.EMC_TOKEN)) { -// collectTokenFrequency(PdfOps.EMC_TOKEN); - consume_EMC(shapes, oCGs); - } - - // Sets the specified parameters in the graphics state. The gs operand - // points to a name resource which should be a an ExtGState object. - // The graphics state parameters in the ExtGState must be concatenated - // with the the current graphics state. - else if (nextToken.equals(PdfOps.gs_TOKEN)) { - consume_gs(graphicState, stack, resources, shapes); - } - - // Set the line width in the graphics state - else if (nextToken.equals(PdfOps.w_TOKEN) || - nextToken.equals(PdfOps.LW_TOKEN)) { - consume_w(graphicState, stack, shapes, glyph2UserSpaceScale); - } - - // Fill Color with ColorSpace - else if (nextToken.equals(PdfOps.sc_TOKEN)) { - consume_sc(graphicState, stack, library, resources, false); - } else if (nextToken.equals(PdfOps.scn_TOKEN)) { - consume_sc(graphicState, stack, library, resources, true); - } - - // Same as K, but for nonstroking operations. - else if (nextToken.equals(PdfOps.k_TOKEN)) { // Fill Color CMYK - consume_k(graphicState, stack, library); - } - - // Same as g but for none stroking operations - else if (nextToken.equals(PdfOps.g_TOKEN)) { - consume_g(graphicState, stack, library); - } - - // Sets the flatness tolerance in the graphics state, NOT SUPPORTED - // flatness is a number in the range 0 to 100, a value of 0 specifies - // the default tolerance - else if (nextToken.equals(PdfOps.i_TOKEN)) { - consume_i(stack); - } - - // Miter Limit - else if (nextToken.equals(PdfOps.M_TOKEN)) { - consume_M(graphicState, stack, shapes); - } - - // Set the line cap style of the graphic state, related to Line Join - // style - else if (nextToken.equals(PdfOps.J_TOKEN)) { - consume_J(graphicState, stack, shapes); - } - - // Same as RG, but for nonstroking operations. - else if (nextToken.equals(PdfOps.rg_TOKEN)) { // Fill Color RGB - consume_rg(graphicState, stack, library); - } - - // Sets the line dash pattern in the graphics state. A normal line - // is [] 0. See Graphics State -> Line dash patter for more information - // in the PDF Reference. Java 2d uses the same notation so there - // is not much work to be done other then parsing the data. - else if (nextToken.equals(PdfOps.d_TOKEN)) { - consume_d(graphicState, stack, shapes); - } - - // Set the line join style in the graphics state - else if (nextToken.equals(PdfOps.j_TOKEN)) { - consume_j(graphicState, stack, shapes); - } - - // Same as CS, but for non-stroking operations. - else if (nextToken.equals(PdfOps.cs_TOKEN)) { - consume_cs(graphicState, stack, resources); - } - - // Set the color rendering intent in the graphics state - else if (nextToken.equals("ri")) { -// collectTokenFrequency(PdfOps.ri_TOKEN); - consume_ri(stack); - } - - // Set the color to use for stroking operations in a device, CIE-based - // (other than ICCBased), or Indexed color space. The number of operands - // required and their interpretation depends on the current stroking color space: - // - For DeviceGray, CalGray, and Indexed color spaces, one operand - // is required (n = 1). - // - For DeviceRGB, CalRGB, and Lab color spaces, three operands are - // required (n = 3). - // - For DeviceCMYK, four operands are required (n = 4). - else if (nextToken.equals(PdfOps.SC_TOKEN)) { // Stroke Color with ColorSpace - consume_SC(graphicState, stack, library, resources, false); - } else if (nextToken.equals(PdfOps.SCN_TOKEN)) { // Stroke Color with ColorSpace - consume_SC(graphicState, stack, library, resources, true); - } - - // Set the stroking color space to DeviceCMYK (or the DefaultCMYK color - // space; see "Default Color Spaces" on page 227) and set the color to - // use for stroking operations. Each operand must be a number between - // 0.0 (zero concentration) and 1.0 (maximum concentration). The - // behavior of this operator is affected by the overprint mode - // (see Section 4.5.6, "Overprint Control"). - else if (nextToken.equals(PdfOps.K_TOKEN)) { // Stroke Color CMYK - consume_K(graphicState, stack, library); - } - - // Set the stroking color space to DeviceGray (or the DefaultGray color - // space; see "Default Color Spaces" ) and set the gray level to use for - // stroking operations. gray is a number between 0.0 (black) - // and 1.0 (white). - else if (nextToken.equals(PdfOps.G_TOKEN)) { - consume_G(graphicState, stack, library); - } - - // Set the stroking color space to DeviceRGB (or the DefaultRGB color - // space; see "Default Color Spaces" on page 227) and set the color to - // use for stroking operations. Each operand must be a number between - // 0.0 (minimum intensity) and 1.0 (maximum intensity). - else if (nextToken.equals(PdfOps.RG_TOKEN)) { // Stroke Color RGB - consume_RG(graphicState, stack, library); - } else if (nextToken.equals(PdfOps.CS_TOKEN)) { - consume_CS(graphicState, stack, resources); - } - - // Rendering mode - else if (nextToken.equals(PdfOps.Tr_TOKEN)) { -// collectTokenFrequency(PdfOps.Tr_TOKEN); - consume_Tr(graphicState, stack); - } - - // Horizontal scaling - else if (nextToken.equals(PdfOps.Tz_TOKEN)) { -// collectTokenFrequency(PdfOps.Tz_TOKEN); - consume_Tz(graphicState, stack); - } - - // Text rise - else if (nextToken.equals(PdfOps.Ts_TOKEN)) { -// collectTokenFrequency(PdfOps.Ts_TOKEN); - consume_Ts(graphicState, stack); - } - - /** - * Begin a compatibility section. Unrecognized operators (along with - * their operands) will be ignored without error until the balancing - * EX operator is encountered. - */ - else if (nextToken.equals(PdfOps.BX_TOKEN)) { -// collectTokenFrequency(PdfOps.BX_TOKEN); - } -// End a compatibility section begun by a balancing BX operator. - else if (nextToken.equals(PdfOps.EX_TOKEN)) { -// collectTokenFrequency(PdfOps.EX_TOKEN); - } - // Move to the next line and show a text string. - else if (nextToken.equals(PdfOps.SINGLE_QUOTE_TOKEN)) { -// collectTokenFrequency(PdfOps.SINGLE_QUOTE_TOKEN); - consume_single_quote(graphicState, stack, shapes, textMetrics, - glyphOutlineClip, oCGs); - } - /** - * Move to the next line and show a text string, using aw as the - * word spacing and ac as the character spacing (setting the - * corresponding parameters in the text state). aw and ac are - * numbers expressed in unscaled text space units. - */ - else if (nextToken.equals(PdfOps.DOUBLE_QUOTE__TOKEN)) { -// collectTokenFrequency(PdfOps.DOUBLE_QUOTE__TOKEN); - consume_double_quote(graphicState, stack, shapes, textMetrics, - glyphOutlineClip, oCGs); - } - } - // push everything else on the stack for consumptions - else { - stack.push(nextToken); - } - - nextToken = parser.getStreamObject(); - } - // during a BT -> ET text parse there is a change that we might be - // in MODE_ADD or MODE_Fill_Add which require that the we push the - // shapes that make up the clipping path to the shapes stack. When - // encountered the path will be used as the current clip. - if (!glyphOutlineClip.isEmpty()) { - // set the clips so further clips can use the clip outline - graphicState.setClip(glyphOutlineClip.getGlyphOutlineClip()); - // add the glyphOutline so the clip can be calculated. - shapes.add(new GlyphOutlineDrawCmd(glyphOutlineClip)); - } - - // get rid of the rest - while (!stack.isEmpty()) { - String tmp = stack.pop().toString(); - if (logger.isLoggable(Level.FINE)) { - logger.warning("Text=" + tmp); - } - } - graphicState.set(textBlockBase); - inTextBlock = false; - - return textMetrics.getyBTStart(); - } - - - private void parseInlineImage(Parser p, Shapes shapes) throws IOException { - try { - //int width = 0, height = 0, bitspercomponent = 0; - // boolean imageMask = false; // from old pdfgo never used - // PColorSpace cs = null; // from old pdfgo never used - - Object tok; - HashMap iih = new HashMap(); - tok = p.getStreamObject(); - while (!tok.equals("ID")) { - if (tok.equals("BPC")) { - tok = new Name("BitsPerComponent"); - } else if (tok.equals("CS")) { - tok = new Name("ColorSpace"); - } else if (tok.equals("D")) { - tok = new Name("Decode"); - } else if (tok.equals("DP")) { - tok = new Name("DecodeParms"); - } else if (tok.equals("F")) { - tok = new Name("Filter"); - } else if (tok.equals("H")) { - tok = new Name("Height"); - } else if (tok.equals("IM")) { - tok = new Name("ImageMask"); - } else if (tok.equals("I")) { - tok = new Name("Indexed"); - } else if (tok.equals("W")) { - tok = new Name("Width"); - } - Object tok1 = p.getStreamObject(); - //System.err.println(tok+" - "+tok1); - iih.put(tok, tok1); - tok = p.getStreamObject(); - } - // For inline images in content streams, we have to use - // a byte[], instead of going back to the original file, - // to reget the image data, because the inline image is - // only a small part of a content stream, which is also - // filtered, and potentially concatenated with other - // content streams. - // Long story short: it's too hard to re-get from PDF file - // Now, since non-inline-image streams can go back to the - // file, we have to fake it as coming from the file ... - ByteArrayOutputStream buf = new ByteArrayOutputStream(4096); - tok = p.peek2(); - boolean ateEI = false; - while (tok != null && !tok.equals(" EI")) { - ateEI = p.readLineForInlineImage(buf); - if (ateEI) - break; - tok = p.peek2(); - } - if (!ateEI) { - // get rid of trash... - p.getToken(); - } - buf.flush(); - buf.close(); - - byte[] data = buf.toByteArray(); - // create the image stream - ImageStream st = new ImageStream(library, iih, data); - ImageReference imageStreamReference = - new InlineImageStreamReference(st, graphicState, resources, 0, null); -// ImageUtility.displayImage(imageStreamReference.getImage(), "BI"); - AffineTransform af = new AffineTransform(graphicState.getCTM()); - graphicState.scale(1, -1); - graphicState.translate(0, -1); - shapes.add(new ImageDrawCmd(imageStreamReference)); - graphicState.set(af); - - } catch (IOException e) { - throw e; - } catch (Exception e) { - logger.log(Level.FINE, "Error parsing inline image.", e); - } - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/TextMetrics.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/TextMetrics.java deleted file mode 100644 index 99181a2def..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/content/TextMetrics.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util.content; - -import java.awt.geom.Point2D; - -/** - * The TextMetrics class purpose is to help sort out the difference between - * how text is drawn vs. how it can be retrieved for text extraction such as - * mouse selection/clip board and output to file. - */ -public class TextMetrics { - - private float shift = 0; - // keeps track of previous text placement so that Compatibility and - // implementation note 57 is respected. That is text drawn after a TJ - // must not be less then the previous glyphs coords. - private float previousAdvance = 0; - private Point2D.Float advance = new Point2D.Float(0, 0); - - // previous Td, TD or Tm y coordinate value for text extraction - private boolean isYstart = true; - private float yBTStart = 0; - - - public float getShift() { - return shift; - } - - public void setShift(float shift) { - this.shift = shift; - } - - public float getPreviousAdvance() { - return previousAdvance; - } - - public void setPreviousAdvance(float previousAdvance) { - this.previousAdvance = previousAdvance; - } - - public Point2D.Float getAdvance() { - return advance; - } - - public void setAdvance(Point2D.Float advance) { - this.advance = advance; - } - - public boolean isYstart() { - return isYstart; - } - - public void setYstart(boolean ystart) { - isYstart = ystart; - } - - public float getyBTStart() { - return yBTStart; - } - - public void setyBTStart(float yBTStart) { - this.yBTStart = yBTStart; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/loggers/BriefLogFormatter.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/loggers/BriefLogFormatter.java deleted file mode 100644 index 2966aac13d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/loggers/BriefLogFormatter.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util.loggers; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.logging.Formatter; -import java.util.logging.LogRecord; - -public class BriefLogFormatter extends Formatter { - - private static final DateFormat format = new SimpleDateFormat("h:mm:ss"); - private static final String lineSep = System.getProperty("line.separator"); - - /** - * A Custom format implementation that is designed for brevity. - */ - public String format(LogRecord record) { - String loggerName = record.getLoggerName(); - if (loggerName == null) { - loggerName = "root"; - } - StringBuilder output = new StringBuilder() - .append(loggerName) - .append("[") - .append(record.getLevel()).append('|') - .append(Thread.currentThread().getName()).append('|') - .append(format.format(new Date(record.getMillis()))) - .append("]: ") - .append(record.getMessage()).append(' ') - .append(lineSep); - return output.toString(); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/loggers/BriefestLogFormatter.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/loggers/BriefestLogFormatter.java deleted file mode 100644 index 112cee6faa..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/core/util/loggers/BriefestLogFormatter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.core.util.loggers; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.logging.Formatter; -import java.util.logging.LogRecord; - -public class BriefestLogFormatter extends Formatter { - - private static final DateFormat format = new SimpleDateFormat("h:mm:ss"); - private static final String lineSep = System.getProperty("line.separator"); - - /** - * A Custom format implementation that is designed for brevity. - */ - public String format(LogRecord record) { - String loggerName = record.getLoggerName(); - if (loggerName == null) { - loggerName = "root"; - } - StringBuilder output = new StringBuilder() - .append(record.getMessage()) - .append(lineSep); - return output.toString(); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/AboutDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/AboutDialog.java deleted file mode 100644 index 1813396665..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/AboutDialog.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.ri.images.Images; - -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowListener; -import java.util.ResourceBundle; - -@SuppressWarnings("serial") -public class AboutDialog extends EscapeJDialog implements ActionListener, WindowListener { - - - private JButton ok; - private Timer timer; - private int whichTimer; - - private static final int WAIT_TIME = 3000; //time to wait in milliseconds - private static final String IMAGE = "icelogo.png"; //image to include in the dialog - - public static final int NO_BUTTONS = 0; - public static final int OK = 2; - public static final int NO_TIMER = 0; - public static final int DISAPPEAR = 4; - - public AboutDialog(Frame frame, ResourceBundle messageBundle, boolean isModal, - int buttons, int whichTimer) { - super(frame, isModal); - this.whichTimer = whichTimer; - - // Show OK button instead of using display timer - buttons = OK; - whichTimer = NO_TIMER; - - setTitle(messageBundle.getString("viewer.dialog.about.title")); - setResizable(false); - - JPanel panelImage = new javax.swing.JPanel(); - ImageIcon icon = new ImageIcon(Images.get(IMAGE)); - JLabel iconLabel = new JLabel(icon); - iconLabel.setBorder(BorderFactory.createEmptyBorder()); - panelImage.add(iconLabel); - - JLabel label; - - JPanel panel1 = new JPanel(); - panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS)); - panel1.add(Box.createVerticalStrut(10)); - panel1.add(panelImage); - - panel1.add(Box.createVerticalStrut(30)); - label = new JLabel(Document.getLibraryVersion()); - label.setAlignmentX(0.5f); - panel1.add(label); - - - String text = messageBundle.getString("viewer.dialog.about.pageNumber.label"); - int c2 = 0, c1; - while ((c1 = text.indexOf("\n", c2)) > -1) { - panel1.add(Box.createVerticalStrut(10)); - label = new JLabel(text.substring(c2, c1)); - label.setAlignmentX(0.5f); - panel1.add(label); - c2 = c1 + 1; - } - panel1.add(Box.createVerticalStrut(10)); - label = new JLabel(text.substring(c2, text.length())); - label.setAlignmentX(0.5f); - panel1.add(label); - - //insets: needs swing component in order to set the Insets - JPanel pane = new JPanel(); - pane.setBorder(new EmptyBorder(5, 15, 5, 15)); - - pane.setLayout(new BorderLayout()); - pane.add(panel1); - - if (buttons > NO_BUTTONS) { - JPanel panel2 = new JPanel(); - panel2.setLayout(new FlowLayout()); - if ((buttons & OK) > 0) { - ok = new JButton(messageBundle.getString("viewer.button.ok.label")); - ok.addActionListener(this); - if (whichTimer > 0) { - ok.setEnabled(false); - } - panel2.add(ok); - } - pane.add(panel2, BorderLayout.SOUTH); - } - - setContentPane(pane); - - pack(); - setLocationRelativeTo(frame); - - if (whichTimer > 0) { - timer = new Timer(WAIT_TIME, this); - timer.start(); - } - } - - public void actionPerformed(ActionEvent ev) { - if (ev.getSource() == timer) { - timer.stop(); - if (whichTimer == OK) { - ok.setEnabled(true); - } else if (whichTimer == DISAPPEAR) { - setVisible(false); - dispose(); - } - } else if (ev.getSource() == ok) { - setVisible(false); - dispose(); - } - } - - public void windowClosing(java.awt.event.WindowEvent ev) { - if (ok.isEnabled()) { - setVisible(false); - dispose(); - } - } - - public void windowActivated(java.awt.event.WindowEvent ev) { - } - - public void windowClosed(java.awt.event.WindowEvent ev) { - } - - public void windowDeactivated(java.awt.event.WindowEvent ev) { - } - - public void windowDeiconified(java.awt.event.WindowEvent ev) { - } - - public void windowIconified(java.awt.event.WindowEvent ev) { - } - - public void windowOpened(java.awt.event.WindowEvent ev) { - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/ComponentKeyBinding.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/ComponentKeyBinding.java deleted file mode 100644 index e152d4fb7a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/ComponentKeyBinding.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.ri.common.views.DocumentViewController; - -import javax.swing.*; -import java.awt.*; -import java.awt.datatransfer.StringSelection; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; - -/** - * Utility for adding key bindings to a view container for common functionality - * usually handled by the existence of menu key listeners. This class currently - * only adds the copy text keyboard command (ctr-c) to view container but can - * be easily extended to handle other keyboard mappings. - * - * @since 4.2.2 - */ -@SuppressWarnings("serial") -public class ComponentKeyBinding { - - /** - * Installs the component key binding on the specified JComponent. - * - * @param controller SwingController used by various keyboard commands - * @param viewerContainer view container to add keyboard mappings too - */ - public static void install(final SwingController controller, final JComponent viewerContainer) { - Action copyText = new AbstractAction() { - public void actionPerformed(ActionEvent e) { - Document document = controller.getDocument(); - DocumentViewController documentViewController = - controller.getDocumentViewController(); - if (document != null && - controller.havePermissionToExtractContent() && - !(documentViewController.getDocumentViewModel().isSelectAll() && - document.getNumberOfPages() > 250)) { - // get the text. - StringSelection stringSelection = new StringSelection( - documentViewController.getSelectedText()); - Toolkit.getDefaultToolkit().getSystemClipboard(). - setContents(stringSelection, null); - } else { - Runnable doSwingWork = new Runnable() { - public void run() { - org.icepdf.ri.util.Resources.showMessageDialog( - viewerContainer, - JOptionPane.INFORMATION_MESSAGE, - controller.getMessageBundle(), - "viewer.dialog.information.copyAll.title", - "viewer.dialog.information.copyAll.msg", - 250); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } - } - }; - - // add copy text command to input map - InputMap inputMap = viewerContainer.getInputMap( - JComponent.WHEN_IN_FOCUSED_WINDOW); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, Event.CTRL_MASK), - "copyText"); - viewerContainer.getActionMap().put("copyText", - copyText); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/CurrentPageChanger.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/CurrentPageChanger.java deleted file mode 100644 index 6243001b60..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/CurrentPageChanger.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.ri.common.views.*; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.AdjustmentEvent; -import java.awt.event.AdjustmentListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -/** - * - */ -public class CurrentPageChanger extends MouseAdapter implements AdjustmentListener { - - private static final Logger logger = - Logger.getLogger(CurrentPageChanger.class.toString()); - - private boolean isScrolled = false; - - private List pageComponents; - private JScrollPane scrollpane; - private Object mouseWheelCurrentPageListener; - private AbstractDocumentView documentView; - private DocumentViewModel documentViewModel; - - public CurrentPageChanger(JScrollPane scrollpane, - AbstractDocumentView documentView, - List pageComponents) { - this(scrollpane, documentView, pageComponents, true); - } - - public CurrentPageChanger(JScrollPane scrollpane, - AbstractDocumentView documentView, - List pageComponents, - boolean addWheelMouseListener) { - - this.pageComponents = pageComponents; - this.scrollpane = scrollpane; - this.documentView = documentView; - documentViewModel = documentView.getViewModel(); - - // listen for scroll bar manaipulators - this.documentView.addMouseListener(this); - this.scrollpane.getHorizontalScrollBar().addAdjustmentListener(this); - this.scrollpane.getHorizontalScrollBar().addMouseListener(this); - - this.scrollpane.getVerticalScrollBar().addAdjustmentListener(this); - this.scrollpane.getVerticalScrollBar().addMouseListener(this); - -// addMouseListenerToAnyButtonsIn(scrollpane.getHorizontalScrollBar()); -// addMouseListenerToAnyButtonsIn(scrollpane.getVerticalScrollBar()); - - // load wheel mouse listener - mouseWheelCurrentPageListener = MouseWheelCurrentPageListener.install(scrollpane, this); - } - - private void addMouseListenerToAnyButtonsIn(java.awt.Component comp) { - int children = (comp instanceof Container) ? ((Container) comp).getComponentCount() : -1; - for (int i = 0; i < children; i++) { - Component kid = ((Container) comp).getComponent(i); - if (kid instanceof javax.swing.AbstractButton) { - kid.addMouseListener(this); - } - addMouseListenerToAnyButtonsIn(kid); - } - } - - public void mouseReleased(MouseEvent e) { - if (isScrolled) { - calculateCurrentPage(); - isScrolled = false; - } - } - - public void adjustmentValueChanged(AdjustmentEvent e) { - isScrolled = true; - } - - public void calculateCurrentPage() { - if (pageComponents != null) { - Rectangle viewport = scrollpane.getViewport().getViewRect(); - // find visible pages - ArrayList visiblePages = - new ArrayList(10); - Rectangle pageBounds; - int pageCount = 0; - for (AbstractPageViewComponent pageComponent : pageComponents) { - if (pageComponent != null) { - pageBounds = documentViewModel.getPageBounds(pageCount); - if (pageBounds != null && - pageComponent.isShowing()) { - visiblePages.add(pageComponent); - } - } - pageCount++; - } - - // find center point of view port - int x = viewport.x + (viewport.width / 2); - int y = viewport.y + (viewport.height / 2); - Point centerView = new Point(x, y); - - // find out which page center is closest to center and thus the new current page - double minLength = Double.MAX_VALUE; - int minPage = -1; - double tmpDistance; - - for (PageViewComponent pageComponent : visiblePages) { - if (pageComponent != null) { - pageBounds = documentViewModel.getPageBounds( - pageComponent.getPageIndex()); - x = pageBounds.x + (pageBounds.width / 2); - y = pageBounds.y + (pageBounds.height / 2); - // find minimum page. - tmpDistance = centerView.distance(x, y); - if (tmpDistance < minLength) { - minLength = tmpDistance; - minPage = pageComponent.getPageIndex(); - } - } - } - - //clean up - visiblePages.clear(); - visiblePages.trimToSize(); - - // finally send out event to update page number - int oldCurrentPage = documentViewModel.getViewCurrentPageIndex(); - documentViewModel.setViewCurrentPageIndex(minPage); - DocumentViewControllerImpl documentViewController = (DocumentViewControllerImpl) documentView.getParentViewController(); - documentViewController.firePropertyChange(PropertyConstants.DOCUMENT_CURRENT_PAGE, - oldCurrentPage, - minPage); - } - } - - public void dispose() { - // remove standard mouse listeners - documentView.removeMouseListener(this); - scrollpane.getHorizontalScrollBar().removeAdjustmentListener(this); - scrollpane.getHorizontalScrollBar().removeMouseListener(this); - scrollpane.getVerticalScrollBar().removeAdjustmentListener(this); - scrollpane.getVerticalScrollBar().removeMouseListener(this); - - // Remove wheel mouse listener - MouseWheelCurrentPageListener.uninstall(scrollpane, mouseWheelCurrentPageListener); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/DocumentInformationDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/DocumentInformationDialog.java deleted file mode 100644 index 8b7ffef4d3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/DocumentInformationDialog.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.PInfo; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ResourceBundle; - -/** - * This class is a reference implementation for displaying a PDF file's - * document information - * - * @since 1.1 - */ -@SuppressWarnings("serial") -public class DocumentInformationDialog extends EscapeJDialog { - - // layouts constraint - private GridBagConstraints constraints; - - - /** - * Creates the document information dialog. - */ - public DocumentInformationDialog(JFrame frame, Document document, - ResourceBundle messageBundle) { - super(frame, true); - setTitle(messageBundle.getString("viewer.dialog.documentInformation.title")); - - // Do some work on information to get display values - String title = ""; - String author = ""; - String subject = ""; - String keyWords = ""; - String creator = ""; - String producer = ""; - String creationDate = ""; - String modDate = ""; - - // get duplicate names from message bundle - String notAvailable = - messageBundle.getString("viewer.dialog.documentInformation.notAvailable"); - - // get information values if available - PInfo documentInfo = document.getInfo(); - if (documentInfo != null) { - title = documentInfo.getTitle(); - author = documentInfo.getAuthor(); - subject = documentInfo.getSubject(); - keyWords = documentInfo.getKeywords(); - creator = documentInfo.getCreator() != null ? - documentInfo.getCreator() : notAvailable; - producer = documentInfo.getProducer() != null ? - documentInfo.getProducer() : notAvailable; - creationDate = documentInfo.getCreationDate() != null ? - documentInfo.getCreationDate().toString() : notAvailable; - modDate = documentInfo.getModDate() != null ? - documentInfo.getModDate().toString() : notAvailable; - } - - // Create GUI elements - final JButton okButton = new JButton(messageBundle.getString("viewer.button.ok.label")); - okButton.setMnemonic(messageBundle.getString("viewer.button.ok.mnemonic").charAt(0)); - okButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (e.getSource() == okButton) { - setVisible(false); - dispose(); - } - - } - }); - - /** - * Place GUI elements on dialog - */ - - JPanel permissionsPanel = new JPanel(); - - permissionsPanel.setAlignmentY(JPanel.TOP_ALIGNMENT); - GridBagLayout layout = new GridBagLayout(); - permissionsPanel.setLayout(layout); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.EAST; - constraints.insets = new Insets(5, 5, 5, 5); - - // add labels - addGB(permissionsPanel, new JLabel( - messageBundle.getString("viewer.dialog.documentInformation.title.label")), - 0, 0, 1, 1); - addGB(permissionsPanel, new JLabel( - messageBundle.getString("viewer.dialog.documentInformation.subject.label")), - 0, 1, 1, 1); - addGB(permissionsPanel, new JLabel( - messageBundle.getString("viewer.dialog.documentInformation.author.label")), - 0, 2, 1, 1); - addGB(permissionsPanel, new JLabel( - messageBundle.getString("viewer.dialog.documentInformation.keywords.label")), - 0, 3, 1, 1); - addGB(permissionsPanel, new JLabel( - messageBundle.getString("viewer.dialog.documentInformation.creator.label")), - 0, 4, 1, 1); - addGB(permissionsPanel, new JLabel( - messageBundle.getString("viewer.dialog.documentInformation.producer.label")), - 0, 5, 1, 1); - addGB(permissionsPanel, new JLabel( - messageBundle.getString("viewer.dialog.documentInformation.created.label")), - 0, 6, 1, 1); - addGB(permissionsPanel, new JLabel( - messageBundle.getString("viewer.dialog.documentInformation.modified.label")), - 0, 7, 1, 1); - constraints.insets = new Insets(15, 5, 5, 5); - constraints.anchor = GridBagConstraints.CENTER; - addGB(permissionsPanel, okButton, 0, 8, 2, 1); - - // add values - constraints.insets = new Insets(5, 5, 5, 5); - constraints.anchor = GridBagConstraints.WEST; - addGB(permissionsPanel, new JLabel(title), 1, 0, 1, 1); - addGB(permissionsPanel, new JLabel(subject), 1, 1, 1, 1); - addGB(permissionsPanel, new JLabel(author), 1, 2, 1, 1); - addGB(permissionsPanel, new JLabel(keyWords), 1, 3, 1, 1); - addGB(permissionsPanel, new JLabel(creator), 1, 4, 1, 1); - addGB(permissionsPanel, new JLabel(producer), 1, 5, 1, 1); - addGB(permissionsPanel, new JLabel(creationDate), 1, 6, 1, 1); - addGB(permissionsPanel, new JLabel(modDate), 1, 7, 1, 1); - - this.getContentPane().add(permissionsPanel); - - pack(); - setLocationRelativeTo(frame); - } - - /** - * Gridbag constructor helper - * - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan - * @param colSpan - */ - private void addGB(JPanel layout, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - layout.add(component, constraints); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/EscapeJDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/EscapeJDialog.java deleted file mode 100644 index a853e9ba46..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/EscapeJDialog.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.icepdf.ri.common; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; - -/** - * Base JDialog implementation that sets up an escape key listener which will close the the dialog. - */ -public class EscapeJDialog extends JDialog { - - public EscapeJDialog() { - } - - public EscapeJDialog(Dialog owner, boolean modal) { - super(owner, modal); - } - - public EscapeJDialog(Frame owner) { - super(owner); - } - - public EscapeJDialog(Frame owner, boolean modal) { - super(owner, modal); - } - - public EscapeJDialog(Frame owner, String title) { - super(owner, title); - } - - public EscapeJDialog(Frame owner, String title, boolean modal) { - super(owner, title, modal); - } - - /** - * Override createRootPane so that "escape" key can be used to - * close this window. - */ - protected JRootPane createRootPane() { - ActionListener actionListener = new ActionListener() { - public void actionPerformed(ActionEvent actionEvent) { - setVisible(false); - dispose(); - } - }; - JRootPane rootPane = new JRootPane(); - KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); - rootPane.registerKeyboardAction(actionListener, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW); - return rootPane; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/FileExtensionUtils.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/FileExtensionUtils.java deleted file mode 100644 index 3ca68fa46d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/FileExtensionUtils.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import javax.swing.filechooser.FileFilter; -import java.io.File; - -/** - *

      Utility class for creating file extension file filters. - * - * @since 2.0 - */ -public class FileExtensionUtils { - public final static String pdf = "pdf"; - public final static String svg = "svg"; - public final static String ps = "ps"; - public final static String txt = "txt"; - - public static FileFilter getPDFFileFilter() { - return new ExtensionFileFilter("Adobe PDF Files (*.pdf)", pdf); - } - - public static FileFilter getTextFileFilter() { - return new ExtensionFileFilter("Text Files (*.txt)", txt); - } - - public static FileFilter getSVGFileFilter() { - return new ExtensionFileFilter("SVG Files (*.svg)", svg); - } - - public static String getExtension(File f) { - return getExtension(f.getName()); - } - - public static String getExtension(String s) { - String ext = null; - int i = s.lastIndexOf('.'); - - if (i > 0 && i < s.length() - 1) { - ext = s.substring(i + 1).toLowerCase(); - } - return ext; - } - - private static class ExtensionFileFilter extends FileFilter { - private String description; - private String extension; - - ExtensionFileFilter(String desc, String ext) { - description = desc; - extension = ext; - } - - //Accept all directories and all files with extension - public boolean accept(File f) { - if (f.isDirectory()) - return true; - - String ext = FileExtensionUtils.getExtension(f); - if (ext != null) { - if (ext.equals(extension)) - return true; - else - return false; - } - return false; - } - - //The description of this filter - public String getDescription() { - return description; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/FloatTextFieldInputVerifier.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/FloatTextFieldInputVerifier.java deleted file mode 100644 index 6b82156307..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/FloatTextFieldInputVerifier.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import javax.swing.*; -import java.awt.*; - -/** - * Utility method to verify that a components input text is a float number. - * - * @since 4.0 - */ -public class FloatTextFieldInputVerifier extends InputVerifier { - private int maxLength = 6; - - - public FloatTextFieldInputVerifier() { - } - - public FloatTextFieldInputVerifier(int maxLength) { - this.maxLength = maxLength; - } - - public boolean verify(JComponent comp) { - boolean returnValue = true; - JTextField textField = (JTextField) comp; - String content = textField.getText(); - // if the string has a valid length - if (content.length() != 0 && content.length() < maxLength) { - try { - // parse the string just to make sure it is a valid number - Float.parseFloat(textField.getText()); - } catch (NumberFormatException e) { - returnValue = false; - } - } else { - if (content.length() > 0) { - // we don't have to reverify as the keylistener makes - // sure that the string is a number. - textField.setText(content.substring(0, maxLength)); - } else { - textField.setText(""); - } - } - return returnValue; - } - - public boolean shouldYieldFocus(JComponent input) { - boolean valid = super.shouldYieldFocus(input); - if (!valid) { - Toolkit.getDefaultToolkit().beep(); - } - return valid; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/FloatTextFieldKeyListener.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/FloatTextFieldKeyListener.java deleted file mode 100644 index 5de41495cf..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/FloatTextFieldKeyListener.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import java.awt.*; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; - -/** - * Utility class to ignore all keyboard events that are not digits, KeyEvent.VK_BACK_SPACE, - * KeyEvent.VK_DELETE, KeyEvent.VK_ENTER and KeyEvent.VK_PERIOD are exempt. - * - * @since 4.0 - */ -public class FloatTextFieldKeyListener extends KeyAdapter { - public void keyTyped(KeyEvent e) { - char c = e.getKeyChar(); - if (!(Character.isDigit(c) || - c == KeyEvent.VK_PERIOD || - c == KeyEvent.VK_MINUS | - c == KeyEvent.VK_BACK_SPACE || - c == KeyEvent.VK_DELETE || - c == KeyEvent.VK_ESCAPE || - c == KeyEvent.VK_ENTER)) { - Toolkit.getDefaultToolkit().beep(); - e.consume(); - } - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/KeyEventConstants.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/KeyEventConstants.java deleted file mode 100644 index 2a58774f63..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/KeyEventConstants.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import java.awt.*; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; - -/** - * The KeyEvent Class contains the key event and input event used for menu - * and button manipulatin via the keyboard. This class may need to be changed - * depending on region and languages. - */ -public class KeyEventConstants { - - // Get the correct menu shortcut key for the current platform - public static final int MENU_SHORTCUT_KEY_MASK = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); - - public static final int KEY_CODE_OPEN_FILE = KeyEvent.VK_O; - public static final int MODIFIER_OPEN_FILE = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_OPEN_URL = KeyEvent.VK_U; - public static final int MODIFIER_OPEN_URL = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_CLOSE = KeyEvent.VK_W; - public static final int MODIFIER_CLOSE = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_SAVE_AS = KeyEvent.VK_S; - public static final int MODIFIER_SAVE_AS = MENU_SHORTCUT_KEY_MASK | InputEvent.SHIFT_MASK; - public static final int KEY_CODE_PRINT_SETUP = KeyEvent.VK_P; - public static final int MODIFIER_PRINT_SETUP = MENU_SHORTCUT_KEY_MASK | InputEvent.SHIFT_MASK; - public static final int KEY_CODE_PRINT = KeyEvent.VK_P; - public static final int MODIFIER_PRINT = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_EXIT = KeyEvent.VK_Q; - public static final int MODIFIER_EXIT = MENU_SHORTCUT_KEY_MASK; - - public static final int KEY_CODE_FIT_ACTUAL = KeyEvent.VK_1; - public static final int MODIFIER_FIT_ACTUAL = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_FIT_PAGE = KeyEvent.VK_2; - public static final int MODIFIER_FIT_PAGE = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_FIT_WIDTH = KeyEvent.VK_3; - public static final int MODIFIER_FIT_WIDTH = MENU_SHORTCUT_KEY_MASK; - - public static final int KEY_CODE_ZOOM_IN = KeyEvent.VK_I; - public static final int MODIFIER_ZOOM_IN = MENU_SHORTCUT_KEY_MASK | InputEvent.SHIFT_MASK; - public static final int KEY_CODE_ZOOM_OUT = KeyEvent.VK_O; - public static final int MODIFIER_ZOOM_OUT = MENU_SHORTCUT_KEY_MASK | InputEvent.SHIFT_MASK; - - public static final int KEY_CODE_ROTATE_LEFT = KeyEvent.VK_L; - public static final int MODIFIER_ROTATE_LEFT = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_ROTATE_RIGHT = KeyEvent.VK_R; - public static final int MODIFIER_ROTATE_RIGHT = MENU_SHORTCUT_KEY_MASK; - - public static final int KEY_CODE_FIRST_PAGE = KeyEvent.VK_UP; - public static final int MODIFIER_FIRST_PAGE = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_PREVIOUS_PAGE = KeyEvent.VK_LEFT; - public static final int MODIFIER_PREVIOUS_PAGE = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_NEXT_PAGE = KeyEvent.VK_RIGHT; - public static final int MODIFIER_NEXT_PAGE = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_LAST_PAGE = KeyEvent.VK_DOWN; - public static final int MODIFIER_LAST_PAGE = MENU_SHORTCUT_KEY_MASK; - - public static final int KEY_CODE_SEARCH = KeyEvent.VK_S; - public static final int MODIFIER_SEARCH = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_GOTO = KeyEvent.VK_N; - public static final int MODIFIER_GOTO = MENU_SHORTCUT_KEY_MASK; - - public static final int KEY_CODE_UNDO = KeyEvent.VK_Z; - public static final int MODIFIER_UNDO = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_REDO = KeyEvent.VK_Z; - public static final int MODIFIER_REDO = MENU_SHORTCUT_KEY_MASK | InputEvent.SHIFT_MASK; - public static final int KEY_CODE_COPY = KeyEvent.VK_C; - public static final int MODIFIER_COPY = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_DELETE = KeyEvent.VK_D; - public static final int MODIFIER_DELETE = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_SELECT_ALL = KeyEvent.VK_A; - public static final int MODIFIER_SELECT_ALL = MENU_SHORTCUT_KEY_MASK; - public static final int KEY_CODE_DESELECT_ALL = KeyEvent.VK_A; - public static final int MODIFIER_DESELECT_ALL = MENU_SHORTCUT_KEY_MASK | InputEvent.SHIFT_MASK; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/KeyListenerPageChanger.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/KeyListenerPageChanger.java deleted file mode 100644 index d5877f6384..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/KeyListenerPageChanger.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.ri.common.views.AbstractDocumentView; - -import javax.swing.*; -import java.awt.event.KeyAdapter; - -/** - * This intercepts KeyEvents for a JScrollPane, and determines if - * they qualify to initiate a page change request for the SwingController. - * - * @author Mark Collette - * @since 2.0 - */ -public class KeyListenerPageChanger extends KeyAdapter { - private SwingController controller; - private JScrollPane scroll; - private AbstractDocumentView documentView; - - /** - * KeyEvents can queue up, if the user holds down a key, - * causing us to do several page changes, unless we use - * flagging to ignore the extraneous KeyEvents - */ - private boolean changingPage; - - - /** - * Install a KeyListenerPageChanger as a KeyListener - * - * @param c SwingController that can change pages - * @param s JScrollPane that has a vertical JScrollBar, and where events come from - */ - public static KeyListenerPageChanger install(SwingController c, JScrollPane s, - AbstractDocumentView documentView) { - KeyListenerPageChanger listener = null; - if (c != null && s != null) { - listener = new KeyListenerPageChanger(c, s, documentView); - s.addKeyListener(listener); - } - return listener; - } - - public void uninstall() { - if (scroll != null) { - scroll.removeKeyListener(this); - } - } - - protected KeyListenerPageChanger(SwingController c, JScrollPane s, - AbstractDocumentView documentView) { - controller = c; - scroll = s; - this.documentView = documentView; - changingPage = false; - } - - public void keyPressed(java.awt.event.KeyEvent e) { - //if( !pageView.changePageWhenKeyOverscrolling() ) - // return; - if (changingPage) - return; - int deltaPage = 0; - JScrollBar visibleVerticalScrollBar = - (scroll.getVerticalScrollBar() != null && - scroll.getVerticalScrollBar().isVisible()) - ? scroll.getVerticalScrollBar() - : null; - int keyCode = e.getKeyCode(); - if (keyCode == java.awt.event.KeyEvent.VK_PAGE_DOWN || - keyCode == java.awt.event.KeyEvent.VK_DOWN) { - if (visibleVerticalScrollBar != null) { - int value = visibleVerticalScrollBar.getModel().getValue(); - int extent = visibleVerticalScrollBar.getModel().getExtent(); - int max = visibleVerticalScrollBar.getModel().getMaximum(); - if (value + extent >= max) - deltaPage = documentView.getNextPageIncrement(); - } else - deltaPage = documentView.getNextPageIncrement(); - } else if (keyCode == java.awt.event.KeyEvent.VK_PAGE_UP || - keyCode == java.awt.event.KeyEvent.VK_UP) { - if (visibleVerticalScrollBar != null) { - int value = visibleVerticalScrollBar.getModel().getValue(); - if (value <= 0) - deltaPage = -documentView.getPreviousPageIncrement(); - } else - deltaPage = -documentView.getPreviousPageIncrement(); - } else if (keyCode == java.awt.event.KeyEvent.VK_HOME) { - deltaPage = -controller.getCurrentPageNumber(); - } else if (keyCode == java.awt.event.KeyEvent.VK_END) { - deltaPage = controller.getDocument().getNumberOfPages() - controller.getCurrentPageNumber() - 1; - } - - if (deltaPage == 0) - return; - int newPage = controller.getCurrentPageNumber() + deltaPage; - if (controller.getDocument() == null) { - return; - } - if (newPage < 0) { - deltaPage = -controller.getCurrentPageNumber(); - } - if (newPage >= controller.getDocument().getNumberOfPages()) { - deltaPage = controller.getDocument().getNumberOfPages() - controller.getCurrentPageNumber() - 1; - } - - if (deltaPage == 0) { - return; - } - - changingPage = true; - final int dp = deltaPage; - SwingUtilities.invokeLater(new Runnable() { - public void run() { - changingPage = false; - controller.goToDeltaPage(dp); - } - }); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/KeyListenerPageColumnChanger.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/KeyListenerPageColumnChanger.java deleted file mode 100644 index 61f0d0797a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/KeyListenerPageColumnChanger.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.ri.common.views.AbstractDocumentView; - -import javax.swing.*; -import java.awt.event.KeyAdapter; - -/** - * This intercepts KeyEvents for a JScrollPane, and determines if - * they qualify to initiate a page change request for the SwingController. - */ -public class KeyListenerPageColumnChanger extends KeyAdapter { - private SwingController controller; - private JScrollPane scroll; - private AbstractDocumentView documentView; - private CurrentPageChanger currentPageChanger; - - /** - * KeyEvents can queue up, if the user holds down a key, - * causing us to do several page changes, unless we use - * flagging to ignore the extraneous KeyEvents - */ - private boolean changingPage; - - - /** - * Install a KeyListenerPageChanger as a KeyListener - * - * @param c SwingController that can change pages - * @param s JScrollPane that has a vertical JScrollBar, and where events come from - */ - public static KeyListenerPageColumnChanger install(SwingController c, JScrollPane s, - AbstractDocumentView documentView, - CurrentPageChanger currentPageChanger) { - KeyListenerPageColumnChanger listener = null; - if (c != null && s != null) { - listener = new KeyListenerPageColumnChanger(c, s, documentView, currentPageChanger); - s.addKeyListener(listener); - } - return listener; - } - - public void uninstall() { - if (scroll != null) { - scroll.removeKeyListener(this); - } - } - - protected KeyListenerPageColumnChanger(SwingController c, JScrollPane s, - AbstractDocumentView documentView, - CurrentPageChanger currentPageChanger) { - controller = c; - scroll = s; - this.documentView = documentView; - changingPage = false; - this.currentPageChanger = currentPageChanger; - } - - public void keyPressed(java.awt.event.KeyEvent e) { - - if (changingPage) - return; - int deltaPage = 0; - - int keyCode = e.getKeyCode(); - if (keyCode == java.awt.event.KeyEvent.VK_PAGE_DOWN) { - deltaPage = documentView.getPreviousPageIncrement(); - } else if (keyCode == java.awt.event.KeyEvent.VK_PAGE_UP) { - deltaPage = -documentView.getNextPageIncrement(); - } else if (keyCode == java.awt.event.KeyEvent.VK_HOME) { - deltaPage = -controller.getCurrentPageNumber(); - } else if (keyCode == java.awt.event.KeyEvent.VK_END) { - deltaPage = controller.getDocument().getNumberOfPages() - controller.getCurrentPageNumber() - 1; - } - - if (deltaPage == 0) - return; - - int newPage = controller.getCurrentPageNumber() + deltaPage; - if (controller.getDocument() == null) { - return; - } - if (newPage < 0) { - deltaPage = -controller.getCurrentPageNumber(); - } - if (newPage >= controller.getDocument().getNumberOfPages()) { - deltaPage = controller.getDocument().getNumberOfPages() - controller.getCurrentPageNumber() - 1; - } - changingPage = true; - final int dp = deltaPage; - SwingUtilities.invokeLater(new Runnable() { - public void run() { - changingPage = false; - controller.goToDeltaPage(dp); - - } - }); - } - - public void keyReleased(java.awt.event.KeyEvent e) { - int keyCode = e.getKeyCode(); - if (keyCode == java.awt.event.KeyEvent.VK_UP || - keyCode == java.awt.event.KeyEvent.VK_DOWN) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - currentPageChanger.calculateCurrentPage(); - } - }); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MouseWheelCurrentPageListener.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MouseWheelCurrentPageListener.java deleted file mode 100644 index da6dee9e5a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MouseWheelCurrentPageListener.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import javax.swing.*; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; - -/** - * - */ -public class MouseWheelCurrentPageListener implements MouseWheelListener { - private JScrollPane scrollpane; - private CurrentPageChanger currentPageChanger; - - /** - * KeyEvents can queue up, if the user holds down a key, - * causing us to do several page changes, unless we use - * flagging to ignore the extraneous KeyEvents - */ - private boolean calculatingCurrentPage; - - - /** - * Install a MouseWheelCurrentPageListener as a MouseWheelListener - */ - public static Object install(JScrollPane scrollpane, - CurrentPageChanger currentPageChanger) { - MouseWheelCurrentPageListener listener = null; - if (scrollpane != null && currentPageChanger != null) { - listener = - new MouseWheelCurrentPageListener(scrollpane, currentPageChanger); - scrollpane.addMouseWheelListener(listener); - } - return listener; - } - - public static void uninstall(JScrollPane scrollpane, Object listener) { - if (scrollpane != null && listener != null && - listener instanceof MouseWheelCurrentPageListener) { - scrollpane.removeMouseWheelListener((MouseWheelCurrentPageListener) listener); - } - } - - protected MouseWheelCurrentPageListener(JScrollPane scrollpane, - CurrentPageChanger currentPageChanger) { - this.scrollpane = scrollpane; - this.currentPageChanger = currentPageChanger; - calculatingCurrentPage = false; - } - - public void mouseWheelMoved(MouseWheelEvent e) { - if (calculatingCurrentPage) - return; - int amount = e.getScrollAmount(); - if (amount > 0) { - calculatingCurrentPage = true; - currentPageChanger.calculateCurrentPage(); - calculatingCurrentPage = false; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MouseWheelListenerPageChanger.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MouseWheelListenerPageChanger.java deleted file mode 100644 index a29c99b284..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MouseWheelListenerPageChanger.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.ri.common.tools.DynamicZoomHandler; -import org.icepdf.ri.common.views.AbstractDocumentView; - -import javax.swing.*; -import java.awt.event.InputEvent; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; - -/** - * This intercepts MouseWheelEvent for a JScrollPane, and determines if - * they qualify to initiate a page change request for the SwingController. - * - * @author Mark Collette - * @since 2.0 - */ -public class MouseWheelListenerPageChanger implements MouseWheelListener { - private SwingController controller; - private JScrollPane scrollpane; - private AbstractDocumentView documentView; - - /** - * KeyEvents can queue up, if the user holds down a key, - * causing us to do several page changes, unless we use - * flagging to ignore the extraneous KeyEvents - */ - private boolean changingPage; - - - /** - * Install a MouseWheelListenerPageChanger as a MouseWheelListener - * - * @param c SwingController that can change pages - * @param s JScrollPane that has a vertical JScrollBar, and where events come from - */ - public static Object install(SwingController c, JScrollPane s, - AbstractDocumentView documentView) { - MouseWheelListenerPageChanger listener = null; - if (c != null && s != null) { - listener = new MouseWheelListenerPageChanger(c, s, documentView); - s.addMouseWheelListener(listener); - } - return listener; - } - - protected MouseWheelListenerPageChanger(SwingController c, JScrollPane s, - AbstractDocumentView documentView) { - controller = c; - scrollpane = s; - this.documentView = documentView; - changingPage = false; - } - - public static void uninstall(JScrollPane scrollpane, Object listener) { - if (scrollpane != null && listener != null && - listener instanceof MouseWheelListenerPageChanger) { - scrollpane.removeMouseWheelListener((MouseWheelListenerPageChanger) listener); - } - } - - public void mouseWheelMoved(MouseWheelEvent e) { - - if (changingPage) - return; - int deltaPage = 0; - JScrollBar visibleVerticalScrollBar = - (scrollpane.getVerticalScrollBar() != null && - scrollpane.getVerticalScrollBar().isVisible()) - ? scrollpane.getVerticalScrollBar() - : null; - - // Scrolling down but only if the ctrl mask isn't present. - if (!((e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK || - documentView.getCurrentToolHandler() instanceof DynamicZoomHandler)) { - int amount = e.getScrollAmount(); - int rotation = e.getWheelRotation(); - - if (amount > 0 && rotation > 0) { - if (visibleVerticalScrollBar != null) { - int value = visibleVerticalScrollBar.getModel().getValue(); - int extent = visibleVerticalScrollBar.getModel().getExtent(); - int max = visibleVerticalScrollBar.getModel().getMaximum(); - if (value + extent >= max) - deltaPage = documentView.getPreviousPageIncrement(); - } else - deltaPage = documentView.getPreviousPageIncrement(); - } - // Up - else if (amount > 0 && rotation < 0) { - if (visibleVerticalScrollBar != null) { - int value = visibleVerticalScrollBar.getModel().getValue(); - if (value <= 0) - deltaPage = -documentView.getPreviousPageIncrement(); - } else - deltaPage = -documentView.getPreviousPageIncrement(); - } - } - - - if (deltaPage == 0) - return; - - int newPage = controller.getCurrentPageNumber() + deltaPage; - if (controller.getDocument() == null) { - return; - } - if (newPage < 0) { - deltaPage = -controller.getCurrentPageNumber(); - } - if (newPage >= controller.getDocument().getNumberOfPages()) { - deltaPage = controller.getDocument().getNumberOfPages() - controller.getCurrentPageNumber() - 1; - } - - if (deltaPage == 0) { - return; - } -// System.out.println("Delta " + deltaPage + " " + controller.getCurrentPageNumber() + " " + visibleVerticalScrollBar); - - changingPage = true; - final int dp = deltaPage; - SwingUtilities.invokeLater(new Runnable() { - public void run() { - changingPage = false; - controller.goToDeltaPage(dp); - } - }); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MyAnnotationCallback.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MyAnnotationCallback.java deleted file mode 100644 index 167c426f4c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MyAnnotationCallback.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.actions.*; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.LinkAnnotation; -import org.icepdf.core.pobjects.annotations.MarkupAnnotation; -import org.icepdf.ri.common.views.*; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.PopupAnnotationComponent; -import org.icepdf.ri.util.BareBonesBrowserLaunch; - -import java.io.File; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * This class represents a basic implementation of the AnnotationCallback - * - * @author ICEsoft Technologies, Inc. - * @since 2.6 - */ -public class MyAnnotationCallback implements AnnotationCallback { - - private static final Logger logger = - Logger.getLogger(MyAnnotationCallback.class.toString()); - - private DocumentViewController documentViewController; - - - public MyAnnotationCallback(DocumentViewController documentViewController) { - this.documentViewController = documentViewController; - } - - /** - *

      Implemented Annotation Callback method. When an annotation is - * activated in a PageViewComponent it passes the annotation to this method - * for processing. The PageViewComponent take care of drawing the - * annotation states but it up to this method to process the - * annotation.

      - * - * @param annotation annotation that was activated by a user via the - * PageViewComponent. - * @param action the action event that was fired when the annotation was clicked. This can be - * the A or AA entry. - * @param x x-coordinate of input device click that initiated the annotation action. - * @param y y-coordinate of input device click that initiated the annotation action. - */ - public void processAnnotationAction(Annotation annotation, Action action, int x, int y) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Annotation " + annotation.toString()); - if (annotation.getAction() != null) { - logger.fine(" Action: " + annotation.getAction().toString()); - } - } - - if (annotation instanceof LinkAnnotation) { - LinkAnnotation linkAnnotation = (LinkAnnotation) annotation; - // look for an A entry, - if (action != null) { - // do instance of check to process actions correctly. - if (action instanceof GoToAction && - documentViewController != null) { - documentViewController.setDestinationTarget( - ((GoToAction) action).getDestination()); - } else if (action instanceof URIAction) { - BareBonesBrowserLaunch.openURL( - ((URIAction) action).getURI()); - } else if (action instanceof GoToRAction) { - // process resource request - } else if (action instanceof LaunchAction) { - LaunchAction launchAction = (LaunchAction) action; - String file = launchAction.getExternalFile(); - String location = - documentViewController.getDocument().getDocumentLocation(); - location = location.substring(0, location.lastIndexOf(File.separator) + 1); - BareBonesBrowserLaunch.openFile(location + file); - } - - } - // look for a Dest entry, only present if an action is not found - // or vise versa. - else if (linkAnnotation.getDestination() != null && - documentViewController != null) { - // use this controller to navigate to the correct page - documentViewController.setDestinationTarget( - linkAnnotation.getDestination()); - } - - } - // catch any other annotation types and try and process their action. - else { - // look for the dest entry and navigate to it. - if (action != null) { - if (action instanceof GoToAction) { - documentViewController.setDestinationTarget( - ((GoToAction) action).getDestination()); - } else if (action instanceof URIAction) { - BareBonesBrowserLaunch.openURL( - ((URIAction) action).getURI()); - } else if (action instanceof SubmitFormAction) { - // submits form data following the submit actions. - int responseCode = ((SubmitFormAction) action).executeFormAction(x, y); - } else if (action instanceof ResetFormAction) { - // resets the form data following reset action. - int responseCode = ((ResetFormAction) action).executeFormAction(x, y); - } else if (action instanceof JavaScriptAction) { - // resets the form dat following reset actions properties - JavaScriptAction javaScriptAction = (JavaScriptAction) action; - if (logger.isLoggable(Level.FINE)) { - logger.fine("Annotation JS: " + javaScriptAction.getJavaScript()); - } - } else if (action instanceof NamedAction) { - // Named actions are key words that we should act on. - NamedAction namedAction = (NamedAction) action; - Name actionName = namedAction.getNamedAction(); - // go to the first page of the document. - if (NamedAction.FIRST_PAGE_KEY.equals(actionName)) { - documentViewController.setCurrentPageIndex(0); - } // go to the last page of the document. - else if (NamedAction.LAST_PAGE_KEY.equals(actionName)) { - int numberOfPages = documentViewController.getDocument().getNumberOfPages(); - documentViewController.setCurrentPageIndex(numberOfPages - 1); - } // next page. - else if (NamedAction.NEXT_PAGE_KEY.equals(actionName)) { - int currentPageNumber = documentViewController.getCurrentPageIndex(); - documentViewController.setCurrentPageIndex(currentPageNumber + 1); - } // previous page. - else if (NamedAction.PREV_PAGE_KEY.equals(actionName)) { - int currentPageNumber = documentViewController.getCurrentPageIndex(); - documentViewController.setCurrentPageIndex(currentPageNumber - 1); - } // print the current document. - else if (NamedAction.PRINT_KEY.equals(actionName)) { - SwingController controller = (SwingController) documentViewController.getParentController(); - controller.print(true); - } // show save as dialog. - else if (NamedAction.SAVE_AS_KEY.equals(actionName)) { - SwingController controller = (SwingController) documentViewController.getParentController(); - controller.saveFile(); - } - } - } - } - } - - /** - *

      Implemented Annotation Callback method. This method is called when a - * pages annotations been initialized but before the page has been painted. - * This method blocks the

      - * - * @param page page that has been initialized. The pages annotations are - * available via an accessor method. - */ - public void pageAnnotationsInitialized(Page page) { - - } - - /** - * New annotation created with view tool. - * - * @param pageComponent page that annotation was added to. - * @param annotationComponent component that will be created. - */ - public void newAnnotation(PageViewComponent pageComponent, - AnnotationComponent annotationComponent) { - // do a bunch a work to get at the page object. - Document document = documentViewController.getDocument(); - PageTree pageTree = document.getPageTree(); - Page page = pageTree.getPage(pageComponent.getPageIndex()); - page.addAnnotation(annotationComponent.getAnnotation()); - - // no we have let the pageComponent now about it. - ((PageViewComponentImpl) pageComponent).addAnnotation(annotationComponent); - -// // finally change the current tool to the annotation selection -// documentViewController.getParentController().setDocumentToolMode( -// DocumentViewModel.DISPLAY_TOOL_SELECTION); - } - - /** - * Update the annotation and ready state for save. - * - * @param annotationComponent annotation component to be added to page. - */ - public void updateAnnotation(AnnotationComponent annotationComponent) { - Document document = documentViewController.getDocument(); - PageTree pageTree = document.getPageTree(); - Page page = pageTree.getPage(annotationComponent.getPageIndex()); - page.updateAnnotation(annotationComponent.getAnnotation()); - } - - /** - * Remove the annotation and ready state for save. - * - * @param annotationComponent annotation component to be added to page. - */ - public void removeAnnotation(PageViewComponent pageComponent, - AnnotationComponent annotationComponent) { - // remove annotation - Document document = documentViewController.getDocument(); - PageTree pageTree = document.getPageTree(); - Page page = pageTree.getPage(pageComponent.getPageIndex()); - // remove from page - page.deleteAnnotation(annotationComponent.getAnnotation()); - // remove from page view. - ((PageViewComponentImpl) pageComponent).removeAnnotation(annotationComponent); - // check to see if there is an associated popup - if (annotationComponent.getAnnotation() instanceof MarkupAnnotation) { - MarkupAnnotation markupAnnotation = - (MarkupAnnotation) annotationComponent.getAnnotation(); - if (markupAnnotation.getPopupAnnotation() != null) { - page.deleteAnnotation(markupAnnotation.getPopupAnnotation()); - // find and remove the popup component - ArrayList annotationComponents = - ((PageViewComponentImpl) pageComponent).getAnnotationComponents(); - Reference compReference; - Reference popupReference = markupAnnotation.getPopupAnnotation().getPObjectReference(); - AnnotationComponent annotationComp; - for (int i = 0, max = annotationComponents.size(); i < max; i++) { - annotationComp = annotationComponents.get(i); - compReference = annotationComp.getAnnotation().getPObjectReference(); - // find the component and toggle it's visibility. - if (compReference != null && compReference.equals(popupReference)) { - if (annotationComp instanceof PopupAnnotationComponent) { - PopupAnnotationComponent popupComponent = ((PopupAnnotationComponent) annotationComp); - ((PageViewComponentImpl) pageComponent).removeAnnotation(popupComponent); - } - } - } - } - } - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MyGUISecurityCallback.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MyGUISecurityCallback.java deleted file mode 100644 index a25f5aaf98..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/MyGUISecurityCallback.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.SecurityCallback; -import org.icepdf.core.pobjects.Document; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowListener; -import java.util.ResourceBundle; - -/** - * This class is reference code for displaying a password dialog box for - * encrypted PDF documents. - * - * @since 1.1 - */ -public class MyGUISecurityCallback implements SecurityCallback { - - private JFrame parentFrame; - private ResourceBundle messageBundle; - - /** - * Create a new instance of a SecurityCallback. This class displays a - * dialog when the requestPassword method is called to retrieve the document's - * password from the user. - * - * @param frame frame that the dialog will be centered on. - */ - public MyGUISecurityCallback(JFrame frame, ResourceBundle messageBundle) { - parentFrame = frame; - this.messageBundle = messageBundle; - } - - public String requestPassword(Document document) { - // get password from dialog - PasswordDialog passwordDialog = new PasswordDialog(parentFrame); - // show the dialog in blocking mode - passwordDialog.setVisible(true); - - // if the dialog was cancelled return null - if (passwordDialog.isCanceled) { - return null; - } - // otherwise return the password - else { - return passwordDialog.getPassword(); - } - } - - /** - * Builds a new JDialog which displays a gui for entering a password. - */ - @SuppressWarnings("serial") - class PasswordDialog extends EscapeJDialog implements WindowListener { - - // layouts constraint - private GridBagConstraints constraints; - - // capture password information - private JPasswordField passwordField; - - // dialog was canceled - private boolean isCanceled = false; - - - /** - * Creates the permissions dialog. - */ - public PasswordDialog(JFrame frame) { - super(frame, true); - setTitle(messageBundle.getString("viewer.dialog.security.title")); - - // Create GUI elements - // ok button - final JButton okButton = new JButton(messageBundle.getString("viewer.dialog.security.okButton.label")); - okButton.setMnemonic(messageBundle.getString("viewer.dialog.security.okButton.mnemonic").charAt(0)); - okButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (e.getSource() == okButton) { - setVisible(false); - dispose(); - } - - } - }); - - // cancel button - final JButton cancelButton = new JButton(messageBundle.getString("viewer.dialog.security.cancelButton.label")); - cancelButton.setMnemonic(messageBundle.getString("viewer.dialog.security.cancelButton.mnemonic").charAt(0)); - cancelButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (e.getSource() == cancelButton) { - setVisible(false); - isCanceled = true; - dispose(); - } - - } - }); - // setup password field - passwordField = new JPasswordField(30); - passwordField.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (e.getSource() == passwordField) { - setVisible(false); - dispose(); - } - - } - }); - JLabel msg1 = new JLabel(messageBundle.getString("viewer.dialog.security.msg")); - JLabel msg2 = new JLabel(messageBundle.getString("viewer.dialog.security.password.label")); - - /** - * Place GUI elements on dialog - */ - - JPanel passwordPanel = new JPanel(); - - passwordPanel.setAlignmentY(JPanel.TOP_ALIGNMENT); - passwordPanel.setAlignmentX(JPanel.CENTER_ALIGNMENT); - GridBagLayout layout = new GridBagLayout(); - passwordPanel.setLayout(layout); - this.getContentPane().add(passwordPanel); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(1, 10, 1, 1); - - // add components - addGB(passwordPanel, msg1, 0, 0, 3, 1); - - addGB(passwordPanel, msg2, 0, 1, 1, 1); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.insets = new Insets(1, 10, 1, 10); - addGB(passwordPanel, passwordField, 1, 1, 2, 1); - - constraints.insets = new Insets(10, 1, 1, 1); - constraints.fill = GridBagConstraints.NONE; - addGB(passwordPanel, okButton, 1, 2, 1, 1); - addGB(passwordPanel, cancelButton, 2, 2, 1, 1); - - pack(); - setLocationRelativeTo(frame); - setResizable(false); - setSize(306, 150); - - this.addWindowListener(this); - } - - /** - * Gets the password string from the dialogs password text field. - * - * @return password that was type in the dialog password text field. - */ - public String getPassword() { - return new String(passwordField.getPassword()); - } - - /** - * Has the dialog been cancelled by either the cancel button or - * by closing the window. - * - * @return true if the dialog was closed, true if the OK button was - * pressed. - */ - public boolean isCancelled() { - return isCanceled; - } - - - /** - * Gridbag constructor helper - * - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan - * @param colSpan - */ - private void addGB(JPanel layout, Component component, - int x, int y, - int colSpan, int rowSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = colSpan; - constraints.gridheight = rowSpan; - layout.add(component, constraints); - } - - /** - * Make sure that the isCanceled flag is set on closing of the window - * - * @param ev window closing event - */ - public void windowClosing(java.awt.event.WindowEvent ev) { - setVisible(false); - isCanceled = true; - dispose(); - } - - // not currently used - public void windowActivated(java.awt.event.WindowEvent ev) { - } - - public void windowClosed(java.awt.event.WindowEvent ev) { - } - - public void windowDeactivated(java.awt.event.WindowEvent ev) { - } - - public void windowDeiconified(java.awt.event.WindowEvent ev) { - } - - public void windowIconified(java.awt.event.WindowEvent ev) { - } - - public void windowOpened(java.awt.event.WindowEvent ev) { - } - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PageNumberTextFieldInputVerifier.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PageNumberTextFieldInputVerifier.java deleted file mode 100644 index f8ce0fee98..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PageNumberTextFieldInputVerifier.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import javax.swing.*; -import java.awt.*; - -/** - * Utility method to verify that a components input text is a whole number. - * - * @author Mark Collette - * @since 2.0 - */ -public class PageNumberTextFieldInputVerifier extends InputVerifier { - final static int maxLength = 4; - - public boolean verify(JComponent comp) { - boolean returnValue = true; - JTextField textField = (JTextField) comp; - String content = textField.getText(); - // if the string has a valid length - if (content.length() != 0 && content.length() < maxLength) { - try { - // parse the string just to make sure it is a valid number - Integer.parseInt(textField.getText()); - } catch (NumberFormatException e) { - returnValue = false; - } - } else { - if (content.length() > 0) { - // we don't have to reverify as the keylistener makes - // sure that the string is a number. - textField.setText(content.substring(0, maxLength)); - } else { - textField.setText(""); - } - } - return returnValue; - } - - public boolean shouldYieldFocus(JComponent input) { - boolean valid = super.shouldYieldFocus(input); - if (!valid) { - Toolkit.getDefaultToolkit().beep(); - } - return valid; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PageNumberTextFieldKeyListener.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PageNumberTextFieldKeyListener.java deleted file mode 100644 index cb20d7d216..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PageNumberTextFieldKeyListener.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import java.awt.*; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; - -/** - * Utility class to ignore all keyboard events that are not digits, KeyEvent.VK_BACK_SPACE, - * KeyEvent.VK_DELETE, or KeyEvent.VK_ENTER. - * - * @author Mark Collette - * @since 2.0 - */ -public class PageNumberTextFieldKeyListener extends KeyAdapter { - public void keyTyped(KeyEvent e) { - char c = e.getKeyChar(); - if (!(Character.isDigit(c) || - c == KeyEvent.VK_BACK_SPACE || - c == KeyEvent.VK_DELETE || - c == KeyEvent.VK_ESCAPE || - c == KeyEvent.VK_ENTER)) { - Toolkit.getDefaultToolkit().beep(); - e.consume(); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PageThumbnailComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PageThumbnailComponent.java deleted file mode 100644 index b21c89dbf8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PageThumbnailComponent.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.PageTree; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.ri.common.views.AbstractPageViewComponent; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.util.concurrent.FutureTask; -import java.util.logging.Logger; - -/** - * The PageThumbnailComponent represents one page thumbnail preview in the larger - * ThumbnailsPanel. The Component when visible will try to load a thumbnail - * from the Page object, the size of this thumbnail is defined by the document - * and is displayed as is. If no embedded thumbnail is found the page is - * initialized and page thumbnail is captured and cached. The size of this - * thumbnail can be configure with the system property: - *

      - * org.icepdf.vi.views.buffersize.vertical - */ -@SuppressWarnings("serial") -public class PageThumbnailComponent extends AbstractPageViewComponent implements MouseListener { - - private static final Logger logger = - Logger.getLogger(PageThumbnailComponent.class.toString()); - - private SwingController controller; - - public PageThumbnailComponent(SwingController controller, - JScrollPane parentScrollPane, PageTree pageTree, - int pageNumber, float thumbNailZoom) { - this(controller, parentScrollPane, pageTree, pageNumber, 0, 0, thumbNailZoom); - } - - public PageThumbnailComponent(SwingController controller, - JScrollPane parentScrollPane, PageTree pageTree, - int pageNumber, - int width, int height, - float thumbNailZoom) { - super(controller.getDocumentViewController().getDocumentViewModel(), - pageTree, pageNumber, parentScrollPane, width, height); - - this.controller = controller; - - // current state. - pageZoom = thumbNailZoom; - pageRotation = 0; - - addMouseListener(this); - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - - // throw the resize event which will trigger a paint. - updateView(PropertyConstants.DOCUMENT_VIEW_ZOOM_CHANGE, 1, pageZoom); - } - - - protected void calculateBufferLocation() { - // grab a reference to the graphics configuration via the AWT thread, if we get it on the worker thread - // it sometimes return null. - graphicsConfiguration = parentScrollPane.getGraphicsConfiguration(); - - // page location in the the entire view. - Rectangle pageLocation = this.getBounds(); - Rectangle viewPort = parentScrollPane.getViewport().getViewRect(); - - // check if we need create or refresh the back pageBufferPadding. - if (viewPort.intersects(pageLocation) && pageBufferStore.getImageReference() == null) { - // start future task to paint back pageBufferPadding - if (pageImageCaptureTask == null || pageImageCaptureTask.isDone() || pageImageCaptureTask.isCancelled()) { - pageImageCaptureTask = new FutureTask( - new PageImageCaptureTask(this, pageSize, pageSize, - pageZoom, - pageRotation)); - Library.execute(pageImageCaptureTask); - } - } - } - - public void dispose() { - removeMouseListener(this); - } - - public void mouseClicked(MouseEvent e) { - if (controller != null) { - controller.showPage(pageIndex); - } - } - - public void mousePressed(MouseEvent e) { - - } - - public void mouseReleased(MouseEvent e) { - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void pageInitializedCallback(Page page) { - - } - - public void pageTeardownCallback() { - - } - - public void clearSelectedText() { - - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PermissionsDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PermissionsDialog.java deleted file mode 100644 index 6a0ba1aac1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PermissionsDialog.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.security.Permissions; -import org.icepdf.core.pobjects.security.SecurityManager; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.text.MessageFormat; -import java.util.ResourceBundle; - -/** - * This class is a reference implementation for displaying a PDF document's - * associated security permissions. - * - * @since 1.1 - */ -@SuppressWarnings("serial") -public class PermissionsDialog extends EscapeJDialog { - - // layouts constraint - private GridBagConstraints constraints; - - /** - * Creates the permissions dialog. - */ - public PermissionsDialog(JFrame frame, Document document, - ResourceBundle messageBundle) { - super(frame, true); - setTitle(messageBundle.getString("viewer.dialog.documentPermissions.title")); - - // get common values for permissions values - String none = messageBundle.getString("viewer.dialog.documentPermissions.none"); - String no = messageBundle.getString("viewer.dialog.documentPermissions.no"); - String yes = messageBundle.getString("viewer.dialog.documentPermissions.yes"); - String fullyAllowed = messageBundle.getString("viewer.dialog.documentPermissions.fullyAllowed"); - String notAllowed = messageBundle.getString("viewer.dialog.documentPermissions.notAllowed"); - String allowed = messageBundle.getString("viewer.dialog.documentPermissions.allowed"); - String standardSecurity = messageBundle.getString("viewer.dialog.documentPermissions.standardSecurity"); - String lowQuality = messageBundle.getString("viewer.dialog.documentPermissions.partial"); - String securityLevel = messageBundle.getString("viewer.dialog.documentPermissions.securityLevel"); - - - // Do some work on Permissions to get display values - String securityMethod = none; - String userPassword = no; - String ownerPassword = no; - String printing = fullyAllowed; - String changing = allowed; - String extraction = allowed; - String authoring = allowed; - String forms = allowed; - String accessibility = allowed; - String assembly = allowed; - String level = none; - - // get permission values if available - - SecurityManager securityManager = document.getSecurityManager(); - if (securityManager != null) { - Permissions permissions = securityManager.getPermissions(); - if (permissions != null) { - // currenly only adobe standard security supported - securityMethod = standardSecurity; - - // Get user and owner passwords - if (!securityManager.getSecurityHandler().isUserAuthorized("")) { - userPassword = yes; - } - if (!securityManager.getSecurityHandler().isOwnerAuthorized("")) { - ownerPassword = yes; - } - if (!permissions.getPermissions(Permissions.PRINT_DOCUMENT)) { - if (!permissions.getPermissions(Permissions.PRINT_DOCUMENT_QUALITY)) { - printing = lowQuality; - } else { - printing = notAllowed; - } - } - if (!permissions.getPermissions(Permissions.MODIFY_DOCUMENT)) { - changing = notAllowed; - } - if (!permissions.getPermissions(Permissions.CONTENT_EXTRACTION)) { - extraction = notAllowed; - } - if (!permissions.getPermissions(Permissions.AUTHORING_FORM_FIELDS)) { - authoring = notAllowed; - } - if (!permissions.getPermissions(Permissions.FORM_FIELD_FILL_SIGNING)) { - forms = notAllowed; - } - if (!permissions.getPermissions(Permissions.CONTENT_ACCESSABILITY)) { - accessibility = notAllowed; - } - if (!permissions.getPermissions(Permissions.DOCUMENT_ASSEMBLY)) { - assembly = notAllowed; - } - - // Figure level of encryption - int length = securityManager.getEncryptionDictionary().getKeyLength(); - Object[] messageArguments = new Object[]{ - String.valueOf(length), - String.valueOf(securityManager.getEncryptionDictionary().getVersion()), - String.valueOf(securityManager.getEncryptionDictionary().getRevisionNumber()) - }; - MessageFormat formatter = new MessageFormat(securityLevel); - level = formatter.format(messageArguments); - - } - } - - // Create GUI elements - final JButton okButton = new JButton(messageBundle.getString("viewer.button.ok.label")); - okButton.setMnemonic(messageBundle.getString("viewer.button.ok.mnemonic").charAt(0)); - okButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - if (e.getSource() == okButton) { - setVisible(false); - dispose(); - } - - } - }); - - /** - * Place GUI elements on dialog - */ - - JPanel permissionsPanel = new JPanel(); - - permissionsPanel.setAlignmentY(JPanel.TOP_ALIGNMENT); - GridBagLayout layout = new GridBagLayout(); - permissionsPanel.setLayout(layout); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.EAST; - constraints.insets = new Insets(5, 5, 5, 5); - - // add labels - addGB(permissionsPanel, new JLabel("Security Method:"), 0, 0, 1, 1); - addGB(permissionsPanel, new JLabel("User Password:"), 0, 1, 1, 1); - addGB(permissionsPanel, new JLabel("Owner Password:"), 0, 2, 1, 1); - addGB(permissionsPanel, new JLabel("Printing:"), 0, 3, 1, 1); - addGB(permissionsPanel, new JLabel("Changing the Document:"), 0, 4, 1, 1); - addGB(permissionsPanel, new JLabel("Content Copying or Extraction:"), 0, 5, 1, 1); - addGB(permissionsPanel, new JLabel("Authoring Comments and Form Fields:"), 0, 6, 1, 1); - addGB(permissionsPanel, new JLabel("Form Field Fill-in or Signing:"), 0, 7, 1, 1); - addGB(permissionsPanel, new JLabel("Content Accessibility Enabled:"), 0, 8, 1, 1); - addGB(permissionsPanel, new JLabel("Document Assembly:"), 0, 9, 1, 1); - addGB(permissionsPanel, new JLabel("Encryption Level:"), 0, 10, 1, 1); - constraints.insets = new Insets(15, 5, 5, 5); - constraints.anchor = GridBagConstraints.CENTER; - addGB(permissionsPanel, okButton, 0, 11, 2, 1); - - // add values - constraints.insets = new Insets(5, 5, 5, 5); - constraints.anchor = GridBagConstraints.WEST; - addGB(permissionsPanel, new JLabel(securityMethod), 1, 0, 1, 1); - addGB(permissionsPanel, new JLabel(userPassword), 1, 1, 1, 1); - addGB(permissionsPanel, new JLabel(ownerPassword), 1, 2, 1, 1); - addGB(permissionsPanel, new JLabel(printing), 1, 3, 1, 1); - addGB(permissionsPanel, new JLabel(changing), 1, 4, 1, 1); - addGB(permissionsPanel, new JLabel(extraction), 1, 5, 1, 1); - addGB(permissionsPanel, new JLabel(authoring), 1, 6, 1, 1); - addGB(permissionsPanel, new JLabel(forms), 1, 7, 1, 1); - addGB(permissionsPanel, new JLabel(accessibility), 1, 8, 1, 1); - addGB(permissionsPanel, new JLabel(assembly), 1, 9, 1, 1); - addGB(permissionsPanel, new JLabel(level), 1, 10, 1, 1); - - this.getContentPane().add(permissionsPanel); - - pack(); - setLocationRelativeTo(frame); - } - - /** - * Gridbag constructor helper - * - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan - * @param colSpan - */ - private void addGB(JPanel layout, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - layout.add(component, constraints); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PrintHelper.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PrintHelper.java deleted file mode 100644 index f52343ed94..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PrintHelper.java +++ /dev/null @@ -1,613 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.pobjects.PDimension; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.PageTree; -import org.icepdf.core.util.GraphicsRenderingHints; - -import javax.print.*; -import javax.print.attribute.HashDocAttributeSet; -import javax.print.attribute.HashPrintRequestAttributeSet; -import javax.print.attribute.standard.*; -import javax.swing.*; -import java.awt.*; -import java.awt.print.PageFormat; -import java.awt.print.Printable; -import java.awt.print.PrinterJob; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      The PrintHelper class is utility class to aid developers in - * printing PDF document content. The PrintHelper takes advantage of the - * Pageable and Printable interfaces availabe in Java 2.

      - * - * @since 2.0 - */ -public class PrintHelper implements Printable { - - private static final Logger logger = - Logger.getLogger(PrintHelper.class.toString()); - - private PageTree pageTree; - private Container container; - private float userRotation; - private boolean printFitToMargin; - private int printingCurrentPage; - private int totalPagesToPrint; - private boolean paintAnnotation = true; - private boolean paintSearchHighlight = true; - - private static PrintService[] services; - private PrintService printService; - private HashDocAttributeSet docAttributeSet; - private HashPrintRequestAttributeSet printRequestAttributeSet; - - /** - * Creates a new PrintHelper instance defaulting the - * paper size to Letter and the print quality to Draft. - * - * @param container parent container used to center print dialogs. - * @param pageTree document page tree. - */ - public PrintHelper(Container container, PageTree pageTree, int rotation) { - this(container, pageTree, rotation, MediaSizeName.NA_LETTER, PrintQuality.DRAFT); - } - - /** - * Creates a new PrintHelper instance using the specified - * media sized and print quality. - * - * @param container parent container uses to center print dialog. - * @param pageTree document page tree. - * @param rotation rotation at witch to paint document. - * @param paperSizeName MediaSizeName constant of paper size to print to. - * @param printQuality quality of the print job, draft, quality etc. - */ - public PrintHelper(Container container, PageTree pageTree, - final float rotation, - final MediaSizeName paperSizeName, - final PrintQuality printQuality) { - this.container = container; - this.pageTree = pageTree; - this.userRotation = rotation; - - // find available printers - services = lookForPrintServices(); - - // default printing properties. - // Print and document attributes sets. - printRequestAttributeSet = - new HashPrintRequestAttributeSet(); - docAttributeSet = new HashDocAttributeSet(); - - // assign print quality. - printRequestAttributeSet.add(printQuality); - - // change paper - printRequestAttributeSet.add(paperSizeName); - docAttributeSet.add(paperSizeName); - - // setting margins to full paper size as PDF have their own margins - MediaSize mediaSize = - MediaSize.getMediaSizeForName(paperSizeName); - float[] size = mediaSize.getSize(MediaSize.INCH); - printRequestAttributeSet - .add(new MediaPrintableArea(0, 0, size[0], size[1], - MediaPrintableArea.INCH)); - docAttributeSet.add(new MediaPrintableArea(0, 0, size[0], size[1], - MediaPrintableArea.INCH)); - - // default setup, all pages, shrink to fit and no dialog. - setupPrintService(0, this.pageTree.getNumberOfPages(), 1, true, false); - - // display paper size. - if (logger.isLoggable(Level.FINE)) { - logger.fine("Paper Size: " + paperSizeName.getName() + - " " + size[0] + " x " + size[1]); - } - } - - /** - * Creates a new PrintHelper instance using the specified - * doc and print attribute sets. This constructor offers the most flexibility - * as it allows the attributes sets to be pre configured. This method - * should only be used by advanced users. - * - * @param container parent container uses to center print dialog. - * @param pageTree document page tree. - * @param userRotation rotation of view - * @param docAttributeSet MediaSizeName constant of paper size to print to. - * @param printRequestAttributeSet quality of the print job, draft, quality etc. - */ - public PrintHelper(Container container, PageTree pageTree, - float userRotation, - HashDocAttributeSet docAttributeSet, - HashPrintRequestAttributeSet printRequestAttributeSet) { - this.container = container; - this.pageTree = pageTree; - this.userRotation = userRotation; - // blindly assign doc and print attribute sets. - this.docAttributeSet = docAttributeSet; - this.printRequestAttributeSet = printRequestAttributeSet; - // find available printers - services = lookForPrintServices(); - // default setup, all pages, shrink to fit and no dialog. - setupPrintService(0, this.pageTree.getNumberOfPages(), 1, true, false); - } - - /** - * Configures the PrinterJob instance with the specified parameters. - * - * @param startPage start of page range, zero-based index. - * @param endPage end of page range, one-based index. - * @param copies number of copies of pages in print range. - * @param shrinkToPrintableArea true, to enable shrink to fit printable area; - * false, otherwise. - * @param showPrintDialog true, to display a print setup dialog when this method - * is initiated; false, otherwise. This dialog will be shown after the - * page dialog if it is visible. - * @return true if print setup should continue, false if printing was cancelled - * by user interaction with optional print dialog. - */ - public boolean setupPrintService(int startPage, - int endPage, - int copies, - boolean shrinkToPrintableArea, - boolean showPrintDialog) { - // make sure our printable doc knows how many pages to print - // Has to be set before printerJob.printDialog(), so it can show to - // the user which pages it can print - printFitToMargin = shrinkToPrintableArea; - - // set the number of pages - printRequestAttributeSet.add(new PageRanges(startPage + 1, endPage + 1)); - // setup number of - printRequestAttributeSet.add(new Copies(copies)); - - // show the print dialog, return false if the user cancels/closes the - // dialog. - if (showPrintDialog) { - printService = getSetupDialog(); - return printService != null; - } else {// no dialog and thus printing will continue. - return true; - } - } - - /** - * Configures the PrinterJob instance with the specified parameters. - * - * @param printService print service to print document to. - * @param startPage start of page range, zero-based index. - * @param endPage end of page range, one-based index. - * @param copies number of copies of pages in print range. - * @param shrinkToPrintableArea true, to enable shrink to fit printable area; - * false, otherwise. - */ - public void setupPrintService(PrintService printService, - int startPage, - int endPage, - int copies, - boolean shrinkToPrintableArea) { - - // make sure our printable doc knows how many pages to print - // Has to be set before printerJob.printDialog(), so it can show to - // the user which pages it can print - printFitToMargin = shrinkToPrintableArea; - - // set the number of pages - printRequestAttributeSet.add(new PageRanges(startPage + 1, endPage + 1)); - // setup number of - printRequestAttributeSet.add(new Copies(copies)); - - this.printService = printService; - } - - /** - * Configures the PrinterJob instance with the specified parameters. this - * method should only be used by advanced users. - * - * @param printService print service to print document to. - * @param printRequestAttributeSet print jobt attribute set. - * @param shrinkToPrintableArea true, to enable shrink to fit printable area; - * false, otherwise. - */ - public void setupPrintService(PrintService printService, - HashPrintRequestAttributeSet printRequestAttributeSet, - boolean shrinkToPrintableArea) { - printFitToMargin = shrinkToPrintableArea; - this.printRequestAttributeSet = printRequestAttributeSet; - this.printService = printService; - } - - /** - * Utility for showing print dialog for the current printService. If no - * print service is assigned the first print service is used to create - * the print dialog. - */ - public void showPrintSetupDialog() { - PrinterJob pj = PrinterJob.getPrinterJob(); - if (printService == null && services != null && - services.length > 0 && services[0] != null) { - printService = services[0]; - } - try { - pj.setPrintService(printService); - // Step 2: Pass the settings to a page dialog and print dialog. - pj.pageDialog(printRequestAttributeSet); - } catch (Throwable e) { - logger.log(Level.FINE, "Error creating page setup dialog.", e); - } - } - - /** - * Gets the page number of the page currently being spooled by the Printable - * interface. - * - * @return current page being spooled by printer. - */ - public int getCurrentPage() { - return printingCurrentPage; - } - - /** - * Number of total pages being printed. - * - * @return total pages being printed. - */ - public int getNumberOfPages() { - return totalPagesToPrint; - } - - /** - * Gets the fit to margin property. If enabled the page is scaled to fit - * the paper size maxing out on the smallest paper dimension. - * - * @return true if fit to margin is enabled. - */ - public boolean isPrintFitToMargin() { - return printFitToMargin; - } - - /** - * Users rotation specified for the print job. - * - * @return float value representing rotation, 0 is 0 degrees. - */ - public float getUserRotation() { - return userRotation; - } - - /** - * Gets the document attributes currently in use. - * - * @return current document attributes. - */ - public HashDocAttributeSet getDocAttributeSet() { - return docAttributeSet; - } - - /** - * Gets the print request attribute sets. - * - * @return attribute set - */ - public HashPrintRequestAttributeSet getPrintRequestAttributeSet() { - return printRequestAttributeSet; - } - - /** - * Gets the currently assigned print service. - * - * @return current print service, can be null. - */ - public PrintService getPrintService() { - return printService; - } - - /** - * Prints the page at the specified index into the specified - * java.awt.Graphics context in the specified format. - * - * @param printGraphics paper graphics context. - * @param pageFormat print attributes translated from PrintService - * @param pageIndex page to print, zero based. - * @return A status code of Printable.NO_SUCH_PAGE or Printable.PAGE_EXISTS - */ - public int print(Graphics printGraphics, PageFormat pageFormat, int pageIndex) { - - // update the pageCount - if (printingCurrentPage != pageIndex) { - printingCurrentPage = pageIndex + 1; - } - - // Throws NO_SUCH_PAGE to printable interface, out of page range - if (pageIndex < 0 || pageIndex >= pageTree.getNumberOfPages()) { - return Printable.NO_SUCH_PAGE; - } - try { - - // Initiate the Page to print, not adding to the pageTree cache purposely, - // after we finish using it we'll dispose it. - Page currentPage = pageTree.getPage(pageIndex); - currentPage.init(); - PDimension pageDim = currentPage.getSize(userRotation); - - // Grab default page width and height - float pageWidth = (float) pageDim.getWidth(); - float pageHeight = (float) pageDim.getHeight(); - - // Default zoom factor - float zoomFactor = 1.0f; - - Point imageablePrintLocation = new Point(); - - // detect if page is being drawn in landscape, if so then we should - // should be rotating the page so that it prints correctly - float rotation = userRotation; - boolean isDefaultRotation = true; - if ((pageWidth > pageHeight && - pageFormat.getOrientation() == PageFormat.PORTRAIT) - // auto rotation for landscape. -// (pageHeight > pageFormat.getImageableWidth() && -// pageFormat.getOrientation() == PageFormat.LANDSCAPE ) - ) { - // rotate clockwise 90 degrees - isDefaultRotation = false; - rotation -= 90; - } - - // if true, we want to shrink out page to the new area. - if (printFitToMargin) { - - // Get location of imageable area from PageFormat object - Dimension imageablePrintSize; - // correct scale to fit calculation for a possible automatic - // rotation. - if (isDefaultRotation) { - imageablePrintSize = new Dimension( - (int) pageFormat.getImageableWidth(), - (int) pageFormat.getImageableHeight()); - } else { - imageablePrintSize = new Dimension( - (int) pageFormat.getImageableHeight(), - (int) pageFormat.getImageableWidth()); - - } - float zw = imageablePrintSize.width / pageWidth; - float zh = imageablePrintSize.height / pageHeight; - zoomFactor = Math.min(zw, zh); - imageablePrintLocation.x = (int) pageFormat.getImageableX(); - imageablePrintLocation.y = (int) pageFormat.getImageableY(); - } - // apply imageablePrintLocation, normally (0,0) - printGraphics.translate(imageablePrintLocation.x, - imageablePrintLocation.y); - - // Paint the page content - currentPage.paint(printGraphics, - GraphicsRenderingHints.PRINT, - Page.BOUNDARY_CROPBOX, - rotation, zoomFactor, paintAnnotation, paintSearchHighlight); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.log(Level.SEVERE, "Printing: Page initialization and painting was interrupted", e); - } - - // Paint content to page buffer to reduce spool size but quality will suffer. -// Image image = viewController.getDocument().getPageImage(pageIndex, -// GraphicsRenderingHints.PRINT, -// Page.BOUNDARY_CROPBOX, -// rotation, zoomFactor); -// printGraphics.drawImage(image,0,0,null); -// image.flush(); - - return Printable.PAGE_EXISTS; - } - - /** - * Print a range of pages from the document as specified by #setupPrintService. - * - * @throws PrintException if a default printer could not be found or some - * other printing related error. - */ - public void print() throws PrintException { - - // make sure we have a service, if not we assign the default printer - if (printService == null && services != null && - services.length > 0 && services[0] != null) { - printService = services[0]; - } - - if (printService != null) { - - // calculate total pages being printed - calculateTotalPagesToPrint(); - - printService.createPrintJob().print( - new SimpleDoc(this, - DocFlavor.SERVICE_FORMATTED.PRINTABLE, - null), - printRequestAttributeSet); - } else { - logger.fine("No print could be found to print to."); - } - - } - - public CancelablePrintJob cancelablePrint() throws PrintException { - - // make sure we have a service, if not we assign the default printer - if (printService == null && services != null && - services.length > 0 && services[0] != null) { - printService = services[0]; - } - - if (printService != null) { - - // calculate total pages being printed - calculateTotalPagesToPrint(); - - DocPrintJob printerJob = printService.createPrintJob(); - printerJob.print( - new SimpleDoc(this, - DocFlavor.SERVICE_FORMATTED.PRINTABLE, - null), - printRequestAttributeSet); - - return (CancelablePrintJob) printerJob; - } else { - return null; - } - } - - public void print(PrintJobWatcher printJobWatcher) throws PrintException { - - // make sure we have a service, if not we assign the default printer - if (printService == null && services != null && - services.length > 0 && services[0] != null) { - printService = services[0]; - } - - if (printService != null) { - - // calculate total pages being printed - calculateTotalPagesToPrint(); - - DocPrintJob printerJob = printService.createPrintJob(); - printJobWatcher.setPrintJob(printerJob); - - printerJob.print( - new SimpleDoc(this, - DocFlavor.SERVICE_FORMATTED.PRINTABLE, - null), - printRequestAttributeSet); - - printJobWatcher.waitForDone(); - } else { - logger.fine("No print could be found to print to."); - } - - } - - /** - * Utility for creating a print setup dialog. - * - * @return print service selected by the user, or null if the user - * cancelled the dialog. - */ - private PrintService getSetupDialog() { - final int offset = 50; - // find graphic configuration for the window the viewer is in. - Window window = SwingUtilities.getWindowAncestor( - container); - GraphicsConfiguration graphicsConfiguration = - window == null ? null : window.getGraphicsConfiguration(); - // try and trim the services list. -// services = new PrintService[]{services[0]}; - - return ServiceUI.printDialog(graphicsConfiguration, - container.getX() + offset, - container.getY() + offset, - services, services[0], - DocFlavor.SERVICE_FORMATTED.PRINTABLE, - printRequestAttributeSet); - } - - private void calculateTotalPagesToPrint() { - // iterate over page ranges to find out how many pages are to - // be printed - PageRanges pageRanges = (PageRanges) - printRequestAttributeSet.get(PageRanges.class); - totalPagesToPrint = 0; - // we need to loop over the multiple ranges as commas can be used - // to specify more then one range. Make sure the specified pages - // fall with in the range allowed by the document. - int start, end; - for (int[] ranges : pageRanges.getMembers()) { - start = ranges[0]; - end = ranges[1]; - if (start < 1) { - start = 1; - } - if (end > pageTree.getNumberOfPages()) { - end = pageTree.getNumberOfPages(); - } - totalPagesToPrint += end - start + 1; - } - } - - private PrintService[] lookForPrintServices() { - PrintService[] services = PrintServiceLookup.lookupPrintServices( - DocFlavor.SERVICE_FORMATTED.PRINTABLE, null); - // check for a default service and make sure it is at index 0. the lookupPrintServices does not - // aways put the default printer first in the array. - PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService(); - if (defaultService != null && services.length > 1) { - PrintService printService; - for (int i = 1, max = services.length; i < max; i++) { - printService = services[i]; - if (printService.equals(defaultService)) { - // found the default printer, now swap it with the first index. - PrintService tmp = services[0]; - services[0] = defaultService; - services[i] = tmp; - break; - } - } - } - return services; - } - - /** - * Are page annotations going to be printed? - * - * @return true if annotation are to be printed, false otherwise - */ - public boolean isPaintAnnotation() { - return paintAnnotation; - } - - /** - * Manually enable or disable the printing of annotation for a print job - * - * @param paintAnnotation true to paint annotation; otherwise false. - */ - public void setPaintAnnotation(boolean paintAnnotation) { - this.paintAnnotation = paintAnnotation; - } - - /** - * Are page search highlight's going to be printed? - * - * @return true if highlights are to be printed, false otherwise - */ - public boolean isPaintSearchHighlight() { - return paintSearchHighlight; - } - - /** - * Manually enable or disable the printing of search highlights for a print job - * - * @param paintSearchHighlight true to paint search highlights; otherwise false. - */ - public void setPaintSearchHighlight(boolean paintSearchHighlight) { - this.paintSearchHighlight = paintSearchHighlight; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PrintJobWatcher.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PrintJobWatcher.java deleted file mode 100644 index 79e5dcf58a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PrintJobWatcher.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import javax.print.DocPrintJob; -import javax.print.event.PrintJobAdapter; -import javax.print.event.PrintJobEvent; - -/** - * Simple Print Job Watcher. - * - * @since 3.0 - */ -public class PrintJobWatcher { - // true if it is safe to close the print job's input stream - private boolean done = false; - - public PrintJobWatcher() { - - } - - public PrintJobWatcher(DocPrintJob job) { - setPrintJob(job); - } - - public void setPrintJob(DocPrintJob job) { - // Add a listener to the print job - job.addPrintJobListener( - new PrintJobAdapter() { - public void printJobCanceled(PrintJobEvent printJobEvent) { - allDone(); - } - - public void printJobCompleted(PrintJobEvent printJobEvent) { - allDone(); - } - - public void printJobFailed(PrintJobEvent printJobEvent) { - allDone(); - } - - public void printJobNoMoreEvents(PrintJobEvent printJobEvent) { - allDone(); - } - - void allDone() { - synchronized (PrintJobWatcher.this) { - done = true; - PrintJobWatcher.this.notify(); - } - } - }); - } - - public synchronized void waitForDone() { - try { - while (!done) { - wait(); - } - } catch (InterruptedException e) { - } - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PrinterTask.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PrinterTask.java deleted file mode 100644 index 143f9bd4ca..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/PrinterTask.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import javax.print.CancelablePrintJob; -import javax.print.PrintException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      The PrinterTask class is responsible for starting a - * PrinterJob's print function in a new thread. This class assumes that the - * PrinterJob is pre-configured and ready for its print() method to be called.

      - * - * @since 2.0 - */ -public class PrinterTask implements Runnable { - - private static final Logger logger = - Logger.getLogger(PrinterTask.class.toString()); - - // PrinterJob to print - private PrintHelper printHelper; - private CancelablePrintJob cancelablePrintJob; - - /** - * Create a new instance of a PrinterTask. - * - * @param printHelper print helper - */ - public PrinterTask(PrintHelper printHelper) { - this.printHelper = printHelper; - } - - /** - * Threads Runnable method. - */ - public void run() { - try { - if (printHelper != null) { - cancelablePrintJob = printHelper.cancelablePrint(); - } - } catch (PrintException ex) { - logger.log(Level.FINE, "Error during printing.", ex); - } - } - - /** - * Cancel the PrinterTask by calling the PrinterJob's cancel() method. - */ - public void cancel() { - try { - if (cancelablePrintJob != null) { - cancelablePrintJob.cancel(); - } - } catch (PrintException ex) { - logger.log(Level.FINE, "Error during printing, " + ex.getMessage()); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/SwingController.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/SwingController.java deleted file mode 100644 index b71d152151..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/SwingController.java +++ /dev/null @@ -1,4801 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.SecurityCallback; -import org.icepdf.core.exceptions.PDFException; -import org.icepdf.core.exceptions.PDFSecurityException; -import org.icepdf.core.io.SizeInputStream; -import org.icepdf.core.pobjects.*; -import org.icepdf.core.pobjects.actions.Action; -import org.icepdf.core.pobjects.actions.GoToAction; -import org.icepdf.core.pobjects.actions.URIAction; -import org.icepdf.core.pobjects.fonts.FontFactory; -import org.icepdf.core.pobjects.security.Permissions; -import org.icepdf.core.search.DocumentSearchController; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.core.util.Utils; -import org.icepdf.ri.common.fonts.FontDialog; -import org.icepdf.ri.common.search.DocumentSearchControllerImpl; -import org.icepdf.ri.common.utility.annotation.AnnotationPanel; -import org.icepdf.ri.common.utility.attachment.AttachmentPanel; -import org.icepdf.ri.common.utility.layers.LayersPanel; -import org.icepdf.ri.common.utility.outline.OutlineItemTreeNode; -import org.icepdf.ri.common.utility.search.SearchPanel; -import org.icepdf.ri.common.utility.signatures.SignaturesPanel; -import org.icepdf.ri.common.utility.thumbs.ThumbnailsPanel; -import org.icepdf.ri.common.views.*; -import org.icepdf.ri.common.views.annotations.AnnotationState; -import org.icepdf.ri.util.*; - -import javax.print.attribute.PrintRequestAttributeSet; -import javax.print.attribute.standard.Media; -import javax.print.attribute.standard.MediaSize; -import javax.print.attribute.standard.MediaSizeName; -import javax.print.attribute.standard.PrintQuality; -import javax.swing.*; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; -import java.awt.*; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.StringSelection; -import java.awt.datatransfer.Transferable; -import java.awt.datatransfer.UnsupportedFlavorException; -import java.awt.dnd.*; -import java.awt.event.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.text.MessageFormat; -import java.text.NumberFormat; -import java.util.HashMap; -import java.util.List; -import java.util.Properties; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * SwingController is the meat of a PDF viewing application. It is the Controller - * aspect of the Model-View-Controller (MVC) framework.
      - *
      - * SwingController acts as a bridge between a Swing user interface, as built by - * SwingViewerBuilder; the Document class, which is the root accessor to the PDF content; - * and the ViewerModel, which maintains the state of the user's perspective of said Document. - * - * @author Mark Collette - * @see SwingViewBuilder - * @see org.icepdf.core.pobjects.Document - * @see ViewModel - * @since 2.0 - */ -public class SwingController - implements Controller, ActionListener, FocusListener, ItemListener, - TreeSelectionListener, WindowListener, DropTargetListener, - KeyListener, PropertyChangeListener { - - protected static final Logger logger = - Logger.getLogger(SwingController.class.toString()); - - public static final int CURSOR_OPEN_HAND = 1; - public static final int CURSOR_CLOSE_HAND = 2; - public static final int CURSOR_ZOOM_IN = 3; - public static final int CURSOR_ZOOM_OUT = 4; - public static final int CURSOR_WAIT = 6; - public static final int CURSOR_SELECT = 7; - public static final int CURSOR_DEFAULT = 8; - - protected static final int MAX_SELECT_ALL_PAGE_COUNT = 250; - - private JMenuItem openFileMenuItem; - private JMenuItem openURLMenuItem; - private JMenuItem closeMenuItem; - private JMenuItem saveAsFileMenuItem; - private JMenuItem exportTextMenuItem; - private JMenuItem exportSVGMenuItem; - private JMenuItem permissionsMenuItem; - private JMenuItem informationMenuItem; - private JMenuItem fontInformationMenuItem; - private JMenuItem printSetupMenuItem; - private JMenuItem printMenuItem; - private JMenuItem exitMenuItem; - private JMenuItem undoMenuItem; - private JMenuItem redoMenuItem; - private JMenuItem copyMenuItem; - private JMenuItem deleteMenuItem; - private JMenuItem selectAllMenuItem; - private JMenuItem deselectAllMenuItem; - private JMenuItem fitActualSizeMenuItem; - private JMenuItem fitPageMenuItem; - private JMenuItem fitWidthMenuItem; - private JMenuItem zoomInMenuItem; - private JMenuItem zoomOutMenuItem; - private JMenuItem rotateLeftMenuItem; - private JMenuItem rotateRightMenuItem; - private JMenuItem showHideToolBarMenuItem; - private JMenuItem showHideUtilityPaneMenuItem; - private JMenuItem firstPageMenuItem; - private JMenuItem previousPageMenuItem; - private JMenuItem nextPageMenuItem; - private JMenuItem lastPageMenuItem; - private JMenuItem searchMenuItem; - private JMenuItem goToPageMenuItem; - private JMenuItem minimiseAllMenuItem; - private JMenuItem bringAllToFrontMenuItem; - private List windowListMenuItems; - private JMenuItem aboutMenuItem; - private JButton openFileButton; - private JButton saveAsFileButton; - private JButton printButton; - private JButton searchButton; - private JToggleButton showHideUtilityPaneButton; - private JButton firstPageButton; - private JButton previousPageButton; - private JButton nextPageButton; - private JButton lastPageButton; - private JTextField currentPageNumberTextField; - private JLabel numberOfPagesLabel; - private JButton zoomInButton; - private JButton zoomOutButton; - private JComboBox zoomComboBox; - private JToggleButton fitActualSizeButton; - private JToggleButton fitHeightButton; - private JToggleButton fitWidthButton; - private JToggleButton fontEngineButton; - private JToggleButton facingPageViewContinuousButton; - private JToggleButton singlePageViewContinuousButton; - private JToggleButton facingPageViewNonContinuousButton; - private JToggleButton singlePageViewNonContinuousButton; - private JButton rotateLeftButton; - private JButton rotateRightButton; - private JToggleButton panToolButton; - private JToggleButton textSelectToolButton; - private JToggleButton zoomInToolButton; - private JToggleButton zoomDynamicToolButton; - private JToggleButton selectToolButton; - private JToggleButton highlightAnnotationToolButton; - private JToggleButton textAnnotationToolButton; - private JToggleButton formHighlightButton; - private JToggleButton linkAnnotationToolButton; - private JToggleButton highlightAnnotationUtilityToolButton; - private JToggleButton strikeOutAnnotationToolButton; - private JToggleButton underlineAnnotationToolButton; - private JToggleButton lineAnnotationToolButton; - private JToggleButton lineArrowAnnotationToolButton; - private JToggleButton squareAnnotationToolButton; - private JToggleButton circleAnnotationToolButton; - private JToggleButton inkAnnotationToolButton; - private JToggleButton freeTextAnnotationToolButton; - private JToggleButton textAnnotationUtilityToolButton; - private JToolBar completeToolBar; - // Printing in background thread monitors - private ProgressMonitor printProgressMonitor; - private Timer printActivityMonitor; - private JTree outlinesTree; - private JScrollPane outlinesScrollPane; - private SearchPanel searchPanel; - private AttachmentPanel attachmentPanel; - private ThumbnailsPanel thumbnailsPanel; - private LayersPanel layersPanel; - private SignaturesPanel signaturesPanel; - private AnnotationPanel annotationPanel; - private JTabbedPane utilityTabbedPane; - private JSplitPane utilityAndDocumentSplitPane; - private int utilityAndDocumentSplitPaneLastDividerLocation; - private JLabel statusLabel; - private JFrame viewer; - protected WindowManagementCallback windowManagementCallback; - // simple model for swing controller, mainly printer and file loading state. - protected ViewModel viewModel; - // subcontroller for document view or document page views. - protected DocumentViewControllerImpl documentViewController; - - // subcontroller for document text searching. - protected DocumentSearchController documentSearchController; - - // todo subcontroller for document annotations creation. - - - protected Document document; - protected boolean disposed; - - // internationalization messages, loads message for default JVM locale. - protected static ResourceBundle messageBundle = null; - - protected PropertiesManager propertiesManager; - - /** - * Create a SwingController object, and its associated ViewerModel - * - * @see ViewModel - */ - public SwingController() { - this(null); - } - - public SwingController(ResourceBundle messageBundle) { - viewModel = new ViewModel(); - // page view controller - documentViewController = new DocumentViewControllerImpl(this); - // document search controller. - documentSearchController = new DocumentSearchControllerImpl(this); - - // register Property change listeners, for zoom, rotation, current page changes - documentViewController.addPropertyChangeListener(this); - - // load the resource bundle using the default local - if (messageBundle != null) { - this.messageBundle = messageBundle; - } else { - this.messageBundle = ResourceBundle.getBundle( - PropertiesManager.DEFAULT_MESSAGE_BUNDLE); - } - } - - /** - * Sets a custom document view controller. Previously constructed documentView controllers are unregistered - * from the propertyChangeListener, the provided controller will be registered with the propertyChangeListener. - * - * @param documentViewController new document controller. - */ - public void setDocumentViewController(DocumentViewControllerImpl documentViewController) { - if (this.documentViewController != null) { - this.documentViewController.removePropertyChangeListener(this); - } - this.documentViewController = documentViewController; - // register Property change listeners, for zoom, rotation, current page changes - documentViewController.addPropertyChangeListener(this); - } - - /** - * Gets controller responsible for the page multiple page views. - * - * @return page view controller. - */ - public DocumentViewController getDocumentViewController() { - return documentViewController; - } - - /** - * Gets controller responsible for the document text searches. - * - * @return page view controller. - */ - public DocumentSearchController getDocumentSearchController() { - return documentSearchController; - } - - /** - * Gets the message bundle used by this class. Message bundle resources - * are loaded via the JVM default locale. - * - * @return message bundle used by this class. - */ - public ResourceBundle getMessageBundle() { - return messageBundle; - } - - /** - * The WindowManagementCallback is used for creating new Document windows, - * and quitting the application - * - * @param wm The new WindowManagementCallback - * @see #getWindowManagementCallback - */ - public void setWindowManagementCallback(WindowManagementCallback wm) { - windowManagementCallback = wm; - } - - /** - * The WindowManagementCallback is used for creating new Document windows, - * and quitting the application - * - * @return The current WindowManagementCallback - * @see #setWindowManagementCallback - */ - public WindowManagementCallback getWindowManagementCallback() { - return windowManagementCallback; - } - - /** - * Called by SwingViewerBuilder, so that SwingController has access to all properties - */ - public void setPropertiesManager(PropertiesManager propertiesManager) { - this.propertiesManager = propertiesManager; - } - - /** - * Gets an instance of the PropertiesManager so that other builders can use the properties manager. - */ - public PropertiesManager getPropertiesManager() { - return propertiesManager; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setOpenFileMenuItem(JMenuItem mi) { - openFileMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setOpenURLMenuItem(JMenuItem mi) { - openURLMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setCloseMenuItem(JMenuItem mi) { - closeMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setSaveAsFileMenuItem(JMenuItem mi) { - saveAsFileMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setExportTextMenuItem(JMenuItem mi) { - exportTextMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setExportSVGMenuItem(JMenuItem mi) { - exportSVGMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setPermissionsMenuItem(JMenuItem mi) { - permissionsMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setInformationMenuItem(JMenuItem mi) { - informationMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFontInformationMenuItem(JMenuItem mi) { - fontInformationMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setPrintSetupMenuItem(JMenuItem mi) { - printSetupMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setPrintMenuItem(JMenuItem mi) { - printMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setExitMenuItem(JMenuItem mi) { - exitMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setUndoMenuItem(JMenuItem mi) { - undoMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setReduMenuItem(JMenuItem mi) { - redoMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setCopyMenuItem(JMenuItem mi) { - copyMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setDeleteMenuItem(JMenuItem mi) { - deleteMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setSelectAllMenuItem(JMenuItem mi) { - selectAllMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setDselectAllMenuItem(JMenuItem mi) { - deselectAllMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFitActualSizeMenuItem(JMenuItem mi) { - fitActualSizeMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFitPageMenuItem(JMenuItem mi) { - fitPageMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFitWidthMenuItem(JMenuItem mi) { - fitWidthMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setZoomInMenuItem(JMenuItem mi) { - zoomInMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setZoomOutMenuItem(JMenuItem mi) { - zoomOutMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setRotateLeftMenuItem(JMenuItem mi) { - rotateLeftMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setRotateRightMenuItem(JMenuItem mi) { - rotateRightMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setShowHideToolBarMenuItem(JMenuItem mi) { - showHideToolBarMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setShowHideUtilityPaneMenuItem(JMenuItem mi) { - showHideUtilityPaneMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFirstPageMenuItem(JMenuItem mi) { - firstPageMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setPreviousPageMenuItem(JMenuItem mi) { - previousPageMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setNextPageMenuItem(JMenuItem mi) { - nextPageMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setLastPageMenuItem(JMenuItem mi) { - lastPageMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setSearchMenuItem(JMenuItem mi) { - searchMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setGoToPageMenuItem(JMenuItem mi) { - goToPageMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setMinimiseAllMenuItem(JMenuItem mi) { - minimiseAllMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setBringAllToFrontMenuItem(JMenuItem mi) { - bringAllToFrontMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setWindowListMenuItems(List menuItems) { - windowListMenuItems = menuItems; - int count = (windowListMenuItems != null) ? windowListMenuItems.size() : 0; - for (int i = 0; i < count; i++) { - JMenuItem mi = (JMenuItem) windowListMenuItems.get(i); - mi.addActionListener(this); - } - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setAboutMenuItem(JMenuItem mi) { - aboutMenuItem = mi; - mi.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setOpenFileButton(JButton btn) { - openFileButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setSaveAsFileButton(JButton btn) { - saveAsFileButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setPrintButton(JButton btn) { - printButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setSearchButton(JButton btn) { - searchButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setShowHideUtilityPaneButton(JToggleButton btn) { - showHideUtilityPaneButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFirstPageButton(JButton btn) { - firstPageButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setPreviousPageButton(JButton btn) { - previousPageButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setNextPageButton(JButton btn) { - nextPageButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setLastPageButton(JButton btn) { - lastPageButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setCurrentPageNumberTextField(JTextField textField) { - currentPageNumberTextField = textField; - currentPageNumberTextField.addActionListener(this); - currentPageNumberTextField.addFocusListener(this); - currentPageNumberTextField.addKeyListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setNumberOfPagesLabel(JLabel lbl) { - numberOfPagesLabel = lbl; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setZoomOutButton(JButton btn) { - zoomOutButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setZoomComboBox(JComboBox zcb, float[] zl) { - zoomComboBox = zcb; - documentViewController.setZoomLevels(zl); - zoomComboBox.setSelectedItem(NumberFormat.getPercentInstance().format(1.0)); - zoomComboBox.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setZoomInButton(JButton btn) { - zoomInButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFitActualSizeButton(JToggleButton btn) { - fitActualSizeButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFitHeightButton(JToggleButton btn) { - fitHeightButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewBuilder, so that SwingController can setup event handling - */ - public void setFontEngineButton(JToggleButton btn) { - fontEngineButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFitWidthButton(JToggleButton btn) { - fitWidthButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setRotateLeftButton(JButton btn) { - rotateLeftButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setRotateRightButton(JButton btn) { - rotateRightButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setPanToolButton(JToggleButton btn) { - panToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setZoomInToolButton(JToggleButton btn) { - zoomInToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setTextSelectToolButton(JToggleButton btn) { - textSelectToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setSelectToolButton(JToggleButton btn) { - selectToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setLinkAnnotationToolButton(JToggleButton btn) { - linkAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setHighlightAnnotationToolButton(JToggleButton btn) { - highlightAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setHighlightAnnotationUtilityToolButton(JToggleButton btn) { - highlightAnnotationUtilityToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setStrikeOutAnnotationToolButton(JToggleButton btn) { - strikeOutAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setUnderlineAnnotationToolButton(JToggleButton btn) { - underlineAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setLineAnnotationToolButton(JToggleButton btn) { - lineAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setLineArrowAnnotationToolButton(JToggleButton btn) { - lineArrowAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setSquareAnnotationToolButton(JToggleButton btn) { - squareAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setCircleAnnotationToolButton(JToggleButton btn) { - circleAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setInkAnnotationToolButton(JToggleButton btn) { - inkAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setFreeTextAnnotationToolButton(JToggleButton btn) { - freeTextAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setTextAnnotationToolButton(JToggleButton btn) { - textAnnotationToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - * for the form highlight button. - */ - public void setFormHighlightButton(JToggleButton btn) { - formHighlightButton = btn; - btn.addActionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setTextAnnotationUtilityToolButton(JToggleButton btn) { - textAnnotationUtilityToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setZoomDynamicToolButton(JToggleButton btn) { - zoomDynamicToolButton = btn; - btn.addItemListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setCompleteToolBar(JToolBar toolbar) { - completeToolBar = toolbar; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setOutlineComponents(JTree tree, JScrollPane scroll) { - outlinesTree = tree; - outlinesScrollPane = scroll; - outlinesTree.addTreeSelectionListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setSearchPanel(SearchPanel sp) { - searchPanel = sp; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setAttachmentPanel(AttachmentPanel sp) { - attachmentPanel = sp; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setThumbnailsPanel(ThumbnailsPanel tn) { - thumbnailsPanel = tn; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setLayersPanel(LayersPanel tn) { - layersPanel = tn; - } - - public void setSignaturesPanel(SignaturesPanel tn) { - signaturesPanel = tn; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setAnnotationPanel(AnnotationPanel lp) { - annotationPanel = lp; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setUtilityTabbedPane(JTabbedPane util) { - utilityTabbedPane = util; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setIsEmbeddedComponent(boolean embeddableComponent) { - if (embeddableComponent) { - documentViewController.setViewKeyListener(this); - documentViewController.getViewContainer().addKeyListener(this); - } - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setUtilityAndDocumentSplitPane(JSplitPane splitPane) { - - utilityAndDocumentSplitPane = splitPane; - // default is to hide the tabbed pane on first load. - setUtilityPaneVisible(false); - // add the valueChangeListener. - utilityAndDocumentSplitPane.addPropertyChangeListener(this); - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setStatusLabel(JLabel lbl) { - statusLabel = lbl; - } - - /** - * Called by SwingViewerBuilder, so that SwingController can setup event handling - */ - public void setViewerFrame(JFrame v) { - viewer = v; - viewer.addWindowListener(this); - // add drag and drop listeners - new DropTarget(viewer, // component - DnDConstants.ACTION_COPY_OR_MOVE, // actions - this); // DropTargetListener - reflectStateInComponents(); - } - - /** - * Not all uses of SwingController would result in there existing a Viewer Frame, - * so this may well return null. - */ - public JFrame getViewerFrame() { - return viewer; - } - - /** - * Tests to see if the PDF document is a collection and should be treated as such. - * - * @return true if PDF collection otherwise false. - */ - public boolean isPdfCollection() { - Catalog catalog = document.getCatalog(); - HashMap collection = catalog.getCollection(); - if (collection != null ) { - // one final check as some docs will have meta data but will specify a page mode. - // check to see that at least one of the files is a PDF - if (catalog.getEmbeddedFilesNameTree() != null) { - NameTree embeddedFilesNameTree = catalog.getEmbeddedFilesNameTree(); - java.util.List filePairs = embeddedFilesNameTree.getNamesAndValues(); - boolean found = false; - if (filePairs != null) { - Library library = catalog.getLibrary(); - // check to see if at least one file is a PDF. - for (int i = 0, max = filePairs.size(); i < max; i += 2) { - // get the name and document for - // file name and file specification pairs. - String fileName = Utils.convertStringObject(library, (StringObject) filePairs.get(i)); - if (fileName != null && fileName.toLowerCase().endsWith(".pdf")) { - found = true; - break; - } - } - } - return found; - } - } - return false; - } - - /** - * Utility method to set the state of all the different GUI elements. Mainly - * to enable/disable the GUI elements when a file is opened/closed respectively. - */ - private void reflectStateInComponents() { - boolean opened = document != null; - boolean pdfCollection = opened && isPdfCollection(); - - int nPages = (getPageTree() != null) ? getPageTree().getNumberOfPages() : 0; - - // get security information for printing and text extraction - boolean canPrint = havePermissionToPrint(); - boolean canExtract = havePermissionToExtractContent(); - boolean canModify = havePermissionToModifyDocument(); - - reflectPageChangeInComponents(); - - // menu items. - setEnabled(closeMenuItem, opened); - setEnabled(saveAsFileMenuItem, opened); - setEnabled(exportTextMenuItem, opened && canExtract && !pdfCollection); - // Exporting to SVG creates output as if we printed, - // which is not the same as extracting text - setEnabled(exportSVGMenuItem, opened && canPrint && !pdfCollection); - setEnabled(permissionsMenuItem, opened); - setEnabled(informationMenuItem, opened); - setEnabled(fontInformationMenuItem, opened); - // Printer setup is global to all PDFs, so don't limit it by this one PDF - setEnabled(printSetupMenuItem, opened && canPrint && !pdfCollection); - setEnabled(printMenuItem, opened && canPrint && !pdfCollection); - - // set initial sate for undo/redo edit, afterwards state is set by - // valueChange events depending on tool selection. - setEnabled(undoMenuItem, false); - setEnabled(redoMenuItem, false); - setEnabled(copyMenuItem, false); - setEnabled(deleteMenuItem, false); - - setEnabled(selectAllMenuItem, opened && canExtract && !pdfCollection); - setEnabled(deselectAllMenuItem, false); - - - setEnabled(fitActualSizeMenuItem, opened && !pdfCollection); - setEnabled(fitPageMenuItem, opened && !pdfCollection); - setEnabled(fitWidthMenuItem, opened && !pdfCollection); - - setEnabled(zoomInMenuItem, opened && !pdfCollection); - setEnabled(zoomOutMenuItem, opened && !pdfCollection); - - setEnabled(rotateLeftMenuItem, opened && !pdfCollection); - setEnabled(rotateRightMenuItem, opened && !pdfCollection); - -// setEnabled(facingPageViewContinuousMenuItem , opened ); -// setEnabled(singlePageViewContinuousMenuItem , opened ); -// setEnabled(facingPageViewNonContinuousMenuItem , opened ); -// setEnabled(singlePageViewNonContinuousMenuItem , opened ); - - setEnabled(fitPageMenuItem, opened && !pdfCollection); - setEnabled(fitWidthMenuItem, opened && !pdfCollection); - if (showHideToolBarMenuItem != null) { - boolean vis = (completeToolBar != null) && completeToolBar.isVisible(); - showHideToolBarMenuItem.setText( - vis ? messageBundle.getString("viewer.toolbar.hideToolBar.label") : - messageBundle.getString("viewer.toolbar.showToolBar.label")); - } - setEnabled(showHideToolBarMenuItem, completeToolBar != null); - if (showHideUtilityPaneMenuItem != null) { - boolean vis = isUtilityPaneVisible(); - showHideUtilityPaneMenuItem.setText( - (opened && vis) ? - messageBundle.getString("viewer.toolbar.hideUtilityPane.label") : - messageBundle.getString("viewer.toolbar.showUtilityPane.label")); - } - setEnabled(showHideUtilityPaneMenuItem, opened && utilityTabbedPane != null ); - setEnabled(searchMenuItem, opened && searchPanel != null && !pdfCollection); - setEnabled(goToPageMenuItem, opened && nPages > 1 && !pdfCollection); - - setEnabled(saveAsFileButton, opened); - setEnabled(printButton, opened && canPrint && !pdfCollection); - setEnabled(searchButton, opened && searchPanel != null && !pdfCollection); - setEnabled(showHideUtilityPaneButton, opened && utilityTabbedPane != null ); - setEnabled(currentPageNumberTextField, opened && nPages > 1 && !pdfCollection); - if (numberOfPagesLabel != null) { - - Object[] messageArguments = new Object[]{String.valueOf(nPages)}; - MessageFormat formatter = - new MessageFormat( - messageBundle.getString("viewer.toolbar.pageIndicator")); - String numberOfPages = formatter.format(messageArguments); - - numberOfPagesLabel.setText( - opened ? numberOfPages : ""); - } - setEnabled(zoomInButton, opened && !pdfCollection); - setEnabled(zoomOutButton, opened && !pdfCollection); - setEnabled(zoomComboBox, opened && !pdfCollection); - setEnabled(fitActualSizeButton, opened && !pdfCollection); - setEnabled(fitHeightButton, opened && !pdfCollection); - setEnabled(fitWidthButton, opened && !pdfCollection); - setEnabled(rotateLeftButton, opened && !pdfCollection); - setEnabled(rotateRightButton, opened && !pdfCollection); - setEnabled(panToolButton, opened && !pdfCollection); - setEnabled(zoomInToolButton, opened && !pdfCollection); - setEnabled(zoomDynamicToolButton, opened && !pdfCollection); - setEnabled(textSelectToolButton, opened && canExtract && !pdfCollection); - setEnabled(selectToolButton, opened && canModify && !pdfCollection); - setEnabled(linkAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(highlightAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(highlightAnnotationUtilityToolButton, opened && canModify && !pdfCollection); - setEnabled(strikeOutAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(underlineAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(lineAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(lineArrowAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(squareAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(circleAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(inkAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(freeTextAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(textAnnotationToolButton, opened && canModify && !pdfCollection); - setEnabled(textAnnotationUtilityToolButton, opened && canModify && !pdfCollection); - setEnabled(formHighlightButton, opened && !pdfCollection && hasForms()); - setEnabled(fontEngineButton, opened && !pdfCollection); - setEnabled(facingPageViewContinuousButton, opened && !pdfCollection); - setEnabled(singlePageViewContinuousButton, opened && !pdfCollection); - setEnabled(facingPageViewNonContinuousButton, opened && !pdfCollection); - setEnabled(singlePageViewNonContinuousButton, opened && !pdfCollection); - - if (opened) { - reflectZoomInZoomComboBox(); - reflectFitInFitButtons(); - reflectDocumentViewModeInButtons(); - reflectToolInToolButtons(); - reflectFormHighlightButtons(); - } - } - - private boolean hasForms() { - if (document == null) { - return false; - } - return !(document.getCatalog().getInteractiveForm() == null || - document.getCatalog().getInteractiveForm().getFields() == null || - document.getCatalog().getInteractiveForm().getFields().size() == 0); - } - - private void reflectPageChangeInComponents() { - boolean opened = document != null; - int nPages = (getPageTree() != null) ? getPageTree().getNumberOfPages() : 0; - int currentPage = isCurrentPage() ? - documentViewController.getCurrentPageDisplayValue() : 0; - - setEnabled(firstPageMenuItem, opened && currentPage != 1); - setEnabled(previousPageMenuItem, opened && currentPage != 1); - setEnabled(nextPageMenuItem, opened && currentPage != nPages); - setEnabled(lastPageMenuItem, opened && currentPage != nPages); - - setEnabled(firstPageButton, opened && currentPage != 1); - setEnabled(previousPageButton, opened && currentPage != 1); - setEnabled(nextPageButton, opened && currentPage != nPages); - setEnabled(lastPageButton, opened && currentPage != nPages); - - if (currentPageNumberTextField != null) { - currentPageNumberTextField.setText( - opened ? Integer.toString(currentPage) : ""); - } - } - - public boolean havePermissionToPrint() { - if (document == null) - return false; - org.icepdf.core.pobjects.security.SecurityManager securityManager = - document.getSecurityManager(); - if (securityManager == null) - return true; - Permissions permissions = securityManager.getPermissions(); - return permissions == null || - permissions.getPermissions(Permissions.PRINT_DOCUMENT); - } - - public boolean havePermissionToExtractContent() { - if (document == null) - return false; - org.icepdf.core.pobjects.security.SecurityManager securityManager = - document.getSecurityManager(); - if (securityManager == null) - return true; - Permissions permissions = securityManager.getPermissions(); - return permissions == null || - permissions.getPermissions(Permissions.CONTENT_EXTRACTION); - } - - public boolean havePermissionToModifyDocument() { - if (document == null) - return false; - org.icepdf.core.pobjects.security.SecurityManager securityManager = - document.getSecurityManager(); - if (securityManager == null) - return true; - Permissions permissions = securityManager.getPermissions(); - return permissions == null || - permissions.getPermissions(Permissions.MODIFY_DOCUMENT); - } - - private void setEnabled(JComponent comp, boolean ena) { - if (comp != null) - comp.setEnabled(ena); - } - - private void setZoomFromZoomComboBox() { - if (reflectingZoomInZoomComboBox) - return; - final int selIndex = zoomComboBox.getSelectedIndex(); - float[] zoomLevels = documentViewController.getZoomLevels(); - if (selIndex >= 0 && selIndex < zoomLevels.length) { - float zoom = 1.0f; - try { - zoom = zoomLevels[selIndex]; - } catch (IndexOutOfBoundsException ex) { - logger.log(Level.FINE, "Error apply zoom levels"); - } finally { - if (zoom != documentViewController.getZoom()) { - setZoom(zoom); - } - } - } else { - boolean success = false; - try { - Object selItem = zoomComboBox.getSelectedItem(); - if (selItem != null) { - String str = selItem.toString(); - str = str.replace('%', ' '); - str = str.trim(); - float zoom = Float.parseFloat(str); - zoom /= 100.0f; - if (zoom != documentViewController.getZoom()) { - setZoom(zoom); - } - success = true; - } - } catch (Exception e) { - // Most likely a NumberFormatException - success = false; - } - if (!success) { - Toolkit.getDefaultToolkit().beep(); - } - } - } - - /** - * Method to determine if the Undo and Redo menu items can be enabled - * This will query the UndoCaretaker for the status of the queue first - */ - public void reflectUndoCommands() { - UndoCaretaker undoCaretaker = ((DocumentViewModelImpl) - documentViewController.getDocumentViewModel()). - getAnnotationCareTaker(); - setEnabled(undoMenuItem, undoCaretaker.isUndo()); - setEnabled(redoMenuItem, undoCaretaker.isRedo()); - } - - private void reflectZoomInZoomComboBox() { - if (reflectingZoomInZoomComboBox) - return; - if (document == null) - return; - int index = -1; - final float zoom = documentViewController.getZoom(); - final float belowZoom = zoom * 0.99f; - final float aboveZoom = zoom * 1.01f; - float[] zoomLevels = documentViewController.getZoomLevels(); - if (zoomLevels != null) { - for (int i = 0; i < zoomLevels.length; i++) { - final float curr = zoomLevels[i]; - if (curr >= belowZoom && curr <= aboveZoom) { - index = i; - break; - } - } - } - try { - reflectingZoomInZoomComboBox = true; - - if (zoomComboBox != null) { - if (index > -1) { - zoomComboBox.setSelectedIndex(index); - } else { - zoomComboBox.setSelectedItem(NumberFormat.getPercentInstance().format(zoom)); - } - } - // upatdate the page fit values if they are in the correct zoom range -// if( viewModel.fitPageFlag == .PAGE_FIT_NONE ) { -// float fitActualZoom = calcZoomForFitActualSize(); -// if( fitActualZoom >= belowZoom && fitActualZoom <= aboveZoom ) -// viewModel.fitPageFlag = ViewModel.PAGE_FIT_ACTUAL_SIZE; -// else { -// float fitPageZoom = calcZoomForFitPage(); -// if( fitPageZoom >= belowZoom && fitPageZoom <= aboveZoom ) -// viewModel.fitPageFlag = ViewModel.PAGE_FIT_IN_WINDOW; -// else { -// float fitWidthZoom = calcZoomForFitWidth(); -// if( fitWidthZoom >= belowZoom && fitWidthZoom <= aboveZoom ) -// viewModel.fitPageFlag = ViewModel.PAGE_FIT_WINDOW_WIDTH; -// } -// } -// } - } finally { - reflectingZoomInZoomComboBox = false; - } - } - - private boolean reflectingZoomInZoomComboBox = false; - - - /** - * Gets the current display tool value for the display panel. - * - * @return constant representing the state of the display tool for the - * display panel. - * @see #setDisplayTool - */ - public int getDocumentViewToolMode() { - return documentViewController.getToolMode(); - } - - /** - * Sets the display tool used when the document is viewed in interactive - * mode. A display changes the icon of the mouse when it is over the panel - * that displays a document page. There are currently four possible tool - * modes: - *
        - *
      • DISPLAY_TOOL_PAN - Changes the mouse icon to a hand and allows - * the user to click and drag the document view (Pan). This pan feature - * is only available when the display window has scrollbars.
      • - *
      • DISPLAY_TOOL_ZOOM_IN - Changes the mouse icon to a magnifying glass - * and adds a left mouse click listener to the display panel. One left mouse - * click increases the zoom factor by 20%.
      • - *
      • DISPLAY_TOOL_ZOOM_OUT - Changes the mouse icon to a magnifying glass - * and adds a left mouse click listener to the display panel. One left - * mouse click decreases the zoom factor by 20%.
      • - *
      • DISPLAY_TOOL_NONE - Changes the mouse icon to the default icon - * and removes mouse properties from the display panel.
      • - *
      - * - * @see #getDocumentViewToolMode - */ - public void setDisplayTool(final int argToolName) { - try { - boolean actualToolMayHaveChanged = false; - if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_PAN) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_PAN); - documentViewController.setViewCursor(DocumentViewController.CURSOR_HAND_OPEN); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_SELECTION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_SELECTION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_SELECT); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION) { - actualToolMayHaveChanged = - documentViewController.setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION); - documentViewController.setViewCursor(DocumentViewController.CURSOR_CROSSHAIR); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN) { - actualToolMayHaveChanged = - documentViewController.setToolMode( - DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN); - documentViewController.setViewCursor(DocumentViewController.CURSOR_ZOOM_IN); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC) { - actualToolMayHaveChanged = - documentViewController.setToolMode( - DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC); - documentViewController.setViewCursor(DocumentViewController.CURSOR_MAGNIFY); - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_WAIT) { - setCursorOnComponents(DocumentViewController.CURSOR_WAIT); - } else if (argToolName == DocumentViewModelImpl.DISPLAY_TOOL_NONE) { - setCursorOnComponents(DocumentViewController.CURSOR_DEFAULT); - } - if (actualToolMayHaveChanged) { - reflectToolInToolButtons(); - } - - // disabled the annotation edit panels, selection will activate them again. - if (annotationPanel != null) { - annotationPanel.setEnabled(false); - } - - // repaint the page views. - documentViewController.getViewContainer().repaint(); - } catch (java.awt.HeadlessException e) { - e.printStackTrace(); - logger.log(Level.FINE, "Headless exception during tool selection", e); - } - } - - - private void setCursorOnComponents(final int cursorType) { - Cursor cursor = documentViewController.getViewCursor(cursorType); - if (utilityTabbedPane != null) - utilityTabbedPane.setCursor(cursor); -// if( documentViewController != null ) { -// documentViewController.setViewCursor( cursorType ); -// } - if (viewer != null) - viewer.setCursor(cursor); - } - - /** - * Sets the state of the "Tools" buttons. This ensure that correct button - * is depressed when the state of the Document class specifies it. - */ - private void reflectToolInToolButtons() { - reflectSelectionInButton(panToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_PAN - )); - reflectSelectionInButton(textSelectToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION - )); - reflectSelectionInButton(selectToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_SELECTION - )); - reflectSelectionInButton(linkAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION - )); - reflectSelectionInButton(highlightAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION - )); - reflectSelectionInButton(highlightAnnotationUtilityToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION - )); - reflectSelectionInButton(strikeOutAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION - )); - reflectSelectionInButton(underlineAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION - )); - reflectSelectionInButton(lineAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION - )); - reflectSelectionInButton(lineArrowAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION - )); - reflectSelectionInButton(squareAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION - )); - reflectSelectionInButton(circleAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION - )); - reflectSelectionInButton(inkAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION - )); - reflectSelectionInButton(freeTextAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION - )); - reflectSelectionInButton(textAnnotationToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION - )); - reflectSelectionInButton(textAnnotationUtilityToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION - )); - reflectSelectionInButton(zoomInToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN - )); - reflectSelectionInButton(zoomDynamicToolButton, - documentViewController.isToolModeSelected( - DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC - )); - reflectSelectionInButton(showHideUtilityPaneButton, - isUtilityPaneVisible()); - reflectSelectionInButton(formHighlightButton, - viewModel.isWidgetAnnotationHighlight()); - } - - /** - * Sets the state of the "Fit" buttons. This ensure that correct button - * is depressed when the state of the Document class specifies it. - */ - private void reflectFitInFitButtons() { - if (document == null) { - return; - } - reflectSelectionInButton(fitWidthButton, - isDocumentFitMode(DocumentViewController.PAGE_FIT_WINDOW_WIDTH)); - reflectSelectionInButton(fitHeightButton, - isDocumentFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT)); - reflectSelectionInButton(fitActualSizeButton, - isDocumentFitMode(DocumentViewController.PAGE_FIT_ACTUAL_SIZE)); - } - - /** - * Sets the state of the highlight forms button. Insures button is depressed when active. - */ - private void reflectFormHighlightButtons() { - if (document == null) { - return; - } - reflectSelectionInButton(formHighlightButton, viewModel.isWidgetAnnotationHighlight()); - } - - /** - * Sets the state of the "Document View" buttons. This ensure that correct button - * is depressed when the state of the view controller class specifies it. - */ - private void reflectDocumentViewModeInButtons() { - if (document == null) { - return; - } - if (isDocumentViewMode(DocumentViewControllerImpl.USE_ATTACHMENTS_VIEW)) { - return; - } - reflectSelectionInButton( - singlePageViewContinuousButton, isDocumentViewMode( - DocumentViewControllerImpl.ONE_COLUMN_VIEW)); - reflectSelectionInButton( - facingPageViewNonContinuousButton, isDocumentViewMode( - DocumentViewControllerImpl.TWO_PAGE_RIGHT_VIEW)); - reflectSelectionInButton( - facingPageViewContinuousButton, isDocumentViewMode( - DocumentViewControllerImpl.TWO_COLUMN_RIGHT_VIEW)); - reflectSelectionInButton( - singlePageViewNonContinuousButton, isDocumentViewMode( - DocumentViewControllerImpl.ONE_PAGE_VIEW)); - } - - private void reflectSelectionInButton(AbstractButton btn, boolean selected) { - if (btn != null) { - if (btn.isSelected() != selected) { - btn.setSelected(selected); - } - - btn.setBorder( - selected ? - BorderFactory.createLoweredBevelBorder() : - BorderFactory.createEmptyBorder()); - } - } - - /** - * Utility method for opening a file. Shows a dialog for the user to - * select which file to open. - */ - public void openFile() { - // Create and display a file open dialog - final JFileChooser fileChooser = new JFileChooser(); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - fileChooser.addChoosableFileFilter(FileExtensionUtils.getPDFFileFilter()); - if (ViewModel.getDefaultFile() != null) { - fileChooser.setCurrentDirectory(ViewModel.getDefaultFile()); - fileChooser.setSelectedFile(ViewModel.getDefaultFile()); - fileChooser.ensureFileIsVisible(ViewModel.getDefaultFile()); - } - // show the dialog - fileChooser.setDialogTitle(messageBundle.getString("viewer.dialog.openFile.title")); - int returnVal = fileChooser.showOpenDialog(viewer); - - if (returnVal == JFileChooser.APPROVE_OPTION) { - final File file = fileChooser.getSelectedFile(); - // trying to get rid of shadow left by file chooser - fileChooser.setVisible(false); - // make sure file being opened is valid - String extension = FileExtensionUtils.getExtension(file); - if (extension != null) { - if (extension.equals(FileExtensionUtils.pdf)) { - if (viewer != null) { - viewer.toFront(); - viewer.requestFocus(); - } - openFileInSomeViewer(file); - } else { - org.icepdf.ri.util.Resources.showMessageDialog(viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openFile.error.title", - "viewer.dialog.openFile.error.msg", - file.getPath()); - } - - // save the default directory - ViewModel.setDefaultFile(file); - } - } - fileChooser.setVisible(false); - } - - private void openFileInSomeViewer(File file) { - // openDocument the file - if (document == null) { - openDocument(file.getPath()); - } else if (windowManagementCallback != null) { - int oldTool = SwingController.this.getDocumentViewToolMode(); - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - try { - windowManagementCallback.newWindow(file.getPath()); - } finally { - setDisplayTool(oldTool); - } - } - } - - public void openFileInSomeViewer(String filename) { - try { - File pdfFile = new File(filename); - openFileInSomeViewer(pdfFile); - } catch (Exception e) { - - } - } - - /** - * Setup the security handle if specified, if not then creates and uses the default implementation. - * - * @param document document to set securityCallback on . - * @param securityCallback - */ - protected void setupSecurityHandler(Document document, SecurityCallback securityCallback) throws - PDFException, PDFSecurityException { - // create default security callback is user has not created one - if (securityCallback == null) { - document.setSecurityCallback( - new MyGUISecurityCallback(viewer, messageBundle)); - } else { - document.setSecurityCallback(documentViewController.getSecurityCallback()); - } - } - - /** - * Open a file specified by the given path name. - * - * @param pathname String representing a valid file path - */ - public void openDocument(String pathname) { - if (pathname != null && pathname.length() > 0) { - try { - // dispose a currently open document, if one. - if (document != null) { - closeDocument(); - } - - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - - // load the document - document = new Document(); - // create default security callback is user has not created one - setupSecurityHandler(document, documentViewController.getSecurityCallback()); - document.setFile(pathname); - commonNewDocumentHandling(pathname); - } catch (PDFException e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.pdfException.title", - "viewer.dialog.openDocument.pdfException.msg", - pathname); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } catch (PDFSecurityException e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.pdfSecurityException.title", - "viewer.dialog.openDocument.pdfSecurityException.msg", - pathname); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } catch (Exception e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.exception.title", - "viewer.dialog.openDocument.exception.msg", - pathname); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } finally { - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_PAN); - } - } - } - - /** - * Utility method for opening a URL. Shows a dialog for the user to - * type what URL to open. - */ - public void openURL() { - String urlLocation = ((ViewModel.getDefaultURL() != null) ? ViewModel.getDefaultURL() : ""); - // display url input dialog - Object o = JOptionPane.showInputDialog( - viewer, - "URL:", - "Open URL", - JOptionPane.QUESTION_MESSAGE, - null, - null, - urlLocation); - if (o != null) { - URLAccess urlAccess = URLAccess.doURLAccess(o.toString()); - urlAccess.closeConnection(); - if (urlAccess.errorMessage != null) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openURL.exception.title", - "viewer.dialog.openURL.exception.msg", - urlAccess.errorMessage, - urlAccess.urlLocation - ); - } else { - if (viewer != null) { - viewer.toFront(); - viewer.requestFocus(); - } - openURLInSomeViewer(urlAccess.url); - } - ViewModel.setDefaultURL(urlAccess.urlLocation); - urlAccess.dispose(); - } - } - - private void openURLInSomeViewer(URL url) { - // openDocument the URL - if (document == null) { - openDocument(url); - } else if (windowManagementCallback != null) { - int oldTool = SwingController.this.getDocumentViewToolMode(); - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - try { - windowManagementCallback.newWindow(url); - } finally { - setDisplayTool(oldTool); - } - } - } - - /** - * Open a URL specifed by the location variable. - * - * @param location location of a valid PDF document - */ - public void openDocument(final URL location) { - if (location != null) { - // dispose a currently open document, if one. - if (document != null) { - closeDocument(); - } - - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - - // load the document - document = new Document(); - try { - // make a connection - final URLConnection urlConnection = location.openConnection(); - final int size = urlConnection.getContentLength(); - SwingWorker worker = new SwingWorker() { - public Object construct() { - InputStream in = null; - try { - // Create ProgressMonitorInputStream - Object[] messageArguments = {location.toString()}; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.dialog.openURL.downloading.msg")); - ProgressMonitorInputStream progressMonitorInputStream = - new ProgressMonitorInputStream( - viewer, - formatter.format(messageArguments), - new SizeInputStream(urlConnection.getInputStream(), size)); - // Create a stream on the URL connection - in = new BufferedInputStream(progressMonitorInputStream); - String pathOrURL = location.toString(); - document.setInputStream(in, pathOrURL); - // create default security callback is user has not created one - setupSecurityHandler(document, documentViewController.getSecurityCallback()); - commonNewDocumentHandling(location.getPath()); - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_PAN); - } catch (IOException ex) { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - logger.log(Level.FINE, "Error opening document.", e); - } - } - closeDocument(); - document = null; - } catch (PDFException e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.pdfException.title", - "viewer.dialog.openDocument.pdfException.msg", - location); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } catch (PDFSecurityException e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.pdfSecurityException.title", - "viewer.dialog.openDocument.pdfSecurityException.msg", - location); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } catch (Exception e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.exception.title", - "viewer.dialog.openDocument.exception.msg", - location); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } - return null; - } - }; - worker.start(); - - } catch (Exception e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.exception.title", - "viewer.dialog.openDocument.exception.msg", - location); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } - } - } - - /** - * Opens a Document via the specified InputStream. This method is a convenience method provided for - * backwards compatibility. - *

      - *

      Note: This method is less efficient than - * {@see #openDocument(Stringpathname)} or {@see #openDocument(URLlocation)} as it - * may have to do intermediary data copying, using more memory. - * - * @param inputStream InputStream containing a valid PDF document. - * @param description When in the GUI for describing this document. - * @param pathOrURL Either a file path, or file name, or URL, describing the - * origin of the PDF file. This is typically null. If non-null, it is - * used to populate the default file name in the File..Save a Copy - * dialog summoned in saveFile() - */ - public void openDocument(InputStream inputStream, String description, String pathOrURL) { - if (inputStream != null) { - try { - // dispose a currently open document, if one. - if (document != null) { - closeDocument(); - } - - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - - // load the document - document = new Document(); - // create default security callback is user has not created one - setupSecurityHandler(document, documentViewController.getSecurityCallback()); - document.setInputStream(inputStream, pathOrURL); - - commonNewDocumentHandling(description); - } catch (PDFException e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.pdfException.title", - "viewer.dialog.openDocument.pdfException.msg", - description); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } catch (PDFSecurityException e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.pdfSecurityException.title", - "viewer.dialog.openDocument.pdfSecurityException.msg", - description); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } catch (Exception e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.exception.title", - "viewer.dialog.openDocument.exception.msg", - description); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } finally { - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_PAN); - } - } - } - - /** - * Load the specified file in a new Viewer RI window. - * - * @param embeddedDocument document to load in ne window - * @param fileName file name of the document in question - */ - public void openDocument(Document embeddedDocument, String fileName) { - if (embeddedDocument != null) { - try { - // dispose a currently open document, if one. - if (document != null) { - closeDocument(); - } - - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - - // load the document - document = embeddedDocument; - // create default security callback is user has not created one - setupSecurityHandler(document, documentViewController.getSecurityCallback()); - commonNewDocumentHandling(fileName); - } catch (Exception e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.exception.title", - "viewer.dialog.openDocument.exception.msg", - fileName); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } finally { - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_PAN); - } - } - } - - /** - * Opens a Document via the specified byte array. - * - * @param data Byte array containing a valid PDF document. - * @param offset the index into the byte array where the PDF data begins - * @param length the number of bytes in the byte array belonging to the PDF data - * @param description When in the GUI for describing this document. - * @param pathOrURL Either a file path, or file name, or URL, describing the - * origin of the PDF file. This is typically null. If non-null, it is - * used to populate the default file name in the File..Save a Copy - * dialog summoned in saveFile() - */ - public void openDocument(byte[] data, int offset, int length, String description, String pathOrURL) { - if (data != null) { - try { - // dispose a currently open document, if one. - if (document != null) { - closeDocument(); - } - - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - - // load the document - document = new Document(); - // create default security callback is user has not created one - setupSecurityHandler(document, documentViewController.getSecurityCallback()); - document.setByteArray(data, offset, length, pathOrURL); - - commonNewDocumentHandling(description); - } catch (PDFException e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.pdfException.title", - "viewer.dialog.openDocument.pdfException.msg", - description); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } catch (PDFSecurityException e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.pdfSecurityException.title", - "viewer.dialog.openDocument.pdfSecurityException.msg", - description); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } catch (Exception e) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.openDocument.exception.title", - "viewer.dialog.openDocument.exception.msg", - description); - document = null; - logger.log(Level.FINE, "Error opening document.", e); - } finally { - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_PAN); - } - } - } - - public void commonNewDocumentHandling(String fileDescription) { - // setup custom search utility tool - if (searchPanel != null) - searchPanel.setDocument(document); - - if (thumbnailsPanel != null) { - thumbnailsPanel.setDocument(document); - } - - // utility pane visibility - boolean showUtilityPane = false; - - // get data on how the view should look from the document dictionary - // if no data, use settings from last viewed document, fit and view type - Catalog catalog = document.getCatalog(); - - // Page layout, the default value is singlePage, but we currently - // remember the users last view mode via the properties manager. Possible - // values are SinglePage, OnceColumn, TwoColumnLeft, TwoColumRight, - // TwoPageLeft, TwoPageRight. - Object tmp = catalog.getObject(Catalog.PAGELAYOUT_KEY); - if (tmp != null && tmp instanceof Name) { - String pageLayout = ((Name) tmp).getName(); - int viewType = DocumentViewControllerImpl.ONE_PAGE_VIEW; - if (pageLayout.equalsIgnoreCase("OneColumn")) { - viewType = DocumentViewControllerImpl.ONE_COLUMN_VIEW; - } else if (pageLayout.equalsIgnoreCase("TwoColumnLeft")) { - viewType = DocumentViewControllerImpl.TWO_COLUMN_LEFT_VIEW; - } else if (pageLayout.equalsIgnoreCase("TwoColumnRight")) { - viewType = DocumentViewControllerImpl.TWO_COLUMN_RIGHT_VIEW; - } else if (pageLayout.equalsIgnoreCase("TwoPageLeft")) { - viewType = DocumentViewControllerImpl.TWO_PAGE_LEFT_VIEW; - } else if (pageLayout.equalsIgnoreCase("TwoPageRight")) { - viewType = DocumentViewControllerImpl.TWO_PAGE_RIGHT_VIEW; - } - documentViewController.setViewType(viewType); - } - // make sure we don't keep Attachments view around from a previous load - // as we don't want to use it for a none attachments PDF file. - if (documentViewController.getViewMode() == - DocumentViewControllerImpl.USE_ATTACHMENTS_VIEW) { - documentViewController.revertViewType(); - } - // check to see if we have collection - if (isPdfCollection()) { - documentViewController.setViewType(DocumentViewControllerImpl.USE_ATTACHMENTS_VIEW); - } - - if (utilityTabbedPane != null) { - // Page mode by default is UseNone, where other options are, UseOutlines, - // UseThumbs, FullScreen (ignore), UseOC(ignore), Use Attachements(ignore); - Name pageMode = catalog.getPageMode(); - showUtilityPane = pageMode.equals(Catalog.PAGE_MODE_USE_OUTLINES_VALUE) || - pageMode.equals(Catalog.PAGE_MODE_OPTIONAL_CONTENT_VALUE) || - pageMode.equals(Catalog.PAGE_MODE_USE_ATTACHMENTS_VALUE) || - pageMode.equals(Catalog.PAGE_MODE_USE_THUMBS_VALUE); - } - - // selected the utility tab defined by the page mode key - if (showUtilityPane){ - Name pageMode = catalog.getPageMode(); - if (pageMode.equals(Catalog.PAGE_MODE_USE_OUTLINES_VALUE) && - utilityTabbedPane.indexOfComponent(outlinesScrollPane) > 0) { - utilityTabbedPane.setSelectedComponent(outlinesScrollPane); - } else if (pageMode.equals(Catalog.PAGE_MODE_OPTIONAL_CONTENT_VALUE) && - utilityTabbedPane.indexOfComponent(layersPanel) > 0) { - utilityTabbedPane.setSelectedComponent(layersPanel); - } else if (pageMode.equals(Catalog.PAGE_MODE_USE_ATTACHMENTS_VALUE) && - utilityTabbedPane.indexOfComponent(attachmentPanel) > 0) { - utilityTabbedPane.setSelectedComponent(attachmentPanel); - } else if (pageMode.equals(Catalog.PAGE_MODE_USE_THUMBS_VALUE) && - utilityTabbedPane.indexOfComponent(thumbnailsPanel) > 0) { - utilityTabbedPane.setSelectedComponent(thumbnailsPanel); - }else{ - // Catalog.PAGE_MODE_USE_NONE_VALUE - showUtilityPane = false; - } - } - - // initiates the view layout model, page coordinates and preferred size - documentViewController.setDocument(document); - - if (layersPanel != null) { - layersPanel.setDocument(document); - } - - if (signaturesPanel != null) { - signaturesPanel.setDocument(document); - } - - if (attachmentPanel != null) { - attachmentPanel.setDocument(document); - } - - // Refresh the properties manager object if we don't already have one - // This would be not null if the UI was constructed manually - if ((propertiesManager == null) && (windowManagementCallback != null)) { - propertiesManager = windowManagementCallback.getProperties(); - } - - // Set the default zoom level from the properties file - float defaultZoom = (float) PropertiesManager.checkAndStoreDoubleProperty( - propertiesManager, - PropertiesManager.PROPERTY_DEFAULT_ZOOM_LEVEL); - documentViewController.setZoom(defaultZoom); - - // Set the default page fit mode - setPageFitMode(PropertiesManager.checkAndStoreIntegerProperty( - propertiesManager, - PropertiesManager.PROPERTY_DEFAULT_PAGEFIT, - DocumentViewController.PAGE_FIT_NONE), false); - - // Apply any ViewerPreferences from the doc - applyViewerPreferences(catalog, propertiesManager); - - // Only show utility panel if there is an outline or layers - OutlineItem item = null; - Outlines outlines = document.getCatalog().getOutlines(); - if (outlines != null && outlinesTree != null) - item = outlines.getRootOutlineItem(); - if (item != null) { - outlinesTree.setModel(new DefaultTreeModel(new OutlineItemTreeNode(item))); - outlinesTree.setRootVisible(!item.isEmpty()); - outlinesTree.setShowsRootHandles(true); - if (utilityTabbedPane != null && outlinesScrollPane != null) { - if (utilityTabbedPane.indexOfComponent(outlinesScrollPane) > -1) { - utilityTabbedPane.setEnabledAt( - utilityTabbedPane.indexOfComponent(outlinesScrollPane), - true); - } - } - } else { - if (utilityTabbedPane != null && outlinesScrollPane != null) { - if (utilityTabbedPane.indexOfComponent(outlinesScrollPane) > -1) { - utilityTabbedPane.setEnabledAt( - utilityTabbedPane.indexOfComponent(outlinesScrollPane), - false); - } - } - } - - // showUtilityPane will be true the document has an outline, but the - // visibility can be over-ridden with the property application.utilitypane.show - boolean hideUtilityPane = PropertiesManager.checkAndStoreBooleanProperty( - propertiesManager, - PropertiesManager.PROPERTY_HIDE_UTILITYPANE, false); - // hide utility pane - if (hideUtilityPane) { - setUtilityPaneVisible(false); - } else { - setUtilityPaneVisible(showUtilityPane); - } - - // apply state value for whether form highlight is being used or not. - boolean showFormHighlight = PropertiesManager.checkAndStoreBooleanProperty( - propertiesManager, - PropertiesManager.PROPERTY_VIEWPREF_FORM_HIGHLIGHT, true); - setFormHighlightVisible(showFormHighlight); - - // check if there are layers and enable/disable the tab as needed - OptionalContent optionalContent = document.getCatalog().getOptionalContent(); - if (layersPanel != null && utilityTabbedPane != null) { - if (optionalContent == null || optionalContent.getOrder() == null) { - if (utilityTabbedPane.indexOfComponent(layersPanel) > -1) { - utilityTabbedPane.setEnabledAt( - utilityTabbedPane.indexOfComponent(layersPanel), - false); - } - } else { - if (utilityTabbedPane.indexOfComponent(layersPanel) > -1) { - utilityTabbedPane.setEnabledAt( - utilityTabbedPane.indexOfComponent(layersPanel), - true); - } - } - } - // check if there are any attachments and enable/disable the tab as needed - if (attachmentPanel != null && utilityTabbedPane != null) { - if (catalog.getEmbeddedFilesNameTree() != null && - catalog.getEmbeddedFilesNameTree().getRoot() != null) { - if (utilityTabbedPane.indexOfComponent(attachmentPanel) > -1) { - utilityTabbedPane.setEnabledAt( - utilityTabbedPane.indexOfComponent(attachmentPanel), - true); - } - } else { - if (utilityTabbedPane.indexOfComponent(attachmentPanel) > -1) { - utilityTabbedPane.setEnabledAt( - utilityTabbedPane.indexOfComponent(attachmentPanel), - false); - } - } - } - // check if there are signatures and enable/disable the tab as needed - boolean signaturesExist = document.getCatalog().getInteractiveForm() != null && - document.getCatalog().getInteractiveForm().isSignatureFields(); - if (signaturesPanel != null && utilityTabbedPane != null) { - if (signaturesExist) { - if (utilityTabbedPane.indexOfComponent(signaturesPanel) > -1) { - utilityTabbedPane.setEnabledAt( - utilityTabbedPane.indexOfComponent(signaturesPanel), - true); - } - } else { - if (utilityTabbedPane.indexOfComponent(signaturesPanel) > -1) { - utilityTabbedPane.setEnabledAt( - utilityTabbedPane.indexOfComponent(signaturesPanel), - false); - } - } - } - - // add to the main pdfContentPanel the document peer - if (viewer != null) { - Object[] messageArguments = new Object[]{fileDescription}; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.window.title.open.default")); - viewer.setTitle(formatter.format(messageArguments)); - - } - - // disable the annotation properties panel by default - if (annotationPanel != null) { - annotationPanel.setEnabled(false); - } - - // set the go to page combo box in the mainToolbar - reflectStateInComponents(); - updateDocumentView(); - } - - /** - * Close the currently opened PDF Document. The toolbar component's states - * are also changed to their default values and made inactive.
      - *
      - * Note: If you create several SwingControllers to manipulate a single - * Document, and each SwingController would be disposed of at a different - * time, while the others continue to use that same shared Document, then - * you should not call Document.dispose() inside of here, or alternatively - * implement reference counting, so that only the last SwingController would - * call Document.dispose() - * - * @see Document - */ - public void closeDocument() { - // Clear the SearchPane, but also stop any search in progress - if (searchPanel != null) - searchPanel.setDocument(null); - - if (thumbnailsPanel != null) - thumbnailsPanel.setDocument(null); - - if (layersPanel != null) { - layersPanel.setDocument(null); - } - - if (attachmentPanel != null) { - attachmentPanel.setDocument(null); - } - - if (signaturesPanel != null) { - signaturesPanel.setDocument(null); - } - - // set the default cursor. - documentViewController.closeDocument(); - - // clear search controller caches. - documentSearchController.dispose(); - - // free the document - if (document != null) { - document.dispose(); - document = null; - } - - // remove the page numbers in the go to page combo box in the mainToolbar - if (currentPageNumberTextField != null) - currentPageNumberTextField.setText(""); - if (numberOfPagesLabel != null) - numberOfPagesLabel.setText(""); - if (currentPageNumberTextField != null) - currentPageNumberTextField.setEnabled(false); - if (statusLabel != null) - statusLabel.setText(" "); - // set the scale level back to 100%, default - if (zoomComboBox != null) - zoomComboBox.setSelectedItem(NumberFormat.getPercentInstance().format(1.0)); - // update thew view to show no pages in the view - updateDocumentView(); - - // tear down the outline tree. - TreeModel treeModel = (outlinesTree != null) ? outlinesTree.getModel() : null; - if (treeModel != null) { - OutlineItemTreeNode root = (OutlineItemTreeNode) treeModel.getRoot(); - if (root != null) - root.recursivelyClearOutlineItems(); - outlinesTree.getSelectionModel().clearSelection(); - outlinesTree.getSelectionModel().setSelectionPath(null); - outlinesTree.setSelectionPath(null); - outlinesTree.setModel(null); - } - setUtilityPaneVisible(false); - if (viewer != null) { - viewer.setTitle(messageBundle.getString("viewer.window.title.default")); - viewer.invalidate(); - viewer.validate(); - viewer.getContentPane().repaint(); - } - - reflectStateInComponents(); - } - - /** - * Way to dispose of all memory references, and clean up the Document resources
      - *
      - * Note: If you create several SwingControllers to manipulate a single - * Document, and each SwingController would be disposed of at a different - * time, while the others continue to use that same shared Document, then - * you should not call Document.dispose() inside of here. Alternatively, - * implement reference counting, so that only the last SwingController would - * call Document.dispose() - */ - public void dispose() { - if (disposed) - return; - disposed = true; - - closeDocument(); - - openFileMenuItem = null; - openURLMenuItem = null; - closeMenuItem = null; - saveAsFileMenuItem = null; - exportTextMenuItem = null; - exportSVGMenuItem = null; - permissionsMenuItem = null; - informationMenuItem = null; - printSetupMenuItem = null; - printMenuItem = null; - exitMenuItem = null; - - fitActualSizeMenuItem = null; - fitPageMenuItem = null; - fitWidthMenuItem = null; - zoomInMenuItem = null; - zoomOutMenuItem = null; - rotateLeftMenuItem = null; - rotateRightMenuItem = null; - showHideToolBarMenuItem = null; - showHideUtilityPaneMenuItem = null; - - firstPageMenuItem = null; - previousPageMenuItem = null; - nextPageMenuItem = null; - lastPageMenuItem = null; - searchMenuItem = null; - goToPageMenuItem = null; - - minimiseAllMenuItem = null; - bringAllToFrontMenuItem = null; - windowListMenuItems = null; - - aboutMenuItem = null; - - openFileButton = null; - saveAsFileButton = null; - printButton = null; - searchButton = null; - showHideUtilityPaneButton = null; - - firstPageButton = null; - previousPageButton = null; - nextPageButton = null; - lastPageButton = null; - if (currentPageNumberTextField != null) { - currentPageNumberTextField.removeActionListener(this); - currentPageNumberTextField.removeFocusListener(this); - currentPageNumberTextField.removeKeyListener(this); - currentPageNumberTextField = null; - } - numberOfPagesLabel = null; - - zoomInButton = null; - zoomOutButton = null; - if (zoomComboBox != null) { - zoomComboBox.removeItemListener(this); - zoomComboBox = null; - } - - fitActualSizeButton = null; - fitHeightButton = null; - fitWidthButton = null; - - rotateLeftButton = null; - rotateRightButton = null; - - panToolButton = null; - zoomInToolButton = null; - zoomDynamicToolButton = null; - textSelectToolButton = null; - selectToolButton = null; - linkAnnotationToolButton = null; - highlightAnnotationToolButton = null; - highlightAnnotationUtilityToolButton = null; - underlineAnnotationToolButton = null; - strikeOutAnnotationToolButton = null; - lineAnnotationToolButton = null; - lineArrowAnnotationToolButton = null; - squareAnnotationToolButton = null; - circleAnnotationToolButton = null; - inkAnnotationToolButton = null; - freeTextAnnotationToolButton = null; - textAnnotationToolButton = null; - textAnnotationUtilityToolButton = null; - formHighlightButton = null; - - fontEngineButton = null; - - completeToolBar = null; - - outlinesTree = null; - if (outlinesScrollPane != null) { - outlinesScrollPane.removeAll(); - outlinesScrollPane = null; - } - if (searchPanel != null) { - searchPanel.dispose(); - searchPanel = null; - } - if (thumbnailsPanel != null) { - thumbnailsPanel.dispose(); - thumbnailsPanel = null; - } - if (layersPanel != null) { - layersPanel.dispose(); - } - if (attachmentPanel != null) { - attachmentPanel.dispose(); - } - if (signaturesPanel != null) { - signaturesPanel.dispose(); - } - if (utilityTabbedPane != null) { - utilityTabbedPane.removeAll(); - utilityTabbedPane = null; - } - - // Clean up the document view controller - if (documentViewController != null) { - documentViewController.removePropertyChangeListener(this); - documentViewController.dispose(); - } - - // clean up search controller - if (documentSearchController != null) { - documentSearchController.dispose(); - } - - if (utilityAndDocumentSplitPane != null) { - utilityAndDocumentSplitPane.removeAll(); - utilityAndDocumentSplitPane.removePropertyChangeListener(this); - } - - statusLabel = null; - if (viewer != null) { - viewer.removeWindowListener(this); - viewer.removeAll(); - } - viewModel = null; - - windowManagementCallback = null; - } - - /** - * Utility method for saving a copy of the currently opened - * PDF to a file. This will check all valid permissions and - * show a file save dialog for the user to select where to - * save the file to, and what name to give it. - */ - public void saveFile() { - - // Create and display a file saving dialog - final JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle(messageBundle.getString("viewer.dialog.saveAs.title")); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - fileChooser.addChoosableFileFilter(FileExtensionUtils.getPDFFileFilter()); - if (ViewModel.getDefaultFile() != null) { - fileChooser.setCurrentDirectory(ViewModel.getDefaultFile()); - } - - // See if we can come up with a default file name - // We want the bytes from whence, but the file name of origin - String origin = document.getDocumentOrigin(); - String originalFileName = null; - if (origin != null) { - int lastSeparator = Math.max( - Math.max( - origin.lastIndexOf("/"), - origin.lastIndexOf("\\")), - origin.lastIndexOf(File.separator) // Might not be / or \ - ); - if (lastSeparator >= 0) { - originalFileName = origin.substring(lastSeparator + 1); - if (originalFileName.length() > 0) { - // Set the selected file to a slightly modified name of the original - fileChooser.setSelectedFile(new File(generateNewSaveName(originalFileName))); - } else { - originalFileName = null; - } - } - } - - // show the dialog - int returnVal = fileChooser.showSaveDialog(viewer); - - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fileChooser.getSelectedFile(); - - // make sure file path being saved to is valid - String extension = FileExtensionUtils.getExtension(file); - if (extension == null) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.saveAs.noExtensionError.title", - "viewer.dialog.saveAs.noExtensionError.msg"); - saveFile(); - } else if (!extension.equals(FileExtensionUtils.pdf)) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.saveAs.extensionError.title", - "viewer.dialog.saveAs.extensionError.msg", - file.getName()); - saveFile(); - } else if ((originalFileName != null) && - (originalFileName.equalsIgnoreCase(file.getName()))) { - // Ensure a unique filename - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.saveAs.noneUniqueName.title", - "viewer.dialog.saveAs.noneUniqueName.msg", - file.getName()); - saveFile(); - } else { - // save file stream - try { - // If we don't know where the file came from, it's because we - // used Document.contentStream() or Document.setByteArray(), - // or we used setUrl() with disk caching disabled. - // with no path or URL as the origin. - // Note that we used to detect scenarios where we could access - // the file directly, or re-download it, to avoid locking our - // internal data structures for long periods for large PDFs, - // but that could cause problems with slow network links too, - // and would complicate the incremental update code, so we're - // harmonising on this approach. - FileOutputStream fileOutputStream = new FileOutputStream(file); - BufferedOutputStream buf = new BufferedOutputStream( - fileOutputStream, 4096 * 2); - - // We want 'save as' or 'save a copy to always occur - if (document.getStateManager().isChanged() && - !Document.foundIncrementalUpdater) { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.saveAs.noUpdates.title", - "viewer.dialog.saveAs.noUpdates.msg"); - } else { - if (!document.getStateManager().isChanged()) { - // save as copy - document.writeToOutputStream(buf); - } else { - // save as will append changes. - document.saveToOutputStream(buf); - } - } - buf.flush(); - fileOutputStream.flush(); - buf.close(); - fileOutputStream.close(); - } catch (MalformedURLException e) { - logger.log(Level.FINE, "Malformed URL Exception ", e); - } catch (IOException e) { - logger.log(Level.FINE, "IO Exception ", e); - } - // save the default directory - ViewModel.setDefaultFile(file); - } - } - } - - /** - * Generates a file name based on the original file name but appends "-new". - * If new file extsion exists a ".pdf" is automatically added. - * - * @param fileName file name that new file name is dirived from. - * @return original file name with the "-new" appended to it. - */ - protected String generateNewSaveName(String fileName) { - if (fileName != null) { - // Return the file with "-new" in the filename, before the extension - // For example Test.pdf would become Test-new.pdf - int endIndex = fileName.toLowerCase().indexOf(FileExtensionUtils.pdf) - 1; - String result; - if (endIndex < 0) { - result = fileName + "-new." + FileExtensionUtils.pdf; - } else { - result = fileName.substring(0, endIndex) + "-new." + - FileExtensionUtils.pdf; - } - return result; - } - return null; - } - - /** - * Utility method for exporting all of a Document's text to a text file. - * Shows a file save dialog for the user to select where to save the - * exported text file to, and what name to give that file. - */ - public void exportText() { - // Create and display a file saving dialog - final JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle(messageBundle.getString("viewer.dialog.exportText.title")); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - fileChooser.addChoosableFileFilter(FileExtensionUtils.getTextFileFilter()); - if (ViewModel.getDefaultFile() != null) { - fileChooser.setCurrentDirectory(ViewModel.getDefaultFile()); - } - // show the dialog - int returnVal = fileChooser.showSaveDialog(viewer); - - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fileChooser.getSelectedFile(); - // make sure file being opened is valid - String extension = FileExtensionUtils.getExtension(file); - if (extension != null) { - // save the default directory - ViewModel.setDefaultFile(file); - - TextExtractionTask textExtractionTask = - new TextExtractionTask(document, file, messageBundle); - - ProgressMonitor progressMonitor = new ProgressMonitor( - viewer, messageBundle.getString("viewer.dialog.exportText.progress.msg"), - "", 0, textExtractionTask.getLengthOfTask()); - progressMonitor.setProgress(0); - progressMonitor.setMillisToDecideToPopup(0); - - TextExtractionGlue glue = new TextExtractionGlue(textExtractionTask, progressMonitor); - Timer timer = new Timer(1000, glue); // 1000 milliseconds - glue.setTimer(timer); - - textExtractionTask.go(); - timer.start(); - } else { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.exportText.noExtensionError.title", - "viewer.dialog.exportText.noExtensionError.msg"); - exportText(); - } - } - } - - /** - * Utility method for exporting the current page of the Document to an SVG file. - * Shows a file save dialog for the user to select where to save the - * exported SVG file to, and what name to give that file. - */ - public void exportSVG() { - // Create and display a file saving dialog - final JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle(messageBundle.getString("viewer.dialog.exportSVG.title")); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - fileChooser.addChoosableFileFilter(FileExtensionUtils.getSVGFileFilter()); - if (ViewModel.getDefaultFile() != null) { - fileChooser.setCurrentDirectory(ViewModel.getDefaultFile()); - } - // show the dialog - int returnVal = fileChooser.showSaveDialog(viewer); - - if (returnVal == JFileChooser.APPROVE_OPTION) { - final File file = fileChooser.getSelectedFile(); - // make sure file being opened is valid - String extension = FileExtensionUtils.getExtension(file); - if (extension != null) { - if (extension.equals(FileExtensionUtils.svg)) { - final Document doc = document; - final int pageIndex = documentViewController.getCurrentPageIndex(); - - if (statusLabel != null) { - Object[] messageArguments = new Object[]{ - String.valueOf(pageIndex + 1), - file.getName() - }; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.dialog.exportSVG.status.exporting.msg")); - statusLabel.setText(formatter.format(messageArguments)); - } - - SwingWorker worker = new SwingWorker() { - public Object construct() { - // save the file - String error = null; - try { - // It is important to create a UTF-8 encoded file. - OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8"); - SVG.createSVG( - doc, - pageIndex, - out); - out.close(); - } catch (Throwable e) { - error = e.getMessage(); - logger.log(Level.FINE, "Error exporting to SVG"); - } - final String tmpMsg; - // finished message - if (error == null) { - Object[] messageArguments = new Object[]{ - String.valueOf(pageIndex + 1), - file.getName() - }; - MessageFormat formatter = - new MessageFormat( - messageBundle.getString("viewer.dialog.exportSVG.status.exporting.msg")); - tmpMsg = formatter.format(messageArguments); - } - // problem message - else { - Object[] messageArguments = new Object[]{ - String.valueOf(pageIndex + 1), - file.getName(), - error - }; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.dialog.exportSVG.status.error.msg")); - tmpMsg = formatter.format(messageArguments); - } - - Runnable doSwingWork = new Runnable() { - public void run() { - if (statusLabel != null) - statusLabel.setText(tmpMsg); - } - }; - SwingUtilities.invokeLater(doSwingWork); - return null; - } - }; - worker.setThreadPriority(Thread.MIN_PRIORITY); - worker.start(); - } else { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.exportSVG.exportError.title", - "viewer.dialog.exportSVG.exportError.msg", - file.getName()); - } - // save the default directory - ViewModel.setDefaultFile(file); - } else { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.exportSVG.noExtensionError.title", - "viewer.dialog.exportSVG.noExtensionError.msg"); - exportSVG(); - } - } - } - - /** - * If there is a WindowManagementCallback in place, then this will invoke its quit method - * - * @see #setWindowManagementCallback - * @see #getWindowManagementCallback - */ - public boolean saveChangesDialog() { - // check if document changes have been made, if so ask the user if they - // want to save the changes. - if (document != null) { - boolean documentChanges = document.getStateManager().isChanged(); - if (documentChanges && Document.foundIncrementalUpdater) { - - Object[] colorArgument = new Object[]{document.getDocumentOrigin()}; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.dialog.saveOnClose.noUpdates.msg")); - String dialogMessage = formatter.format(colorArgument); - - int res = JOptionPane.showConfirmDialog(viewer, - dialogMessage, - messageBundle.getString("viewer.dialog.saveOnClose.noUpdates.title"), - JOptionPane.YES_NO_CANCEL_OPTION); - if (res == JOptionPane.OK_OPTION) { - // start save as process. - saveFile(); - // fall though and close window. - } else if (res == JOptionPane.NO_OPTION) { - // nothing to do, just fall through. - } else if (res == JOptionPane.CANCEL_OPTION) { - // supress the close action - return true; - } - } - } - return false; - } - - /** - * Flips the visibility of the toolbar to the opposite of what it was - * - * @see #setToolBarVisible(boolean) - */ - public void toggleToolBarVisibility() { - if (completeToolBar != null) - setToolBarVisible(!completeToolBar.isVisible()); - } - - /** - * Sets the visibility of the toolbar - * - * @param show The new visibility of the toolbar - */ - public void setToolBarVisible(boolean show) { - if (completeToolBar != null) - completeToolBar.setVisible(show); - reflectStateInComponents(); - } - - /** - * Show the About dialog. Subclasses may override this method to show an - * alternate About dialog - */ - public void showAboutDialog() { - // Added to swing thread to ensure it shows up on top of main - // browser window - Runnable doSwingWork = new Runnable() { - public void run() { - AboutDialog ad = new AboutDialog(viewer, messageBundle, true, - AboutDialog.OK, AboutDialog.NO_TIMER); - ad.setVisible(true); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } - - /** - * Show the permissions set in the PDF file's Document, as relates to encryption, - * altering, or extracting information from, the Document - */ - public void showDocumentPermissionsDialog() { - PermissionsDialog pd = new PermissionsDialog( - viewer, document, messageBundle); - pd.setVisible(true); - } - - /** - * Show information about the PDF file's Document, such as the title, - * subject, author, keywords, creator, producer, creation date, and - * last modification date - */ - public void showDocumentInformationDialog() { - DocumentInformationDialog did = - new DocumentInformationDialog(viewer, document, messageBundle); - did.setVisible(true); - } - - /** - * Show a print setup dialog, to alter the ViewerModel's PageFormat - * - * @see ViewModel - */ - public void showPrintSetupDialog() { - PrintHelper printHelper = viewModel.getPrintHelper(); - // create a new print helper for this document instance - if (printHelper == null) { - MediaSizeName mediaSizeName = loadDefaultPrinterProperties(); - // create the new print help - printHelper = new PrintHelper(documentViewController.getViewContainer(), - getPageTree(), documentViewController.getRotation(), mediaSizeName, - PrintQuality.NORMAL); - } - // reuse previous print attributes if they exist. - else { - printHelper = new PrintHelper(documentViewController.getViewContainer(), - getPageTree(), documentViewController.getRotation(), - printHelper.getDocAttributeSet(), - printHelper.getPrintRequestAttributeSet()); - } - viewModel.setPrintHelper(printHelper); - viewModel.getPrintHelper().showPrintSetupDialog(); - // save new printer attributes to properties - savePrinterProperties(printHelper); - } - - /** - * Sets the default MediaSizeName and creates an new instance of the - * the PrintHelp with the new media size. The media size is also - * persisted to the PropertiesManager. - *

      - * Note: this method should only be called after a valid file or - * file stream has been loaded by the controller otherwise a null pointer - * will result. - * - * @param mediaSize MediaSizeName constant of paper size to print to. - */ - public void setPrintDefaultMediaSizeName(MediaSizeName mediaSize) { - PrintHelper printHelper = new PrintHelper( - documentViewController.getViewContainer(), getPageTree(), - documentViewController.getRotation(), - mediaSize, - PrintQuality.NORMAL); - viewModel.setPrintHelper(printHelper); - // save new printer attributes to properties - savePrinterProperties(printHelper); - } - - /** - * @param withDialog If should show a print dialog before starting to print - */ - public void print(final boolean withDialog) { - if (printMenuItem != null) { - printMenuItem.setEnabled(false); - } - if (printButton != null) { - printButton.setEnabled(false); - } - - Runnable runner = new Runnable() { - public void run() { - initialisePrinting(withDialog); - } - }; - Thread t = new Thread(runner); - t.setPriority(Thread.MIN_PRIORITY); - t.start(); - } - - /** - * If the withDialog parameter is true, show a print dialog, - * defaulted to print all pages. If the click Ok, then print the page range - * they have specified, else if they clicked Cancel, then abort the printing - *

      - * If the withDialog parameter is false, then print all pages of - * the PDF Document without showing and print dialogs - * - * @param withDialog If should show a print dialog before starting to print - */ - private void initialisePrinting(final boolean withDialog) { - boolean canPrint = havePermissionToPrint(); - if (!canPrint) { - reenablePrintUI(); - return; - } - // create a new print helper, one-to-one with document, make sure that - // previous printer properties are preserved. default values listed - // below are for NA_letter in millimeters. - PrintHelper printHelper = viewModel.getPrintHelper(); - if (printHelper == null) { - MediaSizeName mediaSizeName = loadDefaultPrinterProperties(); - // create the new print help - printHelper = new PrintHelper(documentViewController.getViewContainer(), - getPageTree(), documentViewController.getRotation(), - mediaSizeName, PrintQuality.NORMAL); - } else { - printHelper = new PrintHelper(documentViewController.getViewContainer(), - getPageTree(), documentViewController.getRotation(), - printHelper.getDocAttributeSet(), - printHelper.getPrintRequestAttributeSet()); - } - viewModel.setPrintHelper(printHelper); - - // set the printer to show a print dialog - canPrint = printHelper.setupPrintService( - 0, - document.getNumberOfPages() - 1, - viewModel.getPrintCopies(), // default number of copies. - viewModel.isShrinkToPrintableArea(), // shrink to printable area - withDialog // show print dialogl - ); - // save new printer attributes to properties - savePrinterProperties(printHelper); - // if user cancelled the print job from the dialog, don't start printing - // in the background. - if (!canPrint) { - reenablePrintUI(); - return; - } - startBackgroundPrinting(printHelper); - } - - /** - * Loads/set the media size name derived from the properties manager. - * Otherwise a default paper size of NA Letter is returned - * - * @return a MediaSizeName given the conditions above. - */ - private MediaSizeName loadDefaultPrinterProperties() { - int printMediaUnit = - PropertiesManager.checkAndStoreIntegerProperty( - propertiesManager, - PropertiesManager.PROPERTY_PRINT_MEDIA_SIZE_UNIT, - 1000); - double printMediaWidth = - PropertiesManager.checkAndStoreDoubleProperty( - propertiesManager, - PropertiesManager.PROPERTY_PRINT_MEDIA_SIZE_WIDTH, - 215.9); - double printMediaHeight = - PropertiesManager.checkAndStoreDoubleProperty( - propertiesManager, - PropertiesManager.PROPERTY_PRINT_MEDIA_SIZE_HEIGHT, - 279.4); - // get the closed matching media name. - return MediaSize.findMedia((float) printMediaWidth, - (float) printMediaHeight, - printMediaUnit); - } - - /** - * Utility that tries to save the state of the currently set MediaSize. - * The width height and unit values are written to the the propertiesManager. - * When the Viewer RI is exited the properites file is wrtten to disk. - * - * @param printHelper instance of the open documents print helper. - */ - private void savePrinterProperties(PrintHelper printHelper) { - PrintRequestAttributeSet printRequestAttributeSet = - printHelper.getPrintRequestAttributeSet(); - - Object printAttributeSet = printRequestAttributeSet.get(Media.class); - - if (propertiesManager != null && - printAttributeSet instanceof MediaSizeName) { - MediaSizeName paper = (MediaSizeName) printAttributeSet; - MediaSize mediaSize = MediaSize.getMediaSizeForName(paper); - // write out the new page size property values. - int printMediaUnit = MediaSize.MM; - propertiesManager.set( - PropertiesManager.PROPERTY_PRINT_MEDIA_SIZE_UNIT, - String.valueOf(printMediaUnit)); - double printMediaWidth = mediaSize.getX(printMediaUnit); - propertiesManager.set( - PropertiesManager.PROPERTY_PRINT_MEDIA_SIZE_WIDTH, - String.valueOf(printMediaWidth)); - double printMediaHeight = mediaSize.getY(printMediaUnit); - propertiesManager.set( - PropertiesManager.PROPERTY_PRINT_MEDIA_SIZE_HEIGHT, - String.valueOf(printMediaHeight)); - } - } - - private void reenablePrintUI() { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - // enable print UI controls. - if (printMenuItem != null) { - printMenuItem.setEnabled(true); - } - if (printButton != null) { - printButton.setEnabled(true); - } - } - }); - } - - /** - * Utility method to setup a printer job to run as a background process. - * - * @param printHelper a PrintHelper object which is already setup and ready - * to be printed to. - */ - private void startBackgroundPrinting(final PrintHelper printHelper) { - // Create the ProgressMonitor in the Swing thread - SwingUtilities.invokeLater(new Runnable() { - public void run() { - // launch progress dialog - printProgressMonitor = new ProgressMonitor(viewer, - messageBundle.getString("viewer.dialog.printing.status.start.msg"), - "", 0, printHelper.getNumberOfPages()); - } - }); - - final Thread printingThread = Thread.currentThread(); - - // create background printer job - final PrinterTask printerTask = new PrinterTask(printHelper); - // create activity monitor - printActivityMonitor = new Timer(500, - new ActionListener() { - public void actionPerformed(ActionEvent event) { - - int limit = printHelper.getNumberOfPages(); - int current = printHelper.getCurrentPage(); - // update progress and label - printProgressMonitor.setProgress(current); - - // progress bar for printing - Object[] messageArguments = new Object[]{ - String.valueOf(current), - String.valueOf(limit) - }; - MessageFormat formatter = - new MessageFormat( - messageBundle.getString("viewer.dialog.printing.status.progress.msg")); - printProgressMonitor.setNote(formatter.format(messageArguments)); - - // check for job completed or cancelled. - if (!printingThread.isAlive() || printProgressMonitor.isCanceled()) { - // stop the timers, monitors and thread. - printProgressMonitor.close(); - printActivityMonitor.stop(); - printerTask.cancel(); - // enable print UI controls. - if (printMenuItem != null) { - printMenuItem.setEnabled(true); - } - if (printButton != null) { - printButton.setEnabled(true); - } - } - } - }); - // start the timer. - printActivityMonitor.start(); - - // start print job - printerTask.run(); - } - - - /** - * Takes the page number that the user has typed into the text field, - * converts it into a page index, and then displays that page - */ - public void showPageFromTextField() { - String ob = currentPageNumberTextField.getText(); - if (ob != null) { - try { - int pageIndex = Integer.parseInt(ob) - 1; - showPage(pageIndex); - } catch (NumberFormatException nfe) { - logger.log(Level.FINE, "Error converting page number."); - } - } - } - - /** - * When the user selects an OutlineItem from the Outlines (Bookmarks) JTree, - * this displays the relevant target portion of the PDF Document - */ - public void followOutlineItem(OutlineItem o) { - if (o == null) - return; - int oldTool = getDocumentViewToolMode(); - try { - - // set hour glass - outlinesTree.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - - // capture the action if no destination is found and point to the - // actions destination information - Destination dest = o.getDest(); - if (o.getAction() != null) { - Action action = o.getAction(); - if (action instanceof GoToAction) { - dest = ((GoToAction) action).getDestination(); - } else if (action instanceof URIAction) { - BareBonesBrowserLaunch.openURL( - ((URIAction) action).getURI()); - } else { - Library library = action.getLibrary(); - HashMap entries = action.getEntries(); - dest = new Destination(library, library.getObject(entries, Destination.D_KEY)); - } - } else if (dest.getNamedDestination() != null) { - // building the namedDestination tree can be very time consuming, so we need - // update the icons accordingly. - NamedDestinations namedDestinations = document.getCatalog().getDestinations(); - if (namedDestinations != null) { - dest = namedDestinations.getDestination(dest.getNamedDestination()); - } - } - - // Process the destination information - if (dest == null) - return; - - // let the document view controller resolve the destination - documentViewController.setDestinationTarget(dest); - } finally { - // set the icon back to the pointer - setDisplayTool(oldTool); - outlinesTree.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - } - - // Utility method which alows copy or move drag actions - private boolean isDragAcceptable(DropTargetDragEvent event) { - // check to make sure that we only except the copy action - return (event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0; - } - - // Utility method which allows copy or move drop actions - private boolean isDropAcceptable(DropTargetDropEvent event) { - // check to make sure that we only except the copy action - return (event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0; - } - - /** - * Increases the current page visualization zoom factor by 20%. - */ - public void zoomIn() { - - // zoom in the view - documentViewController.setZoomIn(); - -// doCommonZoomUIUpdates(); - } - - /** - * Decreases the current page visualization zoom factor by 20%. - */ - public void zoomOut() { - documentViewController.setZoomOut(); -// doCommonZoomUIUpdates(); - } - - /** - * Zoom to a new zoom level, without centering on any new specific point - * - * @param zoom zoom value passed to view controller. - */ - public void setZoom(float zoom) { - documentViewController.setZoom(zoom); - } - - public void doCommonZoomUIUpdates(boolean becauseOfValidFitMode) { - // update gui - reflectZoomInZoomComboBox(); // Might change fit value - if (!becauseOfValidFitMode) - setPageFitMode(DocumentViewController.PAGE_FIT_NONE, false); - } - - /** - * Returns tree if there is a current page associated with this controller. - * - * @return true if their is a current page, otherwise false. - */ - public boolean isCurrentPage() { - PageTree pageTree = getPageTree(); - if (pageTree == null) - return false; - Page page = pageTree.getPage(documentViewController.getCurrentPageIndex()); - return page != null; - } - - /** - * Gives access to the currently openned Document's Catalog's PageTree - * - * @return PageTree - */ - public PageTree getPageTree() { - if (document == null) - return null; - return document.getPageTree(); - } - - /** - * Sets the ViewerModel's current page index, and updates the display - * to show the newly selected page - * - * @param nPage Index of the Page to show - * @see org.icepdf.ri.common.views.DocumentViewControllerImpl#setCurrentPageIndex - */ - public void showPage(int nPage) { - if (nPage >= 0 && nPage < getPageTree().getNumberOfPages()) { - documentViewController.setCurrentPageIndex(nPage); - updateDocumentView(); - } - } - - /** - * Adds delta to the ViewerModel's current page index, and updates the display - * to show the newly selected page. A positive delta indicates moving to later pages, - * and a negative delta would move to a previous page - * - * @param delta Signed integer that's added to the current page index - * @see org.icepdf.ri.common.views.DocumentViewControllerImpl#getCurrentPageIndex - * @see org.icepdf.ri.common.views.DocumentViewControllerImpl#setCurrentPageIndex - */ - public void goToDeltaPage(int delta) { - int currPage = documentViewController.getCurrentPageIndex(); - int nPage = currPage + delta; - int totalPages = getPageTree().getNumberOfPages(); - if (totalPages == 0) - return; - if (nPage >= totalPages) - nPage = totalPages - 1; - if (nPage < 0) - nPage = 0; - if (nPage != currPage) { - documentViewController.setCurrentPageIndex(nPage); - updateDocumentView(); - } - } - - public void updateDocumentView() { - - if (disposed) - return; - int oldTool = getDocumentViewToolMode(); - try { - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - - reflectPageChangeInComponents(); - - - PageTree pageTree = getPageTree(); - - if (currentPageNumberTextField != null) - currentPageNumberTextField.setText(Integer.toString(documentViewController.getCurrentPageDisplayValue())); - if (numberOfPagesLabel != null) { - - if (pageTree != null) { - Object[] messageArguments = new Object[]{String.valueOf(pageTree.getNumberOfPages())}; - MessageFormat formatter = - new MessageFormat( - messageBundle.getString("viewer.toolbar.pageIndicator")); - String numberOfPages = formatter.format(messageArguments); - - numberOfPagesLabel.setText(numberOfPages); - } - } - - if (statusLabel != null) { - if (pageTree != null) { - // progress bar for printing - Object[] messageArguments = new Object[]{ - String.valueOf(documentViewController.getCurrentPageDisplayValue()), - String.valueOf(pageTree.getNumberOfPages()) - }; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.statusbar.currentPage")); - statusLabel.setText(formatter.format(messageArguments)); - } - } - } catch (Exception e) { - logger.log(Level.FINE, "Error updating page view.", e); - } finally { - setDisplayTool(oldTool); - } - } - - /** - * Rotates the page visualization by 90 degrees in a counter-clockwise - * direction. - */ - public void rotateLeft() { - documentViewController.setRotateLeft(); - // rest fit page mode, if any - setPageFitMode(documentViewController.getFitMode(), true); - } - - /** - * Rotates the page visualization by 90 degrees in a clockwise - * direction. - */ - public void rotateRight() { - documentViewController.setRotateRight(); - // rest fit page mode, if any - setPageFitMode(documentViewController.getFitMode(), true); - } - - - public boolean isDocumentFitMode(final int fitMode) { - return (documentViewController.getFitMode() == fitMode); - } - - public boolean isDocumentViewMode(final int viewMode) { - return (documentViewController.getViewMode() == viewMode); - } - - public void setPageViewSinglePageConButton(JToggleButton btn) { - singlePageViewContinuousButton = btn; - btn.addItemListener(this); - } - - public void setPageViewFacingPageConButton(JToggleButton btn) { - facingPageViewContinuousButton = btn; - btn.addItemListener(this); - } - - public void setPageViewSinglePageNonConButton(JToggleButton btn) { - singlePageViewNonContinuousButton = btn; - btn.addItemListener(this); - } - - public void setPageViewFacingPageNonConButton(JToggleButton btn) { - facingPageViewNonContinuousButton = btn; - btn.addItemListener(this); - } - - /** - * Set the ViewerModel's fit setting to fit the whole page, and update the display - */ - public void setPageFitMode(final int fitMode, boolean refresh) { - - if (!refresh && documentViewController.getFitMode() == fitMode) { - return; - } - - documentViewController.setFitMode(fitMode); - - // update button state. - reflectZoomInZoomComboBox(); - reflectFitInFitButtons(); - } - - public void setPageViewMode(final int viewMode, boolean refresh) { - - if (!refresh && documentViewController.getViewMode() == viewMode) { - return; - } - - documentViewController.setViewType(viewMode); - - // update button state. - reflectDocumentViewModeInButtons(); - reflectFitInFitButtons(); - } - - public void setDocumentToolMode(final int toolType) { - // nothing to do tool should already be setup. - if (documentViewController.isToolModeSelected(toolType)) - return; - - // set the tool mode - documentViewController.setToolMode(toolType); - - // update the button state - reflectToolInToolButtons(); - } - - /** - * If the utility pane is currently visible - * - * @return true if pane is visilbe false otherwise. - */ - public boolean isUtilityPaneVisible() { - return (utilityTabbedPane != null) && utilityTabbedPane.isVisible(); - } - - /** - * Makes the component visible or invisible. - * - * @param visible true to make the component visible; false to make it - * invisible. - */ - public void setUtilityPaneVisible(boolean visible) { - if (utilityTabbedPane != null) { - utilityTabbedPane.setVisible(visible); - } - if (utilityAndDocumentSplitPane != null) { - if (visible) { - // use the last split pane value. - utilityAndDocumentSplitPane.setDividerLocation( - utilityAndDocumentSplitPaneLastDividerLocation); - utilityAndDocumentSplitPane.setDividerSize(8); - } else { - // if we're hiding the panel then we grab the last know value - // and set the width to zero or invisible. - int divLoc = utilityAndDocumentSplitPane.getDividerLocation(); - if (divLoc > 5) { - utilityAndDocumentSplitPaneLastDividerLocation = divLoc; - } - utilityAndDocumentSplitPane.setDividerSize(0); - } - } - reflectStateInComponents(); - } - - /** - * Set the form highlight mode for the viewer. - * - * @param visible true enables the highlight mode, otherwise; false. - */ - private void setFormHighlightVisible(boolean visible) { - viewModel.setIsWidgetAnnotationHighlight(visible); - - // update annotation state for highlight - document.setFormHighlight(viewModel.isWidgetAnnotationHighlight()); - - // repaint the page. - ((AbstractDocumentView) documentViewController.getDocumentView()).repaint(); - } - - /** - * Flips the visibility of the utility pane to the opposite of what it was - * - * @see #setUtilityPaneVisible(boolean) - */ - public void toggleUtilityPaneVisibility() { - setUtilityPaneVisible(!isUtilityPaneVisible()); - } - - /** - * Flips the visibility of the form highlight functionality ot hte opposite of what it was. - */ - public void toggleFormHighlight() { - viewModel.setIsWidgetAnnotationHighlight(!viewModel.isWidgetAnnotationHighlight()); - // write the property for next viewing. - propertiesManager.setBoolean(PropertiesManager.PROPERTY_VIEWPREF_FORM_HIGHLIGHT, - viewModel.isWidgetAnnotationHighlight()); - reflectFormHighlightButtons(); - - setFormHighlightVisible(viewModel.isWidgetAnnotationHighlight()); - } - - /** - * Method to select the currently visible tab in the utility pane - * Because tabs can be hidden via the properties file, we'll want to check first - * whether the desired panel even exists - * - * @param comp to select - * @return true on successful selection - */ - protected boolean safelySelectUtilityPanel(Component comp) { - if ((utilityTabbedPane != null) && (comp != null)) { - if (utilityTabbedPane.indexOfComponent(comp) > -1) { - utilityTabbedPane.setSelectedComponent(comp); - - return true; - } - } - - return false; - } - - /** - * Make the Search pane visible, and if necessary, the utility pane that encloses it - * - * @see #setUtilityPaneVisible(boolean) - */ - public void showSearchPanel() { - if (utilityTabbedPane != null && searchPanel != null) { - // make sure the utility pane is visible - if (!utilityTabbedPane.isVisible()){ - setUtilityPaneVisible(true); - } - - // if utility pane is shown then select the search tab and request focus - if (isUtilityPaneVisible()) { - if (utilityTabbedPane.getSelectedComponent() != searchPanel) { - // select the search panel - safelySelectUtilityPanel(searchPanel); - } - - // request focus - searchPanel.requestFocus(); - } - } - } - - /** - * Make the Annotation Link Panel visible, and if necessary, the utility pane that encloses it - * - * @param selectedAnnotation the annotation to show in the panel - * @see #setUtilityPaneVisible(boolean) - */ - public void showAnnotationPanel(AnnotationComponent selectedAnnotation) { - if (utilityTabbedPane != null && annotationPanel != null) { - // Pass the selected annotation to the link panel - if (selectedAnnotation != null) { - annotationPanel.setEnabled(true); - annotationPanel.setAnnotationComponent(selectedAnnotation); - } - setUtilityPaneVisible(true); - - // select the annotationPanel tab - if (utilityTabbedPane.getSelectedComponent() != annotationPanel) { - safelySelectUtilityPanel(annotationPanel); - } - - } - } - - /** - * Show a dialog, listing every page in the PDF Document, for the user - * to select which page to show. - * - * @see #showPage(int) - */ - public void showPageSelectionDialog() { - int numPages = getPageTree().getNumberOfPages(); - Object[] s = new Object[numPages]; - for (int i = 0; i < numPages; i++) { - s[i] = Integer.toString(i + 1); - } - Object initialSelection = s[documentViewController.getCurrentPageIndex()]; - Object ob = JOptionPane.showInputDialog( - viewer, - messageBundle.getString("viewer.dialog.goToPage.description.label"), - messageBundle.getString("viewer.dialog.goToPage.title"), - JOptionPane.QUESTION_MESSAGE, - null, - s, - initialSelection); - if (ob != null) { - try { - int pageIndex = Integer.parseInt(ob.toString()) - 1; - showPage(pageIndex); - } catch (NumberFormatException nfe) { - logger.log(Level.FINE, "Error selecting page number."); - } - } - } - - /** - * Method to try to read any ViewerPreferences present in the document, and apply them - * Otherwise we will try to check the properties file for any overriding to these values - * - * @param catalog to lookup view preferences from - * @param propertiesManager to check properties in - */ - protected void applyViewerPreferences(Catalog catalog, PropertiesManager propertiesManager) { - if (catalog == null) { - return; - } - - ViewerPreferences viewerPref = catalog.getViewerPreferences(); - - // Hide the toolbar? - if ((viewerPref != null) && (viewerPref.hasHideToolbar())) { - if (viewerPref.getHideToolbar()) { - if (completeToolBar != null) { - completeToolBar.setVisible(false); - } - } - } else { - if (completeToolBar != null) { - completeToolBar.setVisible( - !PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_VIEWPREF_HIDETOOLBAR, - false)); - } - } - - // Hide the menubar? - if ((viewerPref != null) && (viewerPref.hasHideMenubar())) { - if (viewerPref.getHideMenubar()) { - if ((viewer != null) && (viewer.getJMenuBar() != null)) { - viewer.getJMenuBar().setVisible(false); - } - } - } else { - if ((viewer != null) && (viewer.getJMenuBar() != null)) { - viewer.getJMenuBar().setVisible( - !PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_VIEWPREF_HIDEMENUBAR, - false)); - } - } - - // Fit the GUI frame to the size of the document? - if ((viewerPref != null) && (viewerPref.hasFitWindow())) { - if (viewerPref.getFitWindow()) { - if (viewer != null) { - viewer.setSize( - documentViewController.getDocumentView().getDocumentSize()); - } - } - } else { - if ((PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_VIEWPREF_FITWINDOW, - false)) && (viewer != null)) { - viewer.setSize( - documentViewController.getDocumentView().getDocumentSize()); - } - } - } - - /** - * Gives access to this SwingController's ViewerModel - * - * @return The SwingController's ViewerModel - * @see ViewModel - */ - public ViewModel getViewModel() { - return viewModel; - } - - - // - // Controller interface - // - - /** - * A Document is the root of the object hierarchy, giving access - * to the contents of a PDF file. - * Significantly: getDocument().getCatalog().getPageTree().getPage(int pageIndex) - * gives access to each Page, so that it might be drawn. - * - * @return Document root of the PDF file - */ - public Document getDocument() { - return document; - } - - /** - * When viewing a PDF file, one or more pages may be viewed at - * a single time, but this is the single page which is most - * predominantly being displayed. - * - * @return The zero-based index of the current Page being displayed - */ - public int getCurrentPageNumber() { - return documentViewController.getCurrentPageIndex(); - } - - /** - * Each Page may have its own rotation, but on top of that, the user - * may select to have the Page further rotated, by 0, 90, 180, 270 degrees - * - * @return The user's requested rotation - */ - public float getUserRotation() { - return documentViewController.getRotation(); - } - - /** - * The Page being shown may be zoomed in or out, to show more detail, - * or provide an overview. - * - * @return The user's requested zoom - */ - public float getUserZoom() { - return documentViewController.getZoom(); - } - - - // - // ActionListener interface - // - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void actionPerformed(ActionEvent event) { - Object source = event.getSource(); - if (source == null) - return; - - boolean cancelSetFocus = false; - - try { - if (source == openFileMenuItem || source == openFileButton) { - Runnable doSwingWork = new Runnable() { - public void run() { - openFile(); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == openURLMenuItem) { - Runnable doSwingWork = new Runnable() { - public void run() { - openURL(); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == closeMenuItem) { - boolean isCanceled = saveChangesDialog(); - if (!isCanceled) { - closeDocument(); - } - } else if (source == saveAsFileMenuItem || source == saveAsFileButton) { - Runnable doSwingWork = new Runnable() { - public void run() { - saveFile(); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == exportTextMenuItem) { - Runnable doSwingWork = new Runnable() { - public void run() { - exportText(); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == exportSVGMenuItem) { - Runnable doSwingWork = new Runnable() { - public void run() { - exportSVG(); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == exitMenuItem) { - boolean isCanceled = saveChangesDialog(); - if (!isCanceled && windowManagementCallback != null) { - windowManagementCallback.disposeWindow(this, viewer, null); - } - } else if (source == showHideToolBarMenuItem) { - toggleToolBarVisibility(); - } else if (source == minimiseAllMenuItem) { - Runnable doSwingWork = new Runnable() { - public void run() { - SwingController sc = SwingController.this; - if (sc.getWindowManagementCallback() != null) - sc.getWindowManagementCallback().minimiseAllWindows(); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == bringAllToFrontMenuItem) { - Runnable doSwingWork = new Runnable() { - public void run() { - SwingController sc = SwingController.this; - if (sc.getWindowManagementCallback() != null) - sc.getWindowManagementCallback().bringAllWindowsToFront(sc); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (windowListMenuItems != null && windowListMenuItems.contains(source)) { - final int index = windowListMenuItems.indexOf(source); - Runnable doSwingWork = new Runnable() { - public void run() { - SwingController sc = SwingController.this; - if (sc.getWindowManagementCallback() != null) { - sc.getWindowManagementCallback().bringWindowToFront(index); - } - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == aboutMenuItem) { - showAboutDialog(); - } else if (source == fontInformationMenuItem) { - new FontDialog(viewer, this, true).setVisible(true); - } else if (document != null) { - // get document previous icon - int documentIcon = getDocumentViewToolMode(); - try { - // set cursor for document view - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - - if (source == permissionsMenuItem) { - Runnable doSwingWork = new Runnable() { - public void run() { - showDocumentPermissionsDialog(); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == informationMenuItem) { - Runnable doSwingWork = new Runnable() { - public void run() { - showDocumentInformationDialog(); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == printSetupMenuItem) { - Runnable doSwingWork = new Runnable() { - public void run() { - showPrintSetupDialog(); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } else if (source == printMenuItem) { - print(true); - } else if (source == printButton) { - print(true); // Used to be 'false' PDF-86 - } else if (source == undoMenuItem) { - documentViewController.undo(); - // refresh undo buttons. - reflectUndoCommands(); - } else if (source == redoMenuItem) { - documentViewController.redo(); - reflectUndoCommands(); - } else if (source == deleteMenuItem) { - documentViewController.deleteCurrentAnnotation(); - reflectUndoCommands(); - } else if (source == copyMenuItem) { - if (document != null && - havePermissionToExtractContent() && - !(documentViewController.getDocumentViewModel().isSelectAll() && - document.getNumberOfPages() > MAX_SELECT_ALL_PAGE_COUNT)) { - // get the text. - StringSelection stringSelection = new StringSelection( - documentViewController.getSelectedText()); - Toolkit.getDefaultToolkit().getSystemClipboard() - .setContents(stringSelection, stringSelection); - } else { - Runnable doSwingWork = new Runnable() { - public void run() { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.information.copyAll.title", - "viewer.dialog.information.copyAll.msg", - MAX_SELECT_ALL_PAGE_COUNT); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } - } else if (source == selectAllMenuItem) { - // check to see how many page are in the document - documentViewController.selectAllText(); - } else if (source == deselectAllMenuItem) { - documentViewController.clearSelectedText(); - } else if (source == fitActualSizeMenuItem) { - // Clicking only seems to invoke an itemStateChanged() event, - // so this is probably redundant - setPageFitMode(DocumentViewController.PAGE_FIT_ACTUAL_SIZE, false); - } else if (source == fitPageMenuItem) { - // Clicking only seems to invoke an itemStateChanged() event - // so this is probably redundant - setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT, false); - } else if (source == fitWidthMenuItem) { - // Clicking only seems to invoke an itemStateChanged() event - // so this is probably redundant - setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_WIDTH, false); - } else if (source == zoomInMenuItem || source == zoomInButton) { - zoomIn(); - } else if (source == zoomOutMenuItem || source == zoomOutButton) { - zoomOut(); - } else if (source == rotateLeftMenuItem || source == rotateLeftButton) { - rotateLeft(); - } else if (source == rotateRightMenuItem || source == rotateRightButton) { - rotateRight(); - } else if (source == showHideUtilityPaneMenuItem || source == showHideUtilityPaneButton) { - toggleUtilityPaneVisibility(); - } else if (source == formHighlightButton) { - toggleFormHighlight(); - } else if (source == firstPageMenuItem || source == firstPageButton) { - showPage(0); - } else if (source == previousPageMenuItem || source == previousPageButton) { - DocumentView documentView = documentViewController.getDocumentView(); - goToDeltaPage(-documentView.getPreviousPageIncrement()); - } else if (source == nextPageMenuItem || source == nextPageButton) { - DocumentView documentView = documentViewController.getDocumentView(); - goToDeltaPage(documentView.getNextPageIncrement()); - } else if (source == lastPageMenuItem || source == lastPageButton) { - showPage(getPageTree().getNumberOfPages() - 1); - } else if (source == searchMenuItem || source == searchButton) { - cancelSetFocus = true; - showSearchPanel(); - } else if (source == goToPageMenuItem) { - showPageSelectionDialog(); - } else if (source == currentPageNumberTextField) { - showPageFromTextField(); - } else { - logger.log(Level.FINE, "Unknown action event: " + source.toString()); - } - } finally { - // set view pane back to previous icon - setDisplayTool(documentIcon); - } - } - } catch (Exception e) { - final Exception f = e; - Runnable doSwingWork = new Runnable() { - public void run() { - org.icepdf.ri.util.Resources.showMessageDialog( - viewer, - JOptionPane.INFORMATION_MESSAGE, - messageBundle, - "viewer.dialog.error.exception.title", - "viewer.dialog.error.exception.msg", - f.getMessage()); - } - }; - SwingUtilities.invokeLater(doSwingWork); - logger.log(Level.FINE, "Error processing action event.", e); - } - - if (!cancelSetFocus) { - // setup focus to ensure page up and page down keys work - documentViewController.requestViewFocusInWindow(); - } - } - - // - // FocusListener interface - // - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void focusGained(FocusEvent e) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void focusLost(FocusEvent e) { - Object src = e.getSource(); - if (src == null) - return; - if (src == currentPageNumberTextField) { - String fieldValue = currentPageNumberTextField.getText(); - String modelValue = Integer.toString(documentViewController.getCurrentPageDisplayValue()); - if (!fieldValue.equals(modelValue)) - currentPageNumberTextField.setText(modelValue); - } - } - - // - // ItemListener interface - // - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void itemStateChanged(ItemEvent e) { - Object source = e.getSource(); - if (source == null) - return; - - boolean doSetFocus = false; - int tool = getDocumentViewToolMode(); - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - try { - if (source == zoomComboBox) { - if (e.getStateChange() == ItemEvent.SELECTED) { - setZoomFromZoomComboBox(); - // Since combo box is an entry component, we don't force focus to the document - } - } else if (source == fitActualSizeButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - setPageFitMode(DocumentViewController.PAGE_FIT_ACTUAL_SIZE, false); - doSetFocus = true; - } - } else if (source == fitHeightButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT, false); - doSetFocus = true; - } - } else if (source == fitWidthButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_WIDTH, false); - doSetFocus = true; - } - } else if (source == fontEngineButton) { - if (e.getStateChange() == ItemEvent.SELECTED || - e.getStateChange() == ItemEvent.DESELECTED) { - // get instance of the font factory - FontFactory.getInstance().toggleAwtFontSubstitution(); - // refresh the document, refresh will happen by the component. - ((AbstractDocumentView)documentViewController.getDocumentView()).firePropertyChange( - PropertyConstants.DOCUMENT_VIEW_DEMO_MODE_CHANGE, false, true); - doSetFocus = true; - } - } - // tool selection - a call to setDocumentToolMode will generate - // the property change even which the view and child components - // will adjust to. - - else if (source == panToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_PAN; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_PAN); - doSetFocus = true; - } - } else if (source == zoomInToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_IN); - doSetFocus = true; - } - } else if (source == zoomDynamicToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_ZOOM_DYNAMIC); - doSetFocus = true; - } - } else if (source == textSelectToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_SELECTION); - doSetFocus = true; - } - } - // annotations selection and creation tools. - else if (source == selectToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_SELECTION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_SELECTION); - showAnnotationPanel(null); - } - } else if (source == linkAnnotationToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINK_ANNOTATION); - } - } else if (source == highlightAnnotationToolButton || - source == highlightAnnotationUtilityToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION); - } - } else if (source == strikeOutAnnotationToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_STRIKEOUT_ANNOTATION); - } - } else if (source == underlineAnnotationToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_UNDERLINE_ANNOTATION); - } - } else if (source == lineAnnotationToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINE_ANNOTATION); - } - } else if (source == lineArrowAnnotationToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_LINE_ARROW_ANNOTATION); - } - } else if (source == squareAnnotationToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_SQUARE_ANNOTATION); - } - } else if (source == circleAnnotationToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_CIRCLE_ANNOTATION); - } - } else if (source == inkAnnotationToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_INK_ANNOTATION); - } - } else if (source == freeTextAnnotationToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_FREE_TEXT_ANNOTATION); - } - } else if (source == textAnnotationToolButton || - source == textAnnotationUtilityToolButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - tool = DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION; - setDocumentToolMode(DocumentViewModelImpl.DISPLAY_TOOL_TEXT_ANNOTATION); - } - } - // page view events, changes the page layout component. - else if (source == facingPageViewNonContinuousButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - setPageViewMode( - DocumentViewControllerImpl.TWO_PAGE_RIGHT_VIEW, - false); - doSetFocus = true; - } - } else if (source == facingPageViewContinuousButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - setPageViewMode( - DocumentViewControllerImpl.TWO_COLUMN_RIGHT_VIEW, - false); - doSetFocus = true; - } - } else if (source == singlePageViewNonContinuousButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - setPageViewMode( - DocumentViewControllerImpl.ONE_PAGE_VIEW, - false); - doSetFocus = true; - } - } else if (source == singlePageViewContinuousButton) { - if (e.getStateChange() == ItemEvent.SELECTED) { - setPageViewMode( - DocumentViewControllerImpl.ONE_COLUMN_VIEW, - false); - doSetFocus = true; - } - } - - if (doSetFocus) { - // setup focus to ensure page up and page down keys work - documentViewController.requestViewFocusInWindow(); - } - - } finally { - setDisplayTool(tool); - } - } - - // - // TreeSelectionListener interface - // - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void valueChanged(TreeSelectionEvent e) { - if (outlinesTree == null) - return; - TreePath treePath = outlinesTree.getSelectionPath(); - if (treePath == null) - return; - OutlineItemTreeNode node = (OutlineItemTreeNode) treePath.getLastPathComponent(); - OutlineItem o = node.getOutlineItem(); - - followOutlineItem(o); - - // return focus so that arrow keys will work on list - outlinesTree.requestFocus(); - } - - - // - // WindowListener interface - // - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void windowActivated(WindowEvent e) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void windowClosed(WindowEvent e) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void windowClosing(WindowEvent e) { - // We have to call dispose() before using the WindowManagementCallback, because the - // WindowManagementCallback may well call System.exit(). If System.exit() is called - // before dispose() closes our temporary files, then they won't be deleted. - // So, we need to temporarily save what we'll need, for our later invocation of - // WindowManagementCallback.disposeWindow(), that dispose() would otherwise trash - WindowManagementCallback wc = windowManagementCallback; - JFrame v = viewer; - - // assign view properties so that they can be saved on close - DocumentViewController viewControl = getDocumentViewController(); - Properties viewProperties = new Properties(); - viewProperties.setProperty(PropertiesManager.PROPERTY_DEFAULT_PAGEFIT, String.valueOf(viewControl.getFitMode())); - viewProperties.setProperty("document.viewtype", String.valueOf(viewControl.getViewMode())); - - // save changes and close window - boolean cancelled = saveChangesDialog(); - if (!cancelled) { - // dispose the document and other resources. - dispose(); - - if (wc != null) { - wc.disposeWindow(this, v, viewProperties); - } - } - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void windowDeactivated(WindowEvent e) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void windowDeiconified(WindowEvent e) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void windowIconified(WindowEvent e) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void windowOpened(WindowEvent e) { - } - - // - // DropTargetListener interface - // - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void dragEnter(DropTargetDragEvent event) { - if (!isDragAcceptable(event)) { - event.rejectDrag(); - } - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void dragOver(DropTargetDragEvent event) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void dropActionChanged(DropTargetDragEvent event) { - if (!isDragAcceptable(event)) { - event.rejectDrag(); - } - } - - /** - * Handle drop event when a user drags and drops one or more files onto the viewer frame. - * - * @param event information about the drag and drop data. - */ - public void drop(DropTargetDropEvent event) { - try { - // check to make sure that event type is ok - if (!isDropAcceptable(event)) { - event.rejectDrop(); - return; - } - // accept the drop action, must do this to proceed - event.acceptDrop(DnDConstants.ACTION_COPY); - Transferable transferable = event.getTransferable(); - DataFlavor[] flavors = transferable.getTransferDataFlavors(); - for (DataFlavor dataFlavor : flavors) { - // Check to see if a file was dropped on the viewer frame - if (dataFlavor.equals(DataFlavor.javaFileListFlavor)) { - List fileList = (List) transferable.getTransferData(dataFlavor); - // load all the files that where dragged - for (Object aFileList : fileList) { - File file = (File) aFileList; - if (file.getName().toLowerCase().endsWith(".pdf")) { - openFileInSomeViewer(file); - ViewModel.setDefaultFile(file); - } - } - } else if (dataFlavor.equals(DataFlavor.stringFlavor)) { - String s = (String) transferable.getTransferData(dataFlavor); - int startIndex = s.toLowerCase().indexOf("http://"); - int endIndex = s.toLowerCase().indexOf(".pdf"); - if (startIndex >= 0 && endIndex >= 0) { - s = s.substring(startIndex, endIndex + 4); - URL url; - try { - url = new URL(s); - openURLInSomeViewer(url); - ViewModel.setDefaultURL(s); - } catch (MalformedURLException e) { - // eat the error - } - } - } - } - event.dropComplete(true); - - } catch (IOException ioe) { - logger.log(Level.FINE, "IO exception during file drop", ioe); - } catch (UnsupportedFlavorException ufe) { - logger.log(Level.FINE, "Drag and drop not supported", ufe); - } - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void dragExit(DropTargetEvent event) { - } - - - // - // KeyListener interface - // - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void keyPressed(KeyEvent e) { - if (document == null) - return; - int c = e.getKeyCode(); - int m = e.getModifiers(); - if ((c == KeyEventConstants.KEY_CODE_SAVE_AS && m == KeyEventConstants.MODIFIER_SAVE_AS) || - (c == KeyEventConstants.KEY_CODE_PRINT_SETUP && m == KeyEventConstants.MODIFIER_PRINT_SETUP) || - (c == KeyEventConstants.KEY_CODE_PRINT && m == KeyEventConstants.MODIFIER_PRINT) || - (c == KeyEventConstants.KEY_CODE_FIT_ACTUAL && m == KeyEventConstants.MODIFIER_FIT_ACTUAL) || - (c == KeyEventConstants.KEY_CODE_FIT_PAGE && m == KeyEventConstants.MODIFIER_FIT_PAGE) || - (c == KeyEventConstants.KEY_CODE_FIT_WIDTH && m == KeyEventConstants.MODIFIER_FIT_WIDTH) || - (c == KeyEventConstants.KEY_CODE_ZOOM_IN && m == KeyEventConstants.MODIFIER_ZOOM_IN) || - (c == KeyEventConstants.KEY_CODE_ZOOM_OUT && m == KeyEventConstants.MODIFIER_ZOOM_OUT) || - (c == KeyEventConstants.KEY_CODE_ROTATE_LEFT && m == KeyEventConstants.MODIFIER_ROTATE_LEFT) || - (c == KeyEventConstants.KEY_CODE_ROTATE_RIGHT && m == KeyEventConstants.MODIFIER_ROTATE_RIGHT) || - (c == KeyEventConstants.KEY_CODE_FIRST_PAGE && m == KeyEventConstants.MODIFIER_FIRST_PAGE) || - (c == KeyEventConstants.KEY_CODE_PREVIOUS_PAGE && m == KeyEventConstants.MODIFIER_PREVIOUS_PAGE) || - (c == KeyEventConstants.KEY_CODE_NEXT_PAGE && m == KeyEventConstants.MODIFIER_NEXT_PAGE) || - (c == KeyEventConstants.KEY_CODE_LAST_PAGE && m == KeyEventConstants.MODIFIER_LAST_PAGE) || - (c == KeyEventConstants.KEY_CODE_SEARCH && m == KeyEventConstants.MODIFIER_SEARCH) || - (c == KeyEventConstants.KEY_CODE_GOTO && m == KeyEventConstants.MODIFIER_GOTO)) { - // get document previous icon - int documentIcon = getDocumentViewToolMode(); - try { - // set cursor for document view - setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - - if (c == KeyEventConstants.KEY_CODE_SAVE_AS && - m == KeyEventConstants.MODIFIER_SAVE_AS) { - saveFile(); - } else if (c == KeyEventConstants.KEY_CODE_PRINT_SETUP && - m == KeyEventConstants.MODIFIER_PRINT_SETUP) { - showPrintSetupDialog(); - } else if (c == KeyEventConstants.KEY_CODE_PRINT && - m == KeyEventConstants.MODIFIER_PRINT) { - print(true); - } else if (c == KeyEventConstants.KEY_CODE_FIT_ACTUAL && - m == KeyEventConstants.MODIFIER_FIT_ACTUAL) { - setPageFitMode(DocumentViewController.PAGE_FIT_ACTUAL_SIZE, false); - } else if (c == KeyEventConstants.KEY_CODE_FIT_PAGE && - m == KeyEventConstants.MODIFIER_FIT_PAGE) { - setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_HEIGHT, false); - } else if (c == KeyEventConstants.KEY_CODE_FIT_WIDTH && - m == KeyEventConstants.MODIFIER_FIT_WIDTH) { - setPageFitMode(DocumentViewController.PAGE_FIT_WINDOW_WIDTH, false); - } else if (c == KeyEventConstants.KEY_CODE_ZOOM_IN && - m == KeyEventConstants.MODIFIER_ZOOM_IN) { - zoomIn(); - } else if (c == KeyEventConstants.KEY_CODE_ZOOM_OUT && - m == KeyEventConstants.MODIFIER_ZOOM_OUT) { - zoomOut(); - } else if (c == KeyEventConstants.KEY_CODE_ROTATE_LEFT && - m == KeyEventConstants.MODIFIER_ROTATE_LEFT) { - rotateLeft(); - } else if (c == KeyEventConstants.KEY_CODE_ROTATE_RIGHT && - m == KeyEventConstants.MODIFIER_ROTATE_RIGHT) { - rotateRight(); - } else if (c == KeyEventConstants.KEY_CODE_FIRST_PAGE && - m == KeyEventConstants.MODIFIER_FIRST_PAGE) { - showPage(0); - } else if (c == KeyEventConstants.KEY_CODE_PREVIOUS_PAGE && - m == KeyEventConstants.MODIFIER_PREVIOUS_PAGE) { - DocumentView documentView = documentViewController.getDocumentView(); - goToDeltaPage(-documentView.getPreviousPageIncrement()); - } else if (c == KeyEventConstants.KEY_CODE_NEXT_PAGE && - m == KeyEventConstants.MODIFIER_NEXT_PAGE) { - DocumentView documentView = documentViewController.getDocumentView(); - goToDeltaPage(documentView.getNextPageIncrement()); - } else if (c == KeyEventConstants.KEY_CODE_LAST_PAGE && - m == KeyEventConstants.MODIFIER_LAST_PAGE) { - showPage(getPageTree().getNumberOfPages() - 1); - } else if (c == KeyEventConstants.KEY_CODE_SEARCH && - m == KeyEventConstants.MODIFIER_SEARCH) { - showSearchPanel(); - } else if (c == KeyEventConstants.KEY_CODE_GOTO && - m == KeyEventConstants.MODIFIER_GOTO) { - showPageSelectionDialog(); - } - } finally { - // set view pain back to previous icon - setDisplayTool(documentIcon); - } - } - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void keyReleased(KeyEvent e) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void keyTyped(KeyEvent e) { - if (currentPageNumberTextField != null && - e.getSource() == currentPageNumberTextField) { - char c = e.getKeyChar(); - if (c == KeyEvent.VK_ESCAPE) { - String fieldValue = currentPageNumberTextField.getText(); - String modelValue = Integer.toString( - documentViewController.getCurrentPageDisplayValue()); - if (!fieldValue.equals(modelValue)) - currentPageNumberTextField.setText(modelValue); - } - } - } - - /** - * Listen for property change events from the page view. This method - * acts like a mediator passing on the new states to the interested parties. - * - * @param evt property change event - */ - public void propertyChange(PropertyChangeEvent evt) { - Object newValue = evt.getNewValue(); - Object oldValue = evt.getOldValue(); - String propertyName = evt.getPropertyName(); - if (propertyName.equals(PropertyConstants.DOCUMENT_CURRENT_PAGE)) { - if (currentPageNumberTextField != null && newValue instanceof Integer) { - updateDocumentView(); - } - } - // text selected, - else if (propertyName.equals(PropertyConstants.TEXT_SELECTED)) { - // enable the copy menu - boolean canExtract = havePermissionToExtractContent(); - setEnabled(copyMenuItem, canExtract); - setEnabled(deselectAllMenuItem, canExtract); - } - // text deselected - else if (propertyName.equals(PropertyConstants.TEXT_DESELECTED)) { - // disable the copy menu - boolean canExtract = havePermissionToExtractContent(); - setEnabled(copyMenuItem, false); - setEnabled(deselectAllMenuItem, false); - setEnabled(selectAllMenuItem, canExtract); - } - // select all - else if (propertyName.equals(PropertyConstants.TEXT_SELECT_ALL)) { - boolean canExtract = havePermissionToExtractContent(); - setEnabled(selectAllMenuItem, false); - setEnabled(deselectAllMenuItem, canExtract); - setEnabled(copyMenuItem, canExtract); - } - // annotation is selected or has focus - else if (propertyName.equals(PropertyConstants.ANNOTATION_SELECTED) || - propertyName.equals(PropertyConstants.ANNOTATION_FOCUS_GAINED)) { - // enable the delete menu - setEnabled(deleteMenuItem, true); - // get the current selected tool, we only care about the select tool or - // link annotation tool. - if (documentViewController.getToolMode() == - DocumentViewModelImpl.DISPLAY_TOOL_SELECTION) { - AnnotationComponent annotationComponent = - (AnnotationComponent) newValue; - if (annotationComponent != null && - annotationComponent.getAnnotation() != null) { - // set the annotationPane with the new annotation component - if (logger.isLoggable(Level.FINE)) { - logger.fine("selected annotation " + annotationComponent); - } - showAnnotationPanel(annotationComponent); - } - } - } - // annotation is deselected - else if (propertyName.equals(PropertyConstants.ANNOTATION_DESELECTED)) { - if (documentViewController.getToolMode() == - DocumentViewModelImpl.DISPLAY_TOOL_SELECTION) { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Deselected current annotation"); - } - // disable the delete menu - setEnabled(deleteMenuItem, false); - if (annotationPanel != null) { - annotationPanel.setEnabled(false); - } - } - } - // annotation bounds have changed. - else if (propertyName.equals(PropertyConstants.ANNOTATION_BOUNDS)) { - if (documentViewController.getToolMode() == - DocumentViewModelImpl.DISPLAY_TOOL_SELECTION) { - AnnotationState oldAnnotationState = (AnnotationState) oldValue; - AnnotationState newAnnotationState = (AnnotationState) newValue; - - // saves the state changes back to the document structure. - newAnnotationState.apply(newAnnotationState); - newAnnotationState.restore(); - - // add new states to care taker implementation. - documentViewController.getDocumentViewModel() - .addMemento(oldAnnotationState, - newAnnotationState); - } - // check to see if undo/redo can be enabled/disabled. - reflectUndoCommands(); - } - // divider has been moved, save the location as it changes. - else if (propertyName.equals(JSplitPane.LAST_DIVIDER_LOCATION_PROPERTY)) { - JSplitPane sourceSplitPane = (JSplitPane) evt.getSource(); - int dividerLocation = (Integer) evt.getNewValue(); - if (sourceSplitPane.getDividerLocation() != dividerLocation) { - if (propertiesManager != null && dividerLocation > 5) { - utilityAndDocumentSplitPaneLastDividerLocation = dividerLocation; - propertiesManager.setInt( - PropertiesManager.PROPERTY_DIVIDER_LOCATION, - utilityAndDocumentSplitPaneLastDividerLocation); - } - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/SwingViewBuilder.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/SwingViewBuilder.java deleted file mode 100644 index 143cb94310..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/SwingViewBuilder.java +++ /dev/null @@ -1,2211 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import apple.dts.samplecode.osxadapter.OSXAdapter; -import org.icepdf.core.util.Defs; -import org.icepdf.ri.common.utility.annotation.AnnotationPanel; -import org.icepdf.ri.common.utility.attachment.AttachmentPanel; -import org.icepdf.ri.common.utility.layers.LayersPanel; -import org.icepdf.ri.common.utility.outline.OutlinesTree; -import org.icepdf.ri.common.utility.search.SearchPanel; -import org.icepdf.ri.common.utility.signatures.SignaturesPanel; -import org.icepdf.ri.common.utility.thumbs.ThumbnailsPanel; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewControllerImpl; -import org.icepdf.ri.images.Images; -import org.icepdf.ri.util.PropertiesManager; - -import javax.swing.*; -import java.awt.*; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      The purpose of this class is to facilitate in the building of user interface components - * that are used to view and interact with PDF Documents.

      - *

      - *

      As such, there are three main scenarios that are covered. - *

        - *
      1. Building a standalone Viewer JFrame that will behave much as a full-featured PDF viewing application. - *
      2. Building an embeddable PDF Viewer JPanel, which can easily be added into any existing client application, - * augmenting its cababilities to include the capacity for viewing PDF Documents. - *
      3. Building a subset of the above, using the various building block methods in this class to construct GUI - * components that provide certain aspects of the overall functionality, and adding those into - * your application as desired. - *

      - *

      - *

      Building a standalone window

      - *

      This is the main entry point for building a JFrame containing all of the graphical user interface - * elements necessary for viewing PDF files.

      - *

      The hierarchy of the methods that are invoked to construct the complete GUI - * is provided below for your reference. - * You may choose to use any of the individual methods to construct a sub-set of the complete - * GUI that meets your specific requirements. This also provides you flexibility in the containers - * that you add the components into and the overall layout of the application, etc.

      - *
      - * public JFrame buildViewerFrame() - *
        - *
      • public JMenuBar buildCompleteMenuBar() - *
          - *
        • public JMenu buildFileMenu() - *
            - *
          • public JMenuItem buildOpenFileMenuItem()
          • - *
          • public JMenuItem buildOpenURLMenuItem()
          • - *
          • public JMenuItem buildCloseMenuItem()
          • - *
          • public JMenuItem buildSaveAsFileMenuItem()
          • - *
          • public JMenuItem buildExportTextMenuItem()
          • - *
          • public JMenuItem buildExportSVGMenuItem()
          • - *
          • public JMenuItem buildPermissionsMenuItem()
          • - *
          • public JMenuItem buildInformationMenuItem()
          • - *
          • public JMenuItem buildPrintSetupMenuItem()
          • - *
          • public JMenuItem buildPrintMenuItem()
          • - *
          • public JMenuItem buildExitMenuItem()
          • - *
          - *
        • - *

          - *

        • public JMenu buildViewMenu() - *
            - *
          • public JMenuItem buildFitActualSizeMenuItem()
          • - *
          • public JMenuItem buildFitPageMenuItem()
          • - *
          • public JMenuItem buildFitWidthMenuItem()
          • - *
          • public JMenuItem buildZoomInMenuItem()
          • - *
          • public JMenuItem buildZoomOutMenuItem()
          • - *
          • public JMenuItem buildRotateLeftMenuItem()
          • - *
          • public JMenuItem buildRotateRightMenuItem()
          • - *
          • public JMenuItem buildShowHideToolBarMenuItem()
          • - *
          • public JMenuItem buildShowHideUtilityPaneMenuItem()
          • - *
          - *
        • - *

          - *

        • public JMenu buildDocumentMenu() - *
            - *
          • public JMenuItem buildFirstPageMenuItem()
          • - *
          • public JMenuItem buildPreviousPageMenuItem()
          • - *
          • public JMenuItem buildNextPageMenuItem()
          • - *
          • public JMenuItem buildLastPageMenuItem()
          • - *
          • public JMenuItem buildSearchMenuItem()
          • - *
          • public JMenuItem buildGoToPageMenuItem()
          • - *
          - *
        • - *

          - *

        • public JMenu buildWindowMenu() - *
            - *
          • public JMenuItem buildMinimiseAllMenuItem()
          • - *
          • public JMenuItem buildBringAllToFrontMenuItem()
          • - *
          • public void buildWindowListMenuItems(JMenu menu)
          • - *
          - *
        • - *

          - *

        • public JMenu buildHelpMenu() - *
            - *
          • public JMenuItem buildAboutMenuItem()
          • - *
          - *
        • - *
        - *
      • - *

        - *

        - *

      • public void buildContents(Container cp, boolean embeddableComponent) - *
          - *

          - *

        • public JToolBar buildCompleteToolBar(boolean embeddableComponent) - *
            - *
          • public JToolBar buildUtilityToolBar(boolean embeddableComponent) - *
              - *
            • public JButton buildOpenFileButton()
            • - *
            • public JButton buildSaveAsFileButton()
            • - *
            • public JButton buildPrintButton()
            • - *
            • public JButton buildSearchButton()
            • - *
            • public JButton buildShowHideUtilityPaneButton()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildPageNavigationToolBar() - *
              - *
            • public JButton buildFirstPageButton()
            • - *
            • public JButton buildPreviousPageButton()
            • - *
            • public JButton buildNextPageButton()
            • - *
            • public JButton buildLastPageButton()
            • - *
            • public JTextField buildCurrentPageNumberTextField()
            • - *
            • public JLabel buildNumberOfPagesLabel()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildZoomToolBar() - *
              - *
            • public JButton buildZoomOutButton()
            • - *
            • public JComboBox buildZoomCombBox()
            • - *
            • public JButton buildZoomInButton()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildFitToolBar() - *
              - *
            • public JToggleButton buildFitActualSizeButton()
            • - *
            • public JToggleButton buildFitPageButton()
            • - *
            • public JToggleButton buildFitWidthButton()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildRotateToolBar() - *
              - *
            • public JButton buildRotateLeftButton()
            • - *
            • public JButton buildRotateRightButton()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildToolToolBar() - *
              - *
            • public JToggleButton buildPanToolButton()
            • - *
            • public JToggleButton buildZoomInToolButton()
            • - *
            • public JToggleButton buildZoomOutToolButton()
            • - *
            - *
          • - *
          - *
        • - *

          - *

          - *

        • public JSplitPane buildUtilityAndDocumentSplitPane(boolean embeddableComponent) - *
            - *
          • public JTabbedPane buildUtilityTabbedPane() - *
              - *
            • public JComponent buildOutlineComponents()
            • - *
            • public SearchPanel buildSearchPanel()
            • - *
            - *
          • - *

            - *

          • public JScrollPane buildDocumentComponents(boolean embeddableComponent)
          • - *
          - *
        • - *

          - *

        • public JLabel buildStatusPanel()
        • - *

          - *

        - *
      • - *

        - *

      - *

      - *

      - *

      Building an embeddable component

      - *

      This is the main entry point for building a JPanel containing all of the GUI elements - * necessary for viewing PDF files. The main differences between this and buildViewerFrame() are: - *

        - *
      • The buildViewerPanel method returns a JPanel which you may then embed anywhere into your GUI - *
      • The JPanel will not contain a menu bar. - *
      • The JPanel uses the sub-set of the GUI components available in buildViewerFrame that are - * suited to an embedded component scenario. - *
      - *

      - *

      - *

      The following hierarchy of methods that are invoked to construct the complete Component GUI - * is provided for your reference. - * You may choose to use any of the individual methods below to construct a sub-set of the complete - * GUI that meets your specific requirements. This also provides you flexibility in the containers - * that you add the components into and the overall layout of the application, etc.

      - *
      - * public JPanel buildViewerPanel() - *
        - *

        - *

      • public void buildContents(Container cp, boolean embeddableComponent) - *
          - *

          - *

        • public JToolBar buildCompleteToolBar(boolean embeddableComponent) - *
            - *
          • public JToolBar buildUtilityToolBar(boolean embeddableComponent) - *
              - *
            • public JButton buildSaveAsFileButton()
            • - *
            • public JButton buildPrintButton()
            • - *
            • public JButton buildSearchButton()
            • - *
            • public JButton buildShowHideUtilityPaneButton()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildPageNavigationToolBar() - *
              - *
            • public JButton buildFirstPageButton()
            • - *
            • public JButton buildPreviousPageButton()
            • - *
            • public JButton buildNextPageButton()
            • - *
            • public JButton buildLastPageButton()
            • - *
            • public JTextField buildCurrentPageNumberTextField()
            • - *
            • public JLabel buildNumberOfPagesLabel()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildZoomToolBar() - *
              - *
            • public JButton buildZoomOutButton()
            • - *
            • public JComboBox buildZoomCombBox()
            • - *
            • public JButton buildZoomInButton()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildFitToolBar() - *
              - *
            • public JToggleButton buildFitActualSizeButton()
            • - *
            • public JToggleButton buildFitPageButton()
            • - *
            • public JToggleButton buildFitWidthButton()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildRotateToolBar() - *
              - *
            • public JButton buildRotateLeftButton()
            • - *
            • public JButton buildRotateRightButton()
            • - *
            - *
          • - *

            - *

          • public JToolBar buildToolToolBar() - *
              - *
            • public JToggleButton buildPanToolButton()
            • - *
            • public JToggleButton buildZoomInToolButton()
            • - *
            • public JToggleButton buildZoomOutToolButton()
            • - *
            - *
          • - *
          - *
        • - *

          - *

          - *

        • public JSplitPane buildUtilityAndDocumentSplitPane(boolean embeddableComponent) - *
            - *
          • public JTabbedPane buildUtilityTabbedPane() - *
              - *
            • public JComponent buildOutlineComponents()
            • - *
            • public SearchPanel buildSearchPanel()
            • - *
            - *
          • - *

            - *

          • public JScrollPane buildDocumentComponents(boolean embeddableComponent)
          • - *
          - *
        • - *

          - *

          - *

        • public JLabel buildStatusPanel()
        • - *

          - *

          - *

        - *
      • - *

        - *

        - *

        - *

      - * - * @author Mark Collette - * @since 2.0 - */ -public class SwingViewBuilder { - - private static final Logger logger = - Logger.getLogger(SwingViewBuilder.class.toString()); - - public static final int TOOL_BAR_STYLE_FLOATING = 1; - public static final int TOOL_BAR_STYLE_FIXED = 2; - protected static final float[] DEFAULT_ZOOM_LEVELS = { - 0.05f, 0.10f, 0.25f, 0.50f, 0.75f, - 1.0f, 1.5f, 2.0f, 3.0f, - 4.0f, 8.0f, 16.0f, 24.0f, 32.0f, 64.0f}; - - protected SwingController viewerController; - protected Font buttonFont; - protected boolean showButtonText; - protected int toolbarStyle; - protected float[] zoomLevels; - protected boolean haveMadeAToolBar; - protected int documentViewType; - protected int documentPageFitMode; - protected ResourceBundle messageBundle; - protected PropertiesManager propertiesManager; - - public static boolean isMacOs; - - private static boolean isDemo; - - static { - isMacOs = (Defs.sysProperty("mrj.version") != null); - // check for demo system property - isDemo = Defs.sysPropertyBoolean("org.icepdf.ri.viewer.demo", false); - } - - /** - * Construct a SwingVewBuilder with all of the default settings - * - * @param c SwingController that will interact with the GUI - */ - public SwingViewBuilder(SwingController c) { - // Use all the defaults - this(c, null, null, false, SwingViewBuilder.TOOL_BAR_STYLE_FIXED, null, - DocumentViewControllerImpl.ONE_PAGE_VIEW, - DocumentViewController.PAGE_FIT_WINDOW_HEIGHT); - } - - /** - * Constructor that accepts a different PropertiesManager and otherwise - * defaults the remaining settings - * - * @param c SwingController that will interact with the GUI - * @param properties PropertiesManager that can customize the UI - */ - public SwingViewBuilder(SwingController c, PropertiesManager properties) { - this(c, properties, null, false, SwingViewBuilder.TOOL_BAR_STYLE_FIXED, null, - DocumentViewControllerImpl.ONE_PAGE_VIEW, - DocumentViewController.PAGE_FIT_WINDOW_HEIGHT); - } - - /** - * Construct a SwingVewBuilder with all of the default settings - * - * @param c SwingController that will interact with the GUI - * @param documentViewType view type to build , single page, single column etc. - * @param documentPageFitMode fit mode to initially load document with. - */ - public SwingViewBuilder(SwingController c, int documentViewType, - int documentPageFitMode) { - // Use all the defaults - this(c, null, null, false, SwingViewBuilder.TOOL_BAR_STYLE_FIXED, - null, documentViewType, documentPageFitMode); - } - - /** - * Construct a SwingVewBuilder with whichever settings you desire - * - * @param c SwingController that will interact with the GUI - */ - public SwingViewBuilder(SwingController c, Font bf, boolean bt, int ts, - float[] zl, final int documentViewType, - final int documentPageFitMode) { - this(c, null, bf, bt, ts, zl, documentViewType, documentPageFitMode); - } - - /** - * Construct a SwingVewBuilder with whichever settings you desire - * - * @param c SwingController that will interact with the GUI - */ - public SwingViewBuilder(SwingController c, PropertiesManager properties, - Font bf, boolean bt, int ts, - float[] zl, final int documentViewType, - final int documentPageFitMode) { - viewerController = c; - - messageBundle = viewerController.getMessageBundle(); - - if (properties != null) { - viewerController.setPropertiesManager(properties); - this.propertiesManager = properties; - } - - // Attempt to override the highlight color from the properties file - overrideHighlightColor(); - - // update View Controller with previewer document page fit and view type info - DocumentViewControllerImpl documentViewController = (DocumentViewControllerImpl) viewerController.getDocumentViewController(); - documentViewController.setDocumentViewType(documentViewType, documentPageFitMode); - - buttonFont = bf; - if (buttonFont == null) - buttonFont = buildButtonFont(); - showButtonText = bt; - toolbarStyle = ts; - zoomLevels = zl; - if (zoomLevels == null) - zoomLevels = DEFAULT_ZOOM_LEVELS; - // set default doc view type, single page, facing page, etc. - this.documentViewType = documentViewType; - // set default view mode type, fit page, fit width, no-fit. - this.documentPageFitMode = documentPageFitMode; - } - - /** - * This is a standard method for creating a standalone JFrame, that would - * behave as a fully functional PDF Viewer application. - * - * @return a JFrame containing the PDF document's current page visualization, - * menu bar, accelerator buttons, and document outline if available. - * @see #buildViewerPanel - */ - public JFrame buildViewerFrame() { - JFrame viewer = new JFrame(); - viewer.setIconImage(new ImageIcon(Images.get("icepdf-app-icon-64x64.png")).getImage()); - viewer.setTitle(messageBundle.getString("viewer.window.title.default")); - viewer.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - JMenuBar menuBar = buildCompleteMenuBar(); - if (menuBar != null) - viewer.setJMenuBar(menuBar); - Container contentPane = viewer.getContentPane(); - buildContents(contentPane, false); - if (viewerController != null) - viewerController.setViewerFrame(viewer); - return viewer; - } - - /** - * Used by the Applet and Pilot RI code to create an embeddable panel - * for viewing PDF files, as opposed to buildViewerFrame(), which makes a - * standalone JFrame - * - * @return JPanel containing the PDF document's current page visualization, - * menu bar, accelerator buttons, and document outline if available. - * @see #buildViewerFrame - */ - public JPanel buildViewerPanel() { - JPanel panel = new JPanel(); - buildContents(panel, true); - return panel; - } - - /** - * The Container will contain the PDF document's current page visualization - * and document outline if available. - * - * @param cp Container in which to put components for viewing PDF documents - */ - public void buildContents(Container cp, boolean embeddableComponent) { - cp.setLayout(new BorderLayout()); - JToolBar toolBar = buildCompleteToolBar(embeddableComponent); - if (toolBar != null) - cp.add(toolBar, BorderLayout.NORTH); - // Builds the utility pane as well as the main document View, important - // code entry point. - JSplitPane utilAndDocSplit = - buildUtilityAndDocumentSplitPane(embeddableComponent); - if (utilAndDocSplit != null) - cp.add(utilAndDocSplit, BorderLayout.CENTER); - JPanel statusPanel = buildStatusPanel(); - if (statusPanel != null) - cp.add(statusPanel, BorderLayout.SOUTH); - } - - - public JMenuBar buildCompleteMenuBar() { - - JMenuBar menuBar = new JMenuBar(); - addToMenuBar(menuBar, buildFileMenu()); - addToMenuBar(menuBar, buildEditMenu()); - addToMenuBar(menuBar, buildViewMenu()); - addToMenuBar(menuBar, buildDocumentMenu()); - addToMenuBar(menuBar, buildWindowMenu()); - addToMenuBar(menuBar, buildHelpMenu()); - - // If running on MacOS, setup the native app. menu item handlers - if (isMacOs) { - try { - // Generate and register the OSXAdapter, passing it a hash of all the methods we wish to - // use as delegates for various com.apple.eawt.ApplicationListener methods - OSXAdapter.setQuitHandler(viewerController, viewerController.getClass().getDeclaredMethod("exit", (Class[]) null)); - OSXAdapter.setAboutHandler(viewerController, viewerController.getClass().getDeclaredMethod("showAboutDialog", (Class[]) null)); - } catch (Exception e) { - logger.log(Level.FINE, "Error occurred while loading the OSXAdapter:", e); - } - } - - return menuBar; - } - - protected KeyStroke buildKeyStroke(int keyCode, int modifiers) { - return buildKeyStroke(keyCode, modifiers, false); - } - - /** - * Create and return a KeyStroke with the specified code and modifier - * Note this will automatically return null if the PROPERTY_SHOW_KEYBOARD_SHORTCUTS - * property is 'false' - * - * @param keyCode to build - * @param modifiers to build - * @param onRelease to build - * @return built KeyStroke - */ - protected KeyStroke buildKeyStroke(int keyCode, int modifiers, boolean onRelease) { - doubleCheckPropertiesManager(); - - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_KEYBOARD_SHORTCUTS, - true)) { - return KeyStroke.getKeyStroke(keyCode, modifiers, onRelease); - } - - return null; - } - - /** - * Return a valid mnemonic for the passed character, unless the - * PropertiesManager.PROPERTY_SHOW_KEYBOARD_SHORTCUTS property is 'false', - * in which case we'll return -1 - * - * @param mnemonic to build - * @return built mnemonic - */ - protected int buildMnemonic(char mnemonic) { - doubleCheckPropertiesManager(); - - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_KEYBOARD_SHORTCUTS, - true)) { - return mnemonic; - } - - return -1; - } - - public JMenu buildFileMenu() { - JMenu fileMenu = new JMenu(messageBundle.getString("viewer.menu.file.label")); - fileMenu.setMnemonic(buildMnemonic(messageBundle.getString("viewer.menu.file.mnemonic").charAt(0))); - JMenuItem openFileMenuItem = buildOpenFileMenuItem(); - JMenuItem openURLMenuItem = buildOpenURLMenuItem(); - if (openFileMenuItem != null && openURLMenuItem != null) { - JMenu openSubMenu = new JMenu(messageBundle.getString("viewer.menu.open.label")); - openSubMenu.setIcon(new ImageIcon(Images.get("open_a_24.png"))); - openSubMenu.setDisabledIcon(new ImageIcon(Images.get("open_i_24.png"))); - openSubMenu.setRolloverIcon(new ImageIcon(Images.get("open_r_24.png"))); - addToMenu(openSubMenu, openFileMenuItem); - addToMenu(openSubMenu, openURLMenuItem); - addToMenu(fileMenu, openSubMenu); - } else if (openFileMenuItem != null || openURLMenuItem != null) { - addToMenu(fileMenu, openFileMenuItem); - addToMenu(fileMenu, openURLMenuItem); - } - fileMenu.addSeparator(); - addToMenu(fileMenu, buildCloseMenuItem()); - addToMenu(fileMenu, buildSaveAsFileMenuItem()); - addToMenu(fileMenu, buildExportTextMenuItem()); - addToMenu(fileMenu, buildExportSVGMenuItem()); - fileMenu.addSeparator(); - addToMenu(fileMenu, buildPermissionsMenuItem()); - addToMenu(fileMenu, buildInformationMenuItem()); - addToMenu(fileMenu, buildFontInformationMenuItem()); - fileMenu.addSeparator(); - addToMenu(fileMenu, buildPrintSetupMenuItem()); - addToMenu(fileMenu, buildPrintMenuItem()); - if (!isMacOs) { - // Not on a Mac, so create the Exit menu item. - fileMenu.addSeparator(); - addToMenu(fileMenu, buildExitMenuItem()); - } - return fileMenu; - } - - public JMenuItem buildOpenFileMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.open.file.label"), - buildKeyStroke(KeyEventConstants.KEY_CODE_OPEN_FILE, KeyEventConstants.MODIFIER_OPEN_FILE)); - if (viewerController != null && mi != null) - viewerController.setOpenFileMenuItem(mi); - return mi; - } - - public JMenuItem buildOpenURLMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.open.URL.label"), - buildKeyStroke(KeyEventConstants.KEY_CODE_OPEN_URL, KeyEventConstants.MODIFIER_OPEN_URL)); - if (viewerController != null && mi != null) - viewerController.setOpenURLMenuItem(mi); - return mi; - } - - public JMenuItem buildCloseMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.close.label"), null, null, - buildKeyStroke(KeyEventConstants.KEY_CODE_CLOSE, KeyEventConstants.MODIFIER_CLOSE)); - if (viewerController != null && mi != null) - viewerController.setCloseMenuItem(mi); - return mi; - } - - public JMenuItem buildSaveAsFileMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.saveAs.label"), "save", - Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_SAVE_AS, KeyEventConstants.MODIFIER_SAVE_AS, false)); - if (viewerController != null && mi != null) - viewerController.setSaveAsFileMenuItem(mi); - return mi; - } - - public JMenuItem buildExportTextMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.exportText.label"), null, null, null); - if (viewerController != null && mi != null) - viewerController.setExportTextMenuItem(mi); - return mi; - } - - public JMenuItem buildExportSVGMenuItem() { - JMenuItem mi = null; - // Check to make sure SVG libraries are available - try { - Class.forName("org.apache.batik.dom.GenericDOMImplementation"); - - mi = makeMenuItem( - messageBundle.getString("viewer.menu.exportSVG.label"), null, null, null); - if (viewerController != null && mi != null) - viewerController.setExportSVGMenuItem(mi); - } catch (ClassNotFoundException e) { - logger.warning("SVG Support Not Found"); - } - return mi; - } - - public JMenuItem buildPermissionsMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.documentPermission.label"), null, null, null); - if (viewerController != null && mi != null) - viewerController.setPermissionsMenuItem(mi); - return mi; - } - - public JMenuItem buildInformationMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.documentInformation.label"), null, null, null); - if (viewerController != null && mi != null) - viewerController.setInformationMenuItem(mi); - return mi; - } - - public JMenuItem buildFontInformationMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.documentFonts.label"), null, null, null); - if (viewerController != null && mi != null) - viewerController.setFontInformationMenuItem(mi); - return mi; - } - - public JMenuItem buildPrintSetupMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.printSetup.label"), null, null, - buildKeyStroke(KeyEventConstants.KEY_CODE_PRINT_SETUP, KeyEventConstants.MODIFIER_PRINT_SETUP, false)); - if (viewerController != null && mi != null) - viewerController.setPrintSetupMenuItem(mi); - return mi; - } - - public JMenuItem buildPrintMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.print.label"), "print", - Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_PRINT, KeyEventConstants.MODIFIER_PRINT)); - if (viewerController != null && mi != null) - viewerController.setPrintMenuItem(mi); - return mi; - } - - public JMenuItem buildExitMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.exit.label"), null, null, - buildKeyStroke(KeyEventConstants.KEY_CODE_EXIT, KeyEventConstants.MODIFIER_EXIT)); - if (viewerController != null && mi != null) - viewerController.setExitMenuItem(mi); - return mi; - } - - public JMenu buildEditMenu() { - JMenu viewMenu = new JMenu(messageBundle.getString("viewer.menu.edit.label")); - viewMenu.setMnemonic(buildMnemonic(messageBundle.getString("viewer.menu.edit.mnemonic").charAt(0))); - addToMenu(viewMenu, buildUndoMenuItem()); - addToMenu(viewMenu, buildRedoMenuItem()); - viewMenu.addSeparator(); - addToMenu(viewMenu, buildCopyMenuItem()); - addToMenu(viewMenu, buildDeleteMenuItem()); - viewMenu.addSeparator(); - addToMenu(viewMenu, buildSelectAllMenuItem()); - addToMenu(viewMenu, buildDeselectAllMenuItem()); - return viewMenu; - } - - public JMenuItem buildUndoMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.edit.undo.label"), - null, null, buildKeyStroke(KeyEventConstants.KEY_CODE_UNDO, - KeyEventConstants.MODIFIER_UNDO)); - if (viewerController != null && mi != null) - viewerController.setUndoMenuItem(mi); - return mi; - } - - public JMenuItem buildRedoMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.edit.redo.label"), - null, null, buildKeyStroke(KeyEventConstants.KEY_CODE_REDO, - KeyEventConstants.MODIFIER_REDO)); - if (viewerController != null && mi != null) - viewerController.setReduMenuItem(mi); - return mi; - } - - public JMenuItem buildCopyMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.edit.copy.label"), - null, null, buildKeyStroke(KeyEventConstants.KEY_CODE_COPY, - KeyEventConstants.MODIFIER_COPY)); - if (viewerController != null && mi != null) - viewerController.setCopyMenuItem(mi); - return mi; - } - - public JMenuItem buildDeleteMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.edit.delete.label"), - null, null, buildKeyStroke(KeyEventConstants.KEY_CODE_DELETE, - KeyEventConstants.MODIFIER_DELETE)); - if (viewerController != null && mi != null) - viewerController.setDeleteMenuItem(mi); - return mi; - } - - public JMenuItem buildSelectAllMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.edit.selectAll.label"), - null, null, buildKeyStroke(KeyEventConstants.KEY_CODE_SELECT_ALL, - KeyEventConstants.MODIFIER_SELECT_ALL)); - if (viewerController != null && mi != null) - viewerController.setSelectAllMenuItem(mi); - return mi; - } - - public JMenuItem buildDeselectAllMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.edit.deselectAll.label"), - null, null, buildKeyStroke(KeyEventConstants.KEY_CODE_DESELECT_ALL, - KeyEventConstants.MODIFIER_DESELECT_ALL)); - if (viewerController != null && mi != null) - viewerController.setDselectAllMenuItem(mi); - return mi; - } - - public JMenu buildViewMenu() { - JMenu viewMenu = new JMenu(messageBundle.getString("viewer.menu.view.label")); - viewMenu.setMnemonic(buildMnemonic(messageBundle.getString("viewer.menu.view.mnemonic").charAt(0))); - addToMenu(viewMenu, buildFitActualSizeMenuItem()); - addToMenu(viewMenu, buildFitPageMenuItem()); - addToMenu(viewMenu, buildFitWidthMenuItem()); - viewMenu.addSeparator(); - addToMenu(viewMenu, buildZoomInMenuItem()); - addToMenu(viewMenu, buildZoomOutMenuItem()); - viewMenu.addSeparator(); - addToMenu(viewMenu, buildRotateLeftMenuItem()); - addToMenu(viewMenu, buildRotateRightMenuItem()); - viewMenu.addSeparator(); - addToMenu(viewMenu, buildShowHideToolBarMenuItem()); - addToMenu(viewMenu, buildShowHideUtilityPaneMenuItem()); - return viewMenu; - } - - public JMenuItem buildFitActualSizeMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.view.actualSize.label"), - "actual_size", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_FIT_ACTUAL, KeyEventConstants.MODIFIER_FIT_ACTUAL)); - if (viewerController != null && mi != null) - viewerController.setFitActualSizeMenuItem(mi); - return mi; - } - - public JMenuItem buildFitPageMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.view.fitInWindow.label"), - "fit_window", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_FIT_PAGE, KeyEventConstants.MODIFIER_FIT_PAGE)); - if (viewerController != null && mi != null) - viewerController.setFitPageMenuItem(mi); - return mi; - } - - public JMenuItem buildFitWidthMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.view.fitWidth.label"), - null, null, - buildKeyStroke(KeyEventConstants.KEY_CODE_FIT_WIDTH, KeyEventConstants.MODIFIER_FIT_WIDTH)); - if (viewerController != null && mi != null) - viewerController.setFitWidthMenuItem(mi); - return mi; - } - - public JMenuItem buildZoomInMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.view.zoomIn.label"), - "zoom_in", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_ZOOM_IN, KeyEventConstants.MODIFIER_ZOOM_IN, false)); - if (viewerController != null && mi != null) - viewerController.setZoomInMenuItem(mi); - return mi; - } - - public JMenuItem buildZoomOutMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.view.zoomOut.label"), - "zoom_out", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_ZOOM_OUT, KeyEventConstants.MODIFIER_ZOOM_OUT, false)); - if (viewerController != null && mi != null) - viewerController.setZoomOutMenuItem(mi); - return mi; - } - - public JMenuItem buildRotateLeftMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.view.rotateLeft.label"), - "rotate_left", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_ROTATE_LEFT, KeyEventConstants.MODIFIER_ROTATE_LEFT)); - if (viewerController != null && mi != null) - viewerController.setRotateLeftMenuItem(mi); - return mi; - } - - public JMenuItem buildRotateRightMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.view.rotateRight.label"), - "rotate_right", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_ROTATE_RIGHT, KeyEventConstants.MODIFIER_ROTATE_RIGHT)); - if (viewerController != null && mi != null) - viewerController.setRotateRightMenuItem(mi); - return mi; - } - - public JMenuItem buildShowHideToolBarMenuItem() { - JMenuItem mi = makeMenuItem("", null); - if (viewerController != null && mi != null) - viewerController.setShowHideToolBarMenuItem(mi); - return mi; - } - - public JMenuItem buildShowHideUtilityPaneMenuItem() { - JMenuItem mi = makeMenuItem("", null); - if (viewerController != null && mi != null) - viewerController.setShowHideUtilityPaneMenuItem(mi); - return mi; - } - - public JMenu buildDocumentMenu() { - JMenu documentMenu = new JMenu(messageBundle.getString("viewer.menu.document.label")); - documentMenu.setMnemonic(buildMnemonic(messageBundle.getString("viewer.menu.document.mnemonic").charAt(0))); - addToMenu(documentMenu, buildFirstPageMenuItem()); - addToMenu(documentMenu, buildPreviousPageMenuItem()); - addToMenu(documentMenu, buildNextPageMenuItem()); - addToMenu(documentMenu, buildLastPageMenuItem()); - documentMenu.addSeparator(); - addToMenu(documentMenu, buildSearchMenuItem()); - addToMenu(documentMenu, buildGoToPageMenuItem()); - return documentMenu; - } - - public JMenuItem buildFirstPageMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.document.firstPage.label"), - "page_first", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_FIRST_PAGE, KeyEventConstants.MODIFIER_FIRST_PAGE)); - if (viewerController != null && mi != null) - viewerController.setFirstPageMenuItem(mi); - return mi; - } - - public JMenuItem buildPreviousPageMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.document.previousPage.label"), - "page_up", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_PREVIOUS_PAGE, KeyEventConstants.MODIFIER_PREVIOUS_PAGE)); - if (viewerController != null && mi != null) - viewerController.setPreviousPageMenuItem(mi); - return mi; - } - - public JMenuItem buildNextPageMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.document.nextPage.label"), - "page_down", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_NEXT_PAGE, KeyEventConstants.MODIFIER_NEXT_PAGE)); - if (viewerController != null && mi != null) - viewerController.setNextPageMenuItem(mi); - return mi; - } - - public JMenuItem buildLastPageMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.document.lastPage.label"), - "page_last", Images.SIZE_MEDIUM, - buildKeyStroke(KeyEventConstants.KEY_CODE_LAST_PAGE, KeyEventConstants.MODIFIER_LAST_PAGE)); - if (viewerController != null && mi != null) - viewerController.setLastPageMenuItem(mi); - return mi; - } - - public JMenuItem buildSearchMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.document.search.label"), - buildKeyStroke(KeyEventConstants.KEY_CODE_SEARCH, KeyEventConstants.MODIFIER_SEARCH)); - if (viewerController != null && mi != null) - viewerController.setSearchMenuItem(mi); - return mi; - } - - public JMenuItem buildGoToPageMenuItem() { - JMenuItem mi = makeMenuItem( - messageBundle.getString("viewer.menu.document.gotToPage.label"), - buildKeyStroke(KeyEventConstants.KEY_CODE_GOTO, KeyEventConstants.MODIFIER_GOTO)); - if (viewerController != null && mi != null) - viewerController.setGoToPageMenuItem(mi); - return mi; - } - - public JMenu buildWindowMenu() { - final JMenu windowMenu = new JMenu(messageBundle.getString("viewer.menu.window.label")); - windowMenu.setMnemonic(buildMnemonic(messageBundle.getString("viewer.menu.window.mnemonic").charAt(0))); - addToMenu(windowMenu, buildMinimiseAllMenuItem()); - addToMenu(windowMenu, buildBringAllToFrontMenuItem()); - windowMenu.addSeparator(); - final int allowedCount = windowMenu.getItemCount(); - windowMenu.addMenuListener(new javax.swing.event.MenuListener() { - public void menuCanceled(javax.swing.event.MenuEvent e) { - } - - public void menuDeselected(javax.swing.event.MenuEvent e) { - } - - public void menuSelected(javax.swing.event.MenuEvent e) { - int count = windowMenu.getItemCount(); - while (count > allowedCount) { - windowMenu.remove(count - 1); - count--; - } - buildWindowListMenuItems(windowMenu); - } - }); - return windowMenu; - } - - public JMenuItem buildMinimiseAllMenuItem() { - JMenuItem mi = makeMenuItem(messageBundle.getString("viewer.menu.window.minAll.label"), null); - mi.setMnemonic(buildMnemonic(messageBundle.getString("viewer.menu.window.minAll.mnemonic").charAt(0))); - if (viewerController != null) - viewerController.setMinimiseAllMenuItem(mi); - return mi; - } - - public JMenuItem buildBringAllToFrontMenuItem() { - JMenuItem mi = makeMenuItem(messageBundle.getString("viewer.menu.window.frontAll.label"), null); - mi.setMnemonic(buildMnemonic(messageBundle.getString("viewer.menu.window.frontAll.mnemonic").charAt(0))); - if (viewerController != null) - viewerController.setBringAllToFrontMenuItem(mi); - return mi; - } - - @SuppressWarnings("unchecked") - public void buildWindowListMenuItems(JMenu menu) { - if (viewerController != null && - viewerController.getWindowManagementCallback() != null) { - WindowManagementCallback winMgr = viewerController.getWindowManagementCallback(); - List windowDocOriginList = (List) winMgr.getWindowDocumentOriginList(viewerController); - - // Get the current window index, if it's given, and remove it from the list - int currWindowIndex = -1; - int count = windowDocOriginList.size(); - if (count > 0 && windowDocOriginList.get(count - 1) instanceof Integer) { - currWindowIndex = (Integer) windowDocOriginList.remove(--count); - } - - shortenDocumentOrigins(windowDocOriginList); - - List windowListMenuItems = - new ArrayList(Math.max(count, 1)); - for (int i = 0; i < count; i++) { - String number = Integer.toString(i + 1); - String label = null; - String mnemonic = null; - try { - label = messageBundle.getString("viewer.menu.window." + number + ".label"); - mnemonic = messageBundle.getString("viewer.menu.window." + number + ".mnemonic"); - } catch (Exception e) { - logger.log(Level.FINER, - "Error setting viewer window window title", e); - } - // Allows the user to have an arbitrary number of predefined entries - String identifier = (String) windowDocOriginList.get(i); - if (identifier == null) - identifier = ""; - String miText; - if (label != null && label.length() > 0) - miText = number + " " + identifier; - else - miText = " " + identifier; - JMenuItem mi = new JMenuItem(miText); - if (mnemonic != null && number.length() == 1) - mi.setMnemonic(buildMnemonic(number.charAt(0))); - if (currWindowIndex == i) - mi.setEnabled(false); - menu.add(mi); - windowListMenuItems.add(mi); - } - viewerController.setWindowListMenuItems(windowListMenuItems); - } - } - - protected void shortenDocumentOrigins(List windowDocOriginList) { - // At some point we should detect the same filename - // in different subdirectories, and keep some of the - // directory information, to help differentiate them - for (int i = windowDocOriginList.size() - 1; i >= 0; i--) { - String identifier = (String) windowDocOriginList.get(i); - if (identifier == null) - continue; - int separatorIndex = identifier.lastIndexOf(java.io.File.separator); - int forewardSlashIndex = identifier.lastIndexOf("/"); - int backwardSlashIndex = identifier.lastIndexOf("\\"); - int cutIndex = Math.max(separatorIndex, Math.max(forewardSlashIndex, backwardSlashIndex)); - if (cutIndex >= 0) { - identifier = identifier.substring(cutIndex); - windowDocOriginList.set(i, identifier); - } - } - } - - public JMenu buildHelpMenu() { - JMenu helpMenu = new JMenu(messageBundle.getString("viewer.menu.help.label")); - helpMenu.setMnemonic(buildMnemonic(messageBundle.getString("viewer.menu.help.mnemonic").charAt(0))); - - if (!isMacOs) { - // Not on a Mac, so create the About menu item. - addToMenu(helpMenu, buildAboutMenuItem()); - } - return helpMenu; - } - - public JMenuItem buildAboutMenuItem() { - - JMenuItem mi = makeMenuItem(messageBundle.getString("viewer.menu.help.about.label"), null); - if (viewerController != null && mi != null) - viewerController.setAboutMenuItem(mi); - return mi; - } - - - public JToolBar buildCompleteToolBar(boolean embeddableComponent) { - JToolBar toolbar = new JToolBar(); - toolbar.setLayout(new ToolbarLayout(ToolbarLayout.LEFT, 0, 0)); - commonToolBarSetup(toolbar, true); - - // Attempt to get the properties manager so we can configure which toolbars are visible - doubleCheckPropertiesManager(); - - // Build the main set of toolbars based on the property file configuration - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_TOOLBAR_UTILITY)) - addToToolBar(toolbar, buildUtilityToolBar(embeddableComponent, propertiesManager)); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_TOOLBAR_PAGENAV)) - addToToolBar(toolbar, buildPageNavigationToolBar()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_TOOLBAR_ZOOM)) - addToToolBar(toolbar, buildZoomToolBar()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_TOOLBAR_FIT)) - addToToolBar(toolbar, buildFitToolBar()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_TOOLBAR_ROTATE)) - addToToolBar(toolbar, buildRotateToolBar()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_TOOLBAR_TOOL)) - addToToolBar(toolbar, buildToolToolBar()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_TOOLBAR_ANNOTATION)) - addToToolBar(toolbar, buildAnnotationlToolBar()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_TOOLBAR_FORMS)) - addToToolBar(toolbar, buildFormsToolBar()); - - // we only add the configurable font engin in the demo version - if (isDemo) { - addToToolBar(toolbar, buildDemoToolBar()); - } - - // Set the toolbar back to null if no components were added - // The result of this will properly disable the necessary menu items for controlling the toolbar - if (toolbar.getComponentCount() == 0) { - toolbar = null; - } - - if ((viewerController != null) && (toolbar != null)) - viewerController.setCompleteToolBar(toolbar); - - return toolbar; - } - - public JToolBar buildUtilityToolBar(boolean embeddableComponent) { - return buildUtilityToolBar(embeddableComponent, null); - } - - public JToolBar buildUtilityToolBar(boolean embeddableComponent, PropertiesManager propertiesManager) { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, false); - // if embeddable component, we don't want to create the open dialog, as we - // have no window manager for this case. - if ((!embeddableComponent) && - (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_UTILITY_OPEN))) - addToToolBar(toolbar, buildOpenFileButton()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_UTILITY_SAVE)) - addToToolBar(toolbar, buildSaveAsFileButton()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_UTILITY_PRINT)) - addToToolBar(toolbar, buildPrintButton()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_UTILITY_SEARCH)) - addToToolBar(toolbar, buildSearchButton()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, PropertiesManager.PROPERTY_SHOW_UTILITY_UPANE)) - addToToolBar(toolbar, buildShowHideUtilityPaneButton()); - - // Don't bother with this toolbar if we don't have any visible buttons - if (toolbar.getComponentCount() == 0) { - return null; - } - - return toolbar; - } - - public JButton buildOpenFileButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.open.label"), - messageBundle.getString("viewer.toolbar.open.tooltip"), - "open", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setOpenFileButton(btn); - return btn; - } - - public JButton buildSaveAsFileButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.saveAs.label"), - messageBundle.getString("viewer.toolbar.saveAs.tooltip"), - "save", Images.SIZE_LARGE, - buttonFont); - if (viewerController != null && btn != null) - viewerController.setSaveAsFileButton(btn); - return btn; - } - - public JButton buildPrintButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.print.label"), - messageBundle.getString("viewer.toolbar.print.tooltip"), - "print", Images.SIZE_LARGE, - buttonFont); - if (viewerController != null && btn != null) - viewerController.setPrintButton(btn); - return btn; - } - - public JButton buildSearchButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.search.label"), - messageBundle.getString("viewer.toolbar.search.tooltip"), - "search", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setSearchButton(btn); - return btn; - } - - public JToggleButton buildShowHideUtilityPaneButton() { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.utilityPane.label"), - messageBundle.getString("viewer.toolbar.utilityPane.tooltip"), - "utility_pane", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setShowHideUtilityPaneButton(btn); - return btn; - } - - public JToolBar buildPageNavigationToolBar() { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, false); - addToToolBar(toolbar, buildFirstPageButton()); - addToToolBar(toolbar, buildPreviousPageButton()); - addToToolBar(toolbar, buildCurrentPageNumberTextField()); - addToToolBar(toolbar, buildNumberOfPagesLabel()); - addToToolBar(toolbar, buildNextPageButton()); - addToToolBar(toolbar, buildLastPageButton()); - return toolbar; - } - - public JButton buildFirstPageButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.navigation.firstPage.label"), - messageBundle.getString("viewer.toolbar.navigation.firstPage.tooltip"), - "first", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setFirstPageButton(btn); - return btn; - } - - public JButton buildPreviousPageButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.navigation.previousPage.label"), - messageBundle.getString("viewer.toolbar.navigation.previousPage.tooltip"), - "back", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setPreviousPageButton(btn); - return btn; - } - - public JButton buildNextPageButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.navigation.nextPage.label"), - messageBundle.getString("viewer.toolbar.navigation.nextPage.tooltip"), - "forward", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setNextPageButton(btn); - return btn; - } - - public JButton buildLastPageButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.navigation.lastPage.label"), - messageBundle.getString("viewer.toolbar.navigation.lastPage.tooltip"), - "last", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setLastPageButton(btn); - return btn; - } - - public JTextField buildCurrentPageNumberTextField() { - JTextField pageNumberTextField = new JTextField("", 3); - pageNumberTextField.setToolTipText(messageBundle.getString("viewer.toolbar.navigation.current.tooltip")); - pageNumberTextField.setInputVerifier(new PageNumberTextFieldInputVerifier()); - - /** - * Add a key listener and check to make sure the character intered - * is a digit, period, the back_space or delete keys. If not the - * invalid character is ignored and a system beep is triggered. - */ - pageNumberTextField.addKeyListener(new PageNumberTextFieldKeyListener()); - if (viewerController != null) - viewerController.setCurrentPageNumberTextField(pageNumberTextField); - return pageNumberTextField; - } - - public JLabel buildNumberOfPagesLabel() { - JLabel lbl = new JLabel(); - lbl.setToolTipText(messageBundle.getString("viewer.toolbar.navigation.pages.tooltip")); - if (viewerController != null) - viewerController.setNumberOfPagesLabel(lbl); - return lbl; - } - - public JToolBar buildZoomToolBar() { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, false); - addToToolBar(toolbar, buildZoomOutButton()); - addToToolBar(toolbar, buildZoomCombBox()); - addToToolBar(toolbar, buildZoomInButton()); - return toolbar; - } - - public JButton buildZoomOutButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.zoom.out.label"), - messageBundle.getString("viewer.toolbar.zoom.out.tooltip"), - "zoom_out", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setZoomOutButton(btn); - return btn; - } - - public JComboBox buildZoomCombBox() { - // Get the properties manager in preparation for trying to get the zoom levels - doubleCheckPropertiesManager(); - - // Assign any different zoom ranges from the properties file if possible - zoomLevels = PropertiesManager.checkAndStoreFloatArrayProperty(propertiesManager, - PropertiesManager.PROPERTY_ZOOM_RANGES, - zoomLevels); - - JComboBox tmp = new JComboBox(); - tmp.setToolTipText(messageBundle.getString("viewer.toolbar.zoom.tooltip")); - tmp.setPreferredSize(new Dimension(75, tmp.getHeight())); - for (float zoomLevel : zoomLevels) - tmp.addItem(NumberFormat.getPercentInstance().format(zoomLevel)); - tmp.setEditable(true); - if (viewerController != null) - viewerController.setZoomComboBox(tmp, zoomLevels); - return tmp; - } - - public JButton buildZoomInButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.zoom.in.label"), - messageBundle.getString("viewer.toolbar.zoom.in.tooltip"), - "zoom_in", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setZoomInButton(btn); - return btn; - } - - public JToolBar buildFitToolBar() { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, false); - addToToolBar(toolbar, buildFitActualSizeButton()); - addToToolBar(toolbar, buildFitPageButton()); - addToToolBar(toolbar, buildFitWidthButton()); - return toolbar; - } - - public JToggleButton buildFitActualSizeButton() { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.pageFit.actualsize.label"), - messageBundle.getString("viewer.toolbar.pageFit.actualsize.tooltip"), - "actual_size", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setFitActualSizeButton(btn); - return btn; - } - - public JToggleButton buildFitPageButton() { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.pageFit.fitWindow.label"), - messageBundle.getString("viewer.toolbar.pageFit.fitWindow.tooltip"), - "fit_window", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setFitHeightButton(btn); - return btn; - } - - public JToggleButton buildFontEngineButton() { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.pageFit.fontEngine.label"), - messageBundle.getString("viewer.toolbar.pageFit.fontEngine.tooltip"), - "font-engine", 118, 25, buttonFont); - if (viewerController != null && btn != null) - viewerController.setFontEngineButton(btn); - return btn; - } - - public JToggleButton buildFitWidthButton() { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.pageFit.fitWidth.label"), - messageBundle.getString("viewer.toolbar.pageFit.fitWidth.tooltip"), - "fit_width", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setFitWidthButton(btn); - return btn; - } - - public JToolBar buildRotateToolBar() { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, false); - addToToolBar(toolbar, buildRotateRightButton()); - addToToolBar(toolbar, buildRotateLeftButton()); - return toolbar; - } - - public JButton buildRotateLeftButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.rotation.left.label"), - messageBundle.getString("viewer.toolbar.rotation.left.tooltip"), - "rotate_left", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setRotateLeftButton(btn); - return btn; - } - - public JButton buildRotateRightButton() { - JButton btn = makeToolbarButton( - messageBundle.getString("viewer.toolbar.rotation.right.label"), - messageBundle.getString("viewer.toolbar.rotation.right.tooltip"), - "rotate_right", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setRotateRightButton(btn); - return btn; - } - - public JToolBar buildToolToolBar() { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, false); - addToToolBar(toolbar, buildPanToolButton()); - addToToolBar(toolbar, buildTextSelectToolButton()); - addToToolBar(toolbar, buildZoomInToolButton()); - addToToolBar(toolbar, buildZoomOutToolButton()); - return toolbar; - } - - public JToolBar buildAnnotationlToolBar() { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, false); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_TOOLBAR_ANNOTATION_SELECTION)) { - addToToolBar(toolbar, buildSelectToolButton(Images.SIZE_LARGE)); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_TOOLBAR_ANNOTATION_HIGHLIGHT)) { - addToToolBar(toolbar, buildHighlightAnnotationToolButton(Images.SIZE_LARGE)); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_TOOLBAR_ANNOTATION_TEXT)) { - addToToolBar(toolbar, buildTextAnnotationToolButton(Images.SIZE_LARGE)); - } - return toolbar; - } - - public JToolBar buildFormsToolBar() { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, false); - addToToolBar(toolbar, buildFormHighlightButton(Images.SIZE_LARGE)); - return toolbar; - } - - public JToolBar buildAnnotationUtilityToolBar() { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, true); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_HIGHLIGHT)) { - addToToolBar(toolbar, buildHighlightAnnotationUtilityToolButton(Images.SIZE_MEDIUM)); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_STRIKE_OUT)) { - addToToolBar(toolbar, buildStrikeOutAnnotationToolButton()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_UNDERLINE)) { - addToToolBar(toolbar, buildUnderlineAnnotationToolButton()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_LINE)) { - addToToolBar(toolbar, buildLineAnnotationToolButton()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_LINK)) { - addToToolBar(toolbar, buildLinkAnnotationToolButton()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_ARROW)) { - addToToolBar(toolbar, buildLineArrowAnnotationToolButton()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_RECTANGLE)) { - addToToolBar(toolbar, buildSquareAnnotationToolButton()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_CIRCLE)) { - addToToolBar(toolbar, buildCircleAnnotationToolButton()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_INK)) { - addToToolBar(toolbar, buildInkAnnotationToolButton()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_FREE_TEXT)) { - addToToolBar(toolbar, buildFreeTextAnnotationToolButton()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITY_ANNOTATION_TEXT)) { - addToToolBar(toolbar, buildTextAnnotationUtilityToolButton(Images.SIZE_MEDIUM)); - } - return toolbar; - } - - public JToolBar buildDemoToolBar() { - JToolBar toolbar = new JToolBar(); - commonToolBarSetup(toolbar, false); - addToToolBar(toolbar, buildFontEngineButton()); - return toolbar; - } - - public JToggleButton buildPanToolButton() { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.tool.pan.label"), - messageBundle.getString("viewer.toolbar.tool.pan.tooltip"), - "pan", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setPanToolButton(btn); - return btn; - } - - public JToggleButton buildTextSelectToolButton() { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.tool.text.label"), - messageBundle.getString("viewer.toolbar.tool.text.tooltip"), - "selection_text", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setTextSelectToolButton(btn); - return btn; - } - - public JToggleButton buildSelectToolButton(final String imageSize) { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.tool.select.label"), - messageBundle.getString("viewer.toolbar.tool.select.tooltip"), - "select", imageSize, buttonFont); - if (viewerController != null && btn != null) - viewerController.setSelectToolButton(btn); - return btn; - } - - public JToggleButton buildLinkAnnotationToolButton() { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.link.label"), - messageBundle.getString("viewer.toolbar.tool.link.tooltip"), - "link_annot", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setLinkAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildHighlightAnnotationToolButton(final String imageSize) { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.tool.highlight.label"), - messageBundle.getString("viewer.toolbar.tool.highlight.tooltip"), - "highlight_annot", imageSize, buttonFont); - if (viewerController != null && btn != null) - viewerController.setHighlightAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildHighlightAnnotationUtilityToolButton(final String imageSize) { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.highlight.label"), - messageBundle.getString("viewer.toolbar.tool.highlight.tooltip"), - "highlight_annot", imageSize, buttonFont); - if (viewerController != null && btn != null) - viewerController.setHighlightAnnotationUtilityToolButton(btn); - return btn; - } - - public JToggleButton buildStrikeOutAnnotationToolButton() { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.strikeOut.label"), - messageBundle.getString("viewer.toolbar.tool.strikeOut.tooltip"), - "strikeout", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setStrikeOutAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildUnderlineAnnotationToolButton() { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.underline.label"), - messageBundle.getString("viewer.toolbar.tool.underline.tooltip"), - "underline", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setUnderlineAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildLineAnnotationToolButton() { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.line.label"), - messageBundle.getString("viewer.toolbar.tool.line.tooltip"), - "line", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setLineAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildLineArrowAnnotationToolButton() { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.lineArrow.label"), - messageBundle.getString("viewer.toolbar.tool.lineArrow.tooltip"), - "arrow", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setLineArrowAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildSquareAnnotationToolButton() { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.rectangle.label"), - messageBundle.getString("viewer.toolbar.tool.rectangle.tooltip"), - "square", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setSquareAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildCircleAnnotationToolButton() { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.circle.label"), - messageBundle.getString("viewer.toolbar.tool.circle.tooltip"), - "circle", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setCircleAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildInkAnnotationToolButton() { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.ink.label"), - messageBundle.getString("viewer.toolbar.tool.ink.tooltip"), - "ink", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setInkAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildFreeTextAnnotationToolButton() { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.freeText.label"), - messageBundle.getString("viewer.toolbar.tool.freeText.tooltip"), - "freetext_annot", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setFreeTextAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildTextAnnotationToolButton(final String imageSize) { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.tool.textAnno.label"), - messageBundle.getString("viewer.toolbar.tool.textAnno.tooltip"), - "text_annot", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setTextAnnotationToolButton(btn); - return btn; - } - - public JToggleButton buildFormHighlightButton(final String imageSize) { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.tool.forms.highlight.label"), - messageBundle.getString("viewer.toolbar.tool.forms.highlight.tooltip"), - "form_highlight", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setFormHighlightButton(btn); - return btn; - } - - public JToggleButton buildTextAnnotationUtilityToolButton(final String imageSize) { - JToggleButton btn = makeToolbarToggleButtonSmall( - messageBundle.getString("viewer.toolbar.tool.textAnno.label"), - messageBundle.getString("viewer.toolbar.tool.textAnno.tooltip"), - "text_annot", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setTextAnnotationUtilityToolButton(btn); - return btn; - } - - public JToggleButton buildZoomInToolButton() { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.tool.zoomMarquis.label"), - messageBundle.getString("viewer.toolbar.tool.zoomMarquis.tooltip"), - "zoom_marquis", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setZoomInToolButton(btn); - return btn; - } - - public JToggleButton buildZoomOutToolButton() { - JToggleButton btn = makeToolbarToggleButton( - messageBundle.getString("viewer.toolbar.tool.zoomDynamic.label"), - messageBundle.getString("viewer.toolbar.tool.zoomDynamic.tooltip"), - "zoom_dynamic", Images.SIZE_LARGE, buttonFont); - if (viewerController != null && btn != null) - viewerController.setZoomDynamicToolButton(btn); - return btn; - } - - - public JSplitPane buildUtilityAndDocumentSplitPane(boolean embeddableComponent) { - JSplitPane splitpane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); - splitpane.setOneTouchExpandable(false); - splitpane.setDividerSize(8); - splitpane.setContinuousLayout(true); - // set the utility pane the left of the split pane - splitpane.setLeftComponent(buildUtilityTabbedPane()); - - // set the viewController embeddable flag. - DocumentViewController viewController = - viewerController.getDocumentViewController(); - // will add key event listeners - viewerController.setIsEmbeddedComponent(embeddableComponent); - - // remove F6 focus management key from the splitpane - splitpane.getActionMap().getParent().remove("toggleFocus"); - - // add the viewControllers doc view container to the split pain - splitpane.setRightComponent(viewController.getViewContainer()); - - // apply previously set divider location, default is -1 - int dividerLocation = PropertiesManager.checkAndStoreIntegerProperty( - propertiesManager, - PropertiesManager.PROPERTY_DIVIDER_LOCATION, 260); - splitpane.setDividerLocation(dividerLocation); - - // Add the split pan component to the view controller so that it can - // manipulate the divider via the controller, hide, show, etc. for - // utility pane. - if (viewerController != null) - viewerController.setUtilityAndDocumentSplitPane(splitpane); - return splitpane; - } - - public JTabbedPane buildUtilityTabbedPane() { - JTabbedPane utilityTabbedPane = new JTabbedPane(); - utilityTabbedPane.setPreferredSize(new Dimension(250, 400)); - - // Get a properties manager that can be used to configure utility pane visibility - doubleCheckPropertiesManager(); - - // Build the main set of tabs based on the property file configuration - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITYPANE_BOOKMARKS)) { - utilityTabbedPane.add( - messageBundle.getString("viewer.utilityPane.bookmarks.tab.title"), - buildOutlineComponents()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITYPANE_ATTACHMENTS)) { - utilityTabbedPane.add( - messageBundle.getString("viewer.utilityPane.attachments.tab.title"), - buildAttachmentPanle()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITYPANE_SEARCH)) { - utilityTabbedPane.add( - messageBundle.getString("viewer.utilityPane.search.tab.title"), - buildSearchPanel()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITYPANE_THUMBNAILS)) { - utilityTabbedPane.add( - messageBundle.getString("viewer.utilityPane.thumbs.tab.title"), - buildThumbsPanel()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITYPANE_LAYERS)) { - utilityTabbedPane.add( - messageBundle.getString("viewer.utilityPane.layers.tab.title"), - buildLayersComponents()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITYPANE_SIGNATURES)) { - utilityTabbedPane.add( - messageBundle.getString("viewer.utilityPane.signatures.tab.title"), - buildSignatureComponents()); - } - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITYPANE_ANNOTATION)) { - utilityTabbedPane.add( - messageBundle.getString("viewer.utilityPane.annotation.tab.title"), - buildAnnotationPanel()); - } - - // Ensure something was added to the utility pane, otherwise reset it to null - // By doing this we will stop the utility pane management buttons from displaying - if (utilityTabbedPane.getComponentCount() == 0) { - utilityTabbedPane = null; - } - - if (viewerController != null) - viewerController.setUtilityTabbedPane(utilityTabbedPane); - - return utilityTabbedPane; - } - - public JComponent buildOutlineComponents() { - JTree tree = new OutlinesTree(); - JScrollPane scroll = new JScrollPane(tree); - if (viewerController != null) - viewerController.setOutlineComponents(tree, scroll); - return scroll; - } - - public ThumbnailsPanel buildThumbsPanel() { - ThumbnailsPanel thumbsPanel = new ThumbnailsPanel(viewerController, - propertiesManager); - if (viewerController != null) { - viewerController.setThumbnailsPanel(thumbsPanel); - } - return thumbsPanel; - } - - public LayersPanel buildLayersComponents() { - LayersPanel layersPanel = new LayersPanel(viewerController); - if (viewerController != null) { - viewerController.setLayersPanel(layersPanel); - } - return layersPanel; - } - - public JComponent buildSignatureComponents() { - SignaturesPanel signaturesPanel = new SignaturesPanel(viewerController); - if (viewerController != null) { - viewerController.setSignaturesPanel(signaturesPanel); - } - return signaturesPanel; - } - - public SearchPanel buildSearchPanel() { - SearchPanel searchPanel = new SearchPanel(viewerController); - if (viewerController != null) - viewerController.setSearchPanel(searchPanel); - return searchPanel; - } - - public AttachmentPanel buildAttachmentPanle(){ - AttachmentPanel attachmentPanel = new AttachmentPanel(viewerController); - if (viewerController != null) - viewerController.setAttachmentPanel(attachmentPanel); - return attachmentPanel; - } - - public AnnotationPanel buildAnnotationPanel() { - AnnotationPanel annotationPanel = new AnnotationPanel(viewerController, propertiesManager); - annotationPanel.setAnnotationUtilityToolbar(buildAnnotationUtilityToolBar()); - if (viewerController != null) - viewerController.setAnnotationPanel(annotationPanel); - return annotationPanel; - } - - /** - * Builds the status bar panel containing a status label on the left and - * view mode controls on the right. The status bar can be shown or - * hidden completely using the view property 'application.statusbar=true|false' - * and the two child frame elements can be controlled using - * 'application.statusbar.show.statuslabel=true|false' and - * 'application.statusbar.show.viewmode=true|false'. The default value - * for all properties is 'true'. - * - * @return status panel JPanel if visible, null if the proeprty - * 'application.statusbar=false' is set. - */ - public JPanel buildStatusPanel() { - // check to see if the status bars should be built. - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_STATUSBAR)) { - JPanel statusPanel = new JPanel(new BorderLayout()); - - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_STATUSBAR_STATUSLABEL)) { - JPanel pgPanel = new JPanel(); - JLabel lbl = new JLabel(" "); - lbl.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0)); // So text isn't at the very edge - pgPanel.add(lbl); - statusPanel.add(pgPanel, BorderLayout.WEST); - // set status label callback - if (viewerController != null) { - viewerController.setStatusLabel(lbl); - } - } - - JPanel viewPanel = new JPanel(); - // Only add actual buttons to the view panel if requested by the properties file - // Regardless we'll add the parent JPanel, to preserve the same layout behaviour - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_STATUSBAR_VIEWMODE)) { - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_STATUSBAR_VIEWMODE_SINGLE)) - viewPanel.add(buildPageViewSinglePageNonConToggleButton()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_STATUSBAR_VIEWMODE_SINGLE_CONTINUOUS)) - viewPanel.add(buildPageViewSinglePageConToggleButton()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_STATUSBAR_VIEWMODE_DOUBLE)) - viewPanel.add(buildPageViewFacingPageNonConToggleButton()); - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_STATUSBAR_VIEWMODE_DOUBLE_CONTINUOUS)) - viewPanel.add(buildPageViewFacingPageConToggleButton()); - } - statusPanel.add(viewPanel, BorderLayout.CENTER); - viewPanel.setLayout(new ToolbarLayout(ToolbarLayout.RIGHT, 0, 1)); - - JLabel lbl2 = new JLabel(" "); - lbl2.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); // So text isn't at the very edge - statusPanel.add(lbl2, BorderLayout.EAST); - - return statusPanel; - } - return null; - } - - public JToggleButton buildPageViewSinglePageConToggleButton() { - JToggleButton btn = makeToolbarToggleButton(messageBundle.getString("viewer.toolbar.pageView.continuous.singlePage.label"), - messageBundle.getString("viewer.toolbar.pageView.continuous.singlePage.tooltip"), - "single_page_column", Images.SIZE_MEDIUM, - buttonFont); - if (viewerController != null && btn != null) - viewerController.setPageViewSinglePageConButton(btn); - return btn; - } - - public JToggleButton buildPageViewFacingPageConToggleButton() { - JToggleButton btn = makeToolbarToggleButton(messageBundle.getString("viewer.toolbar.pageView.continuous.facingPage.label"), - messageBundle.getString("viewer.toolbar.pageView.continuous.facingPage.tooltip"), - "two_page_column", Images.SIZE_MEDIUM, - buttonFont); - if (viewerController != null && btn != null) - viewerController.setPageViewFacingPageConButton(btn); - return btn; - } - - public JToggleButton buildPageViewSinglePageNonConToggleButton() { - JToggleButton btn = makeToolbarToggleButton(messageBundle.getString("viewer.toolbar.pageView.nonContinuous.singlePage.label"), - messageBundle.getString("viewer.toolbar.pageView.nonContinuous.singlePage.tooltip"), - "single_page", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setPageViewSinglePageNonConButton(btn); - return btn; - } - - public JToggleButton buildPageViewFacingPageNonConToggleButton() { - JToggleButton btn = makeToolbarToggleButton(messageBundle.getString("viewer.toolbar.pageView.nonContinuous.facingPage.label"), - messageBundle.getString("viewer.toolbar.pageView.nonContinuous.facingPage.tooltip"), - "two_page", Images.SIZE_MEDIUM, buttonFont); - if (viewerController != null && btn != null) - viewerController.setPageViewFacingPageNonConButton(btn); - return btn; - } - - - /** - * Utility method for creating a toolbar button. - * - * @param title display text for the menu item - * @param toolTip tool tip text - * @param imageName display image name - * @param imageSize image size file extention constant - * @param font display font - * @return a button with the specified characteristics. - */ - protected JButton makeToolbarButton( - String title, String toolTip, String imageName, final String imageSize, - java.awt.Font font) { - JButton tmp = new JButton(showButtonText ? title : ""); - tmp.setFont(font); - tmp.setToolTipText(toolTip); - tmp.setPreferredSize(new Dimension(32, 32)); - try { - tmp.setIcon(new ImageIcon(Images.get(imageName + "_a" + imageSize + ".png"))); - tmp.setPressedIcon(new ImageIcon(Images.get(imageName + "_i" + imageSize + ".png"))); - tmp.setRolloverIcon(new ImageIcon(Images.get(imageName + "_r" + imageSize + ".png"))); - tmp.setDisabledIcon(new ImageIcon(Images.get(imageName + "_i" + imageSize + ".png"))); - } catch (NullPointerException e) { - logger.warning("Failed to load toolbar button images: " + imageName + "_i" + imageSize + ".png"); - } - tmp.setRolloverEnabled(true); - tmp.setBorderPainted(false); - tmp.setContentAreaFilled(false); - tmp.setFocusPainted(true); - - return tmp; - } - - /** - * Utility method for creating toggle buttons. - * - * @param title display text for the menu item - * @param toolTip tool tip text - * @param imageName display image name - * @param font display font - * @param imageSize imageSize image size constant - * @return a toggle button with the specified characteristics. - */ - protected JToggleButton makeToolbarToggleButton( - String title, String toolTip, String imageName, - final String imageSize, java.awt.Font font) { - JToggleButton tmp = new JToggleButton(showButtonText ? title : ""); - tmp.setFont(font); - tmp.setToolTipText(toolTip); - tmp.setPreferredSize(new Dimension(32, 32)); - tmp.setRolloverEnabled(true); - - try { - tmp.setIcon(new ImageIcon(Images.get(imageName + "_a" + imageSize + ".png"))); - tmp.setPressedIcon(new ImageIcon(Images.get(imageName + "_i" + imageSize + ".png"))); - tmp.setRolloverIcon(new ImageIcon(Images.get(imageName + "_r" + imageSize + ".png"))); - tmp.setDisabledIcon(new ImageIcon(Images.get(imageName + "_i" + imageSize + ".png"))); - } catch (NullPointerException e) { - logger.warning("Failed to load toolbar toggle button images: " + imageName + "_i" + imageSize + ".png"); - } - //tmp.setBorderPainted(false); - tmp.setBorder(BorderFactory.createEmptyBorder()); - tmp.setContentAreaFilled(false); - tmp.setFocusPainted(true); - - return tmp; - } - - /** - * Utility method for creating small toggle buttons (24x24) that also - * have a selected icon state. . - * - * @param title display text for the menu item - * @param toolTip tool tip text - * @param imageName display image name - * @param font display font - * @param imageSize imageSize image size constant - * @return a toggle button with the specified characteristics. - */ - protected JToggleButton makeToolbarToggleButtonSmall( - String title, String toolTip, String imageName, - final String imageSize, java.awt.Font font) { - JToggleButton tmp = new JToggleButton(showButtonText ? title : ""); - tmp.setFont(font); - tmp.setToolTipText(toolTip); - tmp.setPreferredSize(new Dimension(24, 24)); - try { - tmp.setIcon(new ImageIcon(Images.get(imageName + "_a" + imageSize + ".png"))); - tmp.setPressedIcon(new ImageIcon(Images.get(imageName + "_i" + imageSize + ".png"))); -// tmp.setSelectedIcon(new ImageIcon(Images.get(imageName + "_s" + imageSize + ".png"))); - tmp.setRolloverIcon(new ImageIcon(Images.get(imageName + "_r" + imageSize + ".png"))); - tmp.setDisabledIcon(new ImageIcon(Images.get(imageName + "_i" + imageSize + ".png"))); - } catch (NullPointerException e) { - logger.warning("Failed to load toolbar toggle images: " + imageName + "_i" + imageSize + ".png"); - } - //tmp.setBorderPainted(false); - tmp.setBorder(BorderFactory.createEmptyBorder()); - tmp.setContentAreaFilled(false); - tmp.setRolloverEnabled(true); - tmp.setFocusPainted(true); - - return tmp; - } - - - protected JToggleButton makeToolbarToggleButton( - String title, String toolTip, java.awt.Font font) { - JToggleButton tmp = new JToggleButton(showButtonText ? title : ""); - tmp.setFont(font); - tmp.setToolTipText(toolTip); - tmp.setPreferredSize(new Dimension(30, 30)); - tmp.setText(title); - tmp.setFocusPainted(true); - return tmp; - } - - - protected JToggleButton makeToolbarToggleButton( - String title, String toolTip, String imageName, - int imageWidth, int imageHeight, java.awt.Font font) { - JToggleButton tmp = new JToggleButton(showButtonText ? title : ""); - tmp.setFont(font); - tmp.setToolTipText(toolTip); - tmp.setRolloverEnabled(false); - tmp.setPreferredSize(new Dimension(imageWidth, imageHeight)); - try { - tmp.setIcon(new ImageIcon(Images.get(imageName + "_d.png"))); - tmp.setPressedIcon(new ImageIcon(Images.get(imageName + "_d.png"))); - tmp.setSelectedIcon(new ImageIcon(Images.get(imageName + "_n.png"))); - tmp.setDisabledIcon(new ImageIcon(Images.get(imageName + "_n.png"))); - } catch (NullPointerException e) { - logger.warning("Failed to load toobar toggle button images: " + imageName + ".png"); - } - tmp.setBorderPainted(false); - tmp.setBorder(BorderFactory.createEmptyBorder()); - tmp.setContentAreaFilled(false); - tmp.setFocusPainted(false); - - return tmp; - } - - /** - * Utility method for creating a menu item. - * - * @param text display text for the menu item - * @return menu item complete with text and action listener - */ - protected JMenuItem makeMenuItem(String text, KeyStroke accel) { - JMenuItem jmi = new JMenuItem(text); - if (accel != null) - jmi.setAccelerator(accel); - return jmi; - } - - /** - * Utility method for creating a menu item with an image. - * - * @param text display text for the menu item - * @param imageName display image for the menu item - * @param imageSize size of the image. - * @return memu item complete with text, image and action listener - */ - protected JMenuItem makeMenuItem(String text, String imageName, - final String imageSize, KeyStroke accel) { - JMenuItem jmi = new JMenuItem(text); - if (imageName != null) { - try { - jmi.setIcon(new ImageIcon(Images.get(imageName + "_a" + imageSize + ".png"))); - jmi.setDisabledIcon(new ImageIcon(Images.get(imageName + "_i" + imageSize + ".png"))); - jmi.setRolloverIcon(new ImageIcon(Images.get(imageName + "_r" + imageSize + ".png"))); - } catch (NullPointerException e) { - logger.warning("Failed to load menu images: " + imageName + "_a" + imageSize + ".png"); - } - } else { - jmi.setIcon(new ImageIcon(Images.get("menu_spacer.gif"))); - jmi.setDisabledIcon(new ImageIcon(Images.get("menu_spacer.gif"))); - jmi.setRolloverIcon(new ImageIcon(Images.get("menu_spacer.gif"))); - } - jmi.setBorder(BorderFactory.createEmptyBorder()); - jmi.setContentAreaFilled(false); - jmi.setFocusPainted(true); - if (accel != null) - jmi.setAccelerator(accel); - - return jmi; - } - - protected void commonToolBarSetup(JToolBar toolbar, boolean isMainToolBar) { - if (!isMainToolBar) { - toolbar.requestFocus(); - toolbar.setRollover(true); - } - if (toolbarStyle == TOOL_BAR_STYLE_FIXED) { - toolbar.setFloatable(false); - if (!isMainToolBar) { - if (haveMadeAToolBar) - toolbar.addSeparator(); - haveMadeAToolBar = true; - } - } - } - - /** - * Method to try to get the properties manager from the window management callback, - * if we don't already have a propertiesManager object - */ - protected void doubleCheckPropertiesManager() { - if ((propertiesManager == null) && - (viewerController != null) && - (viewerController.getWindowManagementCallback() != null)) { - propertiesManager = viewerController.getWindowManagementCallback().getProperties(); - } - } - - /** - * Method to attempt to override the system property highlight color - * If the current color is blank, we'll try to pull the same property from - * our local propertiesManager and, if found, apply it to the system properties - * This affects the search highlight coloring - */ - protected void overrideHighlightColor() { - // Attempt to override the default highlight color - // We will only attempt this if a -D system parameter was not passed - if (Defs.sysProperty(PropertiesManager.SYSPROPERTY_HIGHLIGHT_COLOR) == null) { - doubleCheckPropertiesManager(); - - // Try to pull the color from our local properties file - // If we can find a value, then set it as the system property - if (propertiesManager != null) { - String newColor = propertiesManager.getString(PropertiesManager.SYSPROPERTY_HIGHLIGHT_COLOR, null); - if (newColor != null) { - Defs.setSystemProperty(PropertiesManager.SYSPROPERTY_HIGHLIGHT_COLOR, newColor); - } - } - } - } - - protected Font buildButtonFont() { - return new java.awt.Font("Helvetica", java.awt.Font.PLAIN, 9); - } - - protected void addToToolBar(JToolBar toolbar, JComponent comp) { - if (comp != null) - toolbar.add(comp); - } - - protected void addToMenu(JMenu menu, JMenuItem mi) { - if (mi != null) - menu.add(mi); - } - - protected void addToMenuBar(JMenuBar menuBar, JMenu menu) { - if (menu != null) - menuBar.add(menu); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/SwingWorker.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/SwingWorker.java deleted file mode 100644 index 4b03c385b5..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/SwingWorker.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import javax.swing.*; - -/** - * This is the 3rd version of SwingWorker (also known as - * SwingWorker 3), an abstract class that you subclass to - * perform GUI-related work in a dedicated thread. For - * instructions on and examples of using this class, see: - *

      - * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html - *

      - * Note that the API changed slightly in the 3rd version: - * You must now invoke start() on the SwingWorker after - * creating it. - */ -public abstract class SwingWorker { - private Object value; // see getValue(), setValue() - private Integer threadPriority; - - /** - * Class to maintain reference to current worker thread - * under separate synchronization control. - */ - private static class ThreadVar { - private Thread thread; - - ThreadVar(Thread t) { - thread = t; - } - - synchronized Thread get() { - return thread; - } - - synchronized void clear() { - thread = null; - } - } - - private ThreadVar threadVar; - - /** - * Get the value produced by the worker thread, or null if it - * hasn't been constructed yet. - */ - protected synchronized Object getValue() { - return value; - } - - /** - * Set the value produced by worker thread - */ - private synchronized void setValue(Object x) { - value = x; - } - - /** - * Compute the value to be returned by the get method. - */ - public abstract Object construct(); - - /** - * Called on the event dispatching thread (not on the worker thread) - * after the construct method has returned. - */ - public void finished() { - } - - /** - * A new method that interrupts the worker thread. Call this method - * to force the worker to stop what it's doing. - */ - public void interrupt() { - Thread t = threadVar.get(); - if (t != null) { - t.interrupt(); - } - threadVar.clear(); - } - - /** - * Return the value created by the construct method. - * Returns null if either the constructing thread or the current - * thread was interrupted before a value was produced. - * - * @return the value created by the construct method - */ - public Object get() { - while (true) { - Thread t = threadVar.get(); - if (t == null) { - return getValue(); - } - try { - t.join(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); // propagate - return null; - } - } - } - - - /** - * Start a thread that will call the construct method - * and then exit. - */ - public SwingWorker() { - final Runnable doFinished = new Runnable() { - public void run() { - finished(); - } - }; - - Runnable doConstruct = new Runnable() { - public void run() { - try { - setValue(construct()); - } finally { - threadVar.clear(); - } - - SwingUtilities.invokeLater(doFinished); - } - }; - - Thread t = new Thread(doConstruct); - threadVar = new ThreadVar(t); - } - - /** - * Start the worker thread. - */ - public void start() { - Thread t = threadVar.get(); - if (t != null) { - if (threadPriority != null) - t.setPriority(threadPriority); - t.start(); - } - } - - public void setThreadPriority(int priority) { - threadPriority = priority; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/TextExtractionGlue.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/TextExtractionGlue.java deleted file mode 100644 index f59e4f0d1c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/TextExtractionGlue.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.ri.util.TextExtractionTask; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * Acts as glue between the TextExtractionTask and ProgressMonitor. - * - * @author Mark Collette - * @since 2.0 - */ -public class TextExtractionGlue implements ActionListener { - private TextExtractionTask textExtractionTask; - private ProgressMonitor progressMonitor; - private Timer timer; - - TextExtractionGlue(TextExtractionTask task, ProgressMonitor prog) { - textExtractionTask = task; - progressMonitor = prog; - } - - void setTimer(Timer t) { - timer = t; - } - - public void actionPerformed(ActionEvent evt) { - // Update progressMonitor progress - progressMonitor.setProgress(textExtractionTask.getCurrent()); - String s = textExtractionTask.getMessage(); - - if (s != null) { - progressMonitor.setNote(s); - } - - if (progressMonitor.isCanceled() || textExtractionTask.isDone()) { - progressMonitor.close(); - textExtractionTask.stop(); - Toolkit.getDefaultToolkit().beep(); - timer.stop(); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/ToolbarLayout.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/ToolbarLayout.java deleted file mode 100644 index 7c0df1d9a3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/ToolbarLayout.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common; - -import java.awt.*; - -/** - * The ToolbarLayout class provides a Flow-like Layout Manager specifically - * suited for use within a JToolBar. - *

      - *

      This layout manager will dynamically wrap JToolBar contents to additional - * toolbar rows if the current toolbar width is not sufficient for it to display - * all of the toolbar items on the current number of toolbar rows. Alternatively, - * it will also collapse the number of JToolBar rows if possible to display the - * toolbar contents on as few rows as possible. - */ - -class ToolbarLayout implements LayoutManager { - public static final int LEFT = 0; - public static final int CENTER = 1; - public static final int RIGHT = 2; - public static final int LEADING = 3; - public static final int TRAILING = 4; - - int align; - int hgap; - int vgap; - - public ToolbarLayout() { - this(CENTER, 5, 5); - } - - public ToolbarLayout(int align) { - this(align, 5, 5); - } - - public ToolbarLayout(int align, int hgap, int vgap) { - this.hgap = hgap; - this.vgap = vgap; - setAlignment(align); - } - - public int getAlignment() { - return align; - } - - public void setAlignment(int align) { - switch (align) { - case LEADING: - this.align = LEFT; - break; - case TRAILING: - this.align = RIGHT; - break; - default: - this.align = align; - break; - } - } - - public int getHgap() { - return hgap; - } - - public void setHgap(int hgap) { - this.hgap = hgap; - } - - public int getVgap() { - return vgap; - } - - public void setVgap(int vgap) { - this.vgap = vgap; - } - - public Dimension minimumLayoutSize(Container parent) { - synchronized (parent.getTreeLock()) { - Dimension dim = new Dimension(0, 0); - int componentCount = parent.getComponentCount(); - - for (int i = 0; i < componentCount; i++) { - Component c = parent.getComponent(i); - if (c.isVisible()) { - Dimension d = c.getMinimumSize(); - dim.height = Math.max(dim.height, d.height); - if (i > 0) { - dim.width += hgap; - } - dim.width += d.width; - } - } - Insets insets = parent.getInsets(); - dim.width += insets.left + insets.right + 2 * hgap; - dim.height += insets.top + insets.bottom + 2 * vgap; - return dim; - } - } - - public Dimension preferredLayoutSize(Container parent) { - if (parent.getWidth() == 0) { - // Parent has no size yet, ask for enough to fit all toolbar items on one row - return minimumLayoutSize(parent); - - } else { - - synchronized (parent.getTreeLock()) { - Dimension dim = new Dimension(0, 0); - int maxWidth = 0; - int componentCount = parent.getComponentCount(); - Insets insets = parent.getInsets(); - int padWidths = (hgap * 2) + insets.left + insets.right; - - for (int i = 0; i < componentCount; i++) { - Component c = parent.getComponent(i); - if (c.isVisible()) { - Dimension d = c.getPreferredSize(); - // Does this comp fit in the current toolbar width? - if ((dim.width + d.width + padWidths) <= parent.getWidth()) { - // Yes, check to see if the row height needs to grow to fit it. - dim.height = Math.max(dim.height, d.height); - } else { - // No, add height for another toolbar row, reset row width - dim.height += vgap + d.height; - dim.width = 0; - } - if (dim.width > 0) { - // Add hgap between toolbar items - dim.width += hgap; - } - // Add width of this toolbar item to row width - dim.width += d.width; - if (dim.width > maxWidth) { - maxWidth = dim.width; - } - } - } - - dim.width = Math.max(dim.width, maxWidth); - dim.width += insets.left + insets.right + 2 * hgap; - dim.height += insets.top + insets.bottom + 2 * vgap; - return dim; - } - } - } - - - public void layoutContainer(Container parent) { - synchronized (parent.getTreeLock()) { - Insets insets = parent.getInsets(); - int maxWidth = parent.getWidth() - - (insets.left + insets.right + hgap * 2); - int componentCount = parent.getComponentCount(); - int x = 0, y = insets.top + vgap; - int rowh = 0, start = 0; - boolean ltr = parent.getComponentOrientation().isLeftToRight(); - - for (int i = 0; i < componentCount; i++) { - Component c = parent.getComponent(i); - if (c.isVisible()) { - Dimension d = c.getPreferredSize(); - c.setSize(d.width, d.height); - if ((x == 0) || ((x + d.width) <= maxWidth)) { - if (x > 0) { - x += hgap; - } - x += d.width; - rowh = Math.max(rowh, d.height); - } else { - rowh = moveComponents(parent, insets.left + hgap, y, - maxWidth - x, rowh, start, i, ltr); - x = d.width; - y += vgap + rowh; - rowh = d.height; - start = i; - } - } - } - moveComponents(parent, insets.left + hgap, y, maxWidth - x, - rowh, start, componentCount, ltr); - } - } - - private int moveComponents(Container parent, int x, int y, int width, - int height, int rowStart, int rowEnd, - boolean ltr) { - switch (align) { - case LEFT: - x += ltr ? 0 : width; - break; - case CENTER: - x += width / 2; - break; - case RIGHT: - x += ltr ? width : 0; - break; - case LEADING: - break; - case TRAILING: - x += width; - break; - } - for (int i = rowStart; i < rowEnd; i++) { - Component c = parent.getComponent(i); - if (c.isVisible()) { - int cy; - cy = y + (height - c.getHeight()) / 2; - if (ltr) { - c.setLocation(x, cy); - } else { - c.setLocation(parent.getWidth() - x - c.getWidth(), cy); - } - x += c.getWidth() + hgap; - } - } - return height; - } - - public void addLayoutComponent(String name, Component comp) { - } - - public void removeLayoutComponent(Component comp) { - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/UndoCaretaker.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/UndoCaretaker.java deleted file mode 100644 index b78be129cc..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/UndoCaretaker.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.core.Memento; -import org.icepdf.core.util.Defs; - -import java.util.ArrayList; - -/** - * Undo caretaker implementation for the Viewer RI. Currently only annotation - * can be manipulate but this class can easily handle any class that implements - * the Memento interfce. - * - * @since 4.0 - */ -public class UndoCaretaker { - - // max number of object to store in undo list. - private static int maxHistorySize; - - static { - // enables interactive annotation support. - maxHistorySize = - Defs.sysPropertyInt( - "org.icepdf.ri.viewer.undo.size", 25); - } - - private ArrayList mementoStateHistory; - private int cursor; - - public UndoCaretaker() { - mementoStateHistory = new ArrayList(maxHistorySize); - cursor = 0; - } - - /** - * Undo the last state change. Only possible if there are items in the - * undo history list. - */ - public void undo() { - if (isUndo()) { - // move the point reference - cursor = cursor - 1; - Memento tmp = mementoStateHistory.get(cursor); - // restore the old state - tmp.restore(); - } - } - - /** - * Gets the status of the undo command. - * - * @return true if an undo command is possible, false if undo can not be done. - */ - public boolean isUndo() { - return mementoStateHistory.size() > 0 && cursor > 0; - } - - /** - * Redo the last state change. ONly possible if there have been previous - * undo call. - */ - public void redo() { - if (isRedo()) { - // move the pointer - cursor = cursor + 1; - Memento tmp = mementoStateHistory.get(cursor); - // restore the old state - tmp.restore(); - } - } - - /** - * Gets the status of the redo command. - * - * @return true if an redo command is possible, false if the redo can not be done. - */ - public boolean isRedo() { - // check for at least one history state in the next index. - return cursor + 1 < mementoStateHistory.size(); - } - - /** - * Adds the give states to the history list. - * - * @param previousState previous state - * @param newState new state. - */ - public void addState(Memento previousState, Memento newState) { - // first check history bounds, if we are in an none - if (cursor >= maxHistorySize) { - // get rid of first index. - mementoStateHistory.remove(0); - mementoStateHistory.remove(1); - cursor = mementoStateHistory.size() - 1; - } - // check to see if we are in a possible redo state, if so we clear - // all states from the current pointer. - if (isRedo()) { - for (int i = cursor + 1, max = mementoStateHistory.size(); i < max; i++) { - mementoStateHistory.remove(cursor + 1); - } - } - // first entry is special case, add them as is. - if (mementoStateHistory.size() == 0) { - mementoStateHistory.add(previousState); - mementoStateHistory.add(newState); - cursor = 1; - } - // we do an offset add - else { - mementoStateHistory.set(cursor, previousState); - mementoStateHistory.add(newState); - cursor++; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/ViewModel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/ViewModel.java deleted file mode 100644 index a70fe520a2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/ViewModel.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import java.io.File; - -/** - * Data model for the view, which maintains state on how a Document is being - * presented to the user. - *

      - * The default value of isShrinkToPrintableArea is true. - * - * @author Mark Collette - * @since 2.0 - */ -public class ViewModel { - - // Store current directory path - private static File defaultFile = null; - - // Store current URL path - private static String defaultURL = null; - - // store for shrink to fit setting for SwingController prints. - private boolean isShrinkToPrintableArea = true; - - // number of copies to print - private int printCopies = 1; - - private PrintHelper printHelper; - - private boolean isWidgetAnnotationHighlight; - - public static File getDefaultFile() { - return defaultFile; - } - - public static String getDefaultFilePath() { - if (defaultFile == null) - return null; - return defaultFile.getAbsolutePath(); - } - - public static String getDefaultURL() { - return defaultURL; - } - - public static void setDefaultFile(File f) { - defaultFile = f; - } - - public static void setDefaultFilePath(String defFilePath) { - if (defFilePath == null || defFilePath.length() == 0) - defaultFile = null; - else - defaultFile = new File(defFilePath); - } - - public static void setDefaultURL(String defURL) { - if (defURL == null || defURL.length() == 0) - defaultURL = null; - else - defaultURL = defURL; - } - - public PrintHelper getPrintHelper() { - return printHelper; - } - - public void setPrintHelper(PrintHelper printHelper) { - this.printHelper = printHelper; - } - - /** - * Indicates the currently stored state of the shrink to fit printable area - * property. - * - * @return true, to enable shrink to fit printable area; - * false, otherwise. - */ - public boolean isShrinkToPrintableArea() { - return isShrinkToPrintableArea; - } - - /** - * Can be set before a SwingController.print() is called to enable/disable - * shrink to fit printable area. - * - * @param shrinkToPrintableArea true, to enable shrink to fit printable area; - * false, otherwise. - */ - public void setShrinkToPrintableArea(boolean shrinkToPrintableArea) { - isShrinkToPrintableArea = shrinkToPrintableArea; - } - - /** - * Number of copies to print - * - * @return number of copies to print - */ - public int getPrintCopies() { - return printCopies; - } - - /** - * Sets the number of print copies that should be make during the next - * print. - * - * @param printCopies one or more copies - */ - public void setPrintCopies(int printCopies) { - this.printCopies = printCopies; - } - - /** - * Indicates that widget highlighting is enabled. - * @return true if enabled, otherwise false. - */ - public boolean isWidgetAnnotationHighlight() { - return isWidgetAnnotationHighlight; - } - - /** - * Sets the value of widgetAnnotation highlight model. - * - * @param isWidgetAnnotationHighlight true to enable highlight, otherwise false. - */ - public void setIsWidgetAnnotationHighlight(boolean isWidgetAnnotationHighlight) { - this.isWidgetAnnotationHighlight = isWidgetAnnotationHighlight; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/WindowManagementCallback.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/WindowManagementCallback.java deleted file mode 100644 index 9a1e3e40c6..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/WindowManagementCallback.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common; - -import org.icepdf.ri.util.PropertiesManager; - -import javax.swing.*; -import java.net.URL; -import java.util.List; -import java.util.Properties; - -/** - *

      An interface that describes the necessary methods needed for common - * window management. An application may need to centrally manage the process - * of opening and closing new windows, as well as requests - * to end the program. This interface facilitates that capability. - * - * @author Mark Collette - * @since 2.0 - */ -public interface WindowManagementCallback { - public void newWindow(String path); - - public void newWindow(URL url); - - public void disposeWindow(SwingController controller, JFrame viewer, - Properties properties); - - public void minimiseAllWindows(); - - public void bringAllWindowsToFront(SwingController frontMost); - - public void bringWindowToFront(int index); - - public List getWindowDocumentOriginList(SwingController giveIndex); - - public void quit(SwingController controller, JFrame viewer, - Properties properties); - - public PropertiesManager getProperties(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/fonts/FindFontsTask.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/fonts/FindFontsTask.java deleted file mode 100644 index 0bf2474e3e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/fonts/FindFontsTask.java +++ /dev/null @@ -1,218 +0,0 @@ -package org.icepdf.ri.common.fonts; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.Resources; -import org.icepdf.core.pobjects.fonts.Font; -import org.icepdf.core.util.Library; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.SwingWorker; - -import javax.swing.*; -import java.awt.*; -import java.text.MessageFormat; -import java.util.HashMap; -import java.util.ResourceBundle; -import java.util.Set; - -/** - * This class is a utility for finding and reporting all font types in a document. Each page in the document - * is checked for valid font resources, if found the fonts are added to the calling FontDialog for addition to - * a JTree of know document fonts. - * - * {@link org.icepdf.ri.common.fonts.FontDialog} - * - * @since 6.1.3 - */ -public class FindFontsTask { - // total length of task, we keep track of the total number of pages processed. - private int lengthOfTask; - // current progress, used for the progress bar - private int current = 0; - // message displayed to user of progress made - private String dialogMessage; - // canned internationalized messages. - private MessageFormat searchingMessageForm; - - // flags for threading - private boolean done = false; - private boolean canceled = false; - - // parent swing controller - private SwingController controller; - - // append nodes for found fonts. - private FontDialog fontDialog; - - private boolean currentlySearching; - - private Container viewContainer; - - /** - * Creates a new instance of the SearchTextTask. - * - * @param fontDialog parent search panel that start this task via an action - * @param controller root controller object - * @param messageBundle message bundle used for dialog text. - */ - public FindFontsTask(FontDialog fontDialog, - SwingController controller, - ResourceBundle messageBundle) { - this.controller = controller; - this.fontDialog = fontDialog; - lengthOfTask = controller.getDocument().getNumberOfPages(); - this.viewContainer = controller.getDocumentViewController().getViewContainer(); - // setup searching format format. - searchingMessageForm = new MessageFormat(messageBundle.getString("viewer.dialog.fonts.searching.label")); - } - - /** - * Start the task, start searching the document for the pattern. - */ - public void go() { - final SwingWorker worker = new SwingWorker() { - public Object construct() { - current = 0; - done = false; - canceled = false; - dialogMessage = null; - return new FindFontsTask.ActualTask(); - } - }; - worker.setThreadPriority(Thread.NORM_PRIORITY); - worker.start(); - } - - /** - * Gets the page that is currently being searched by this task. - * - * @return current page being processed. - */ - public int getCurrent() { - return current; - } - - /** - * Stop the task. - */ - public void stop() { - canceled = true; - dialogMessage = null; - } - - /** - * Find out if the task has completed. - * - * @return true if task is done, false otherwise. - */ - public boolean isDone() { - return done; - } - - public boolean isCurrentlySearching() { - return currentlySearching; - } - - /** - * Returns the most recent dialog message, or null - * if there is no current dialog message. - * - * @return current message dialog text. - */ - public String getMessage() { - return dialogMessage; - } - - /** - * The actual long running task. This runs in a SwingWorker thread. - */ - private class ActualTask { - ActualTask() { - - try { - currentlySearching = true; - current = 0; - // little cache of fonts by reference so we don't load a font more then once. - HashMap fontCache = new HashMap(); - - Document document = controller.getDocument(); - // iterate over each page in the document - for (int i = 0; i < document.getNumberOfPages(); i++) { - // break if needed - if (canceled || done) { - resetDialogMessage(); - break; - } - // Update task information - current = i; - - // update search message in results pane. - int percent = (int) ((i / (float) lengthOfTask) * 100); - Object[] messageArguments = {String.valueOf(percent)}; - dialogMessage = searchingMessageForm.format(messageArguments); - - Library library = document.getCatalog().getLibrary(); - Page page = document.getPageTree().getPage(i); - page.initPageResources(); - Resources pageResources = page.getResources(); - if (pageResources != null) { - HashMap pageFonts = pageResources.getFonts(); - if (pageFonts != null && pageFonts.size() > 0) { - Set fontKeys = pageFonts.keySet(); - for (Object fontObjectReference : fontKeys) { - Object fontObject = pageFonts.get(fontObjectReference); - if (fontObject instanceof Reference) { - Reference fontReference = (Reference) fontObject; - // check if we already have this font - if (!fontCache.containsKey(fontReference)) { - fontObject = library.getObject(fontReference); - if (fontObject instanceof org.icepdf.core.pobjects.fonts.Font) { - final Font font = (Font) fontObject; - font.init(); - fontCache.put(fontReference, font); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - // add the node - fontDialog.addFoundEntry(font); - // try repainting the container - fontDialog.expandAllNodes(); - viewContainer.repaint(); - } - }); - } - } - } - } - - } - } - Thread.yield(); - } - // update the dialog and end the task - resetDialogMessage(); - - done = true; - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - currentlySearching = false; - } - - // repaint the view container - SwingUtilities.invokeLater(new Runnable() { - public void run() { - viewContainer.validate(); - } - }); - } - } - - - /** - * Utility method for setting the dialog message. - */ - private void resetDialogMessage() { - dialogMessage = ""; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/fonts/FontDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/fonts/FontDialog.java deleted file mode 100644 index 7f7c50d802..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/fonts/FontDialog.java +++ /dev/null @@ -1,465 +0,0 @@ -package org.icepdf.ri.common.fonts; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.fonts.Font; -import org.icepdf.ri.common.EscapeJDialog; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.SwingWorker; -import org.icepdf.ri.images.Images; -import org.icepdf.ri.util.FontPropertiesManager; -import org.icepdf.ri.util.PropertiesManager; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import javax.swing.tree.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; -import java.text.MessageFormat; -import java.util.ResourceBundle; - - -/** - * This class is a reference implementation for displaying a PDF file's - * font information. The dialog will start a worker thread that will read all the document's font objects and - * build a tree view of the all the fonts. This font view is primarily for debug purposes to make it easier to track - * font substitution results. The dialog also provides an easy way to refresh the - * "\.icesoft\icepdf-viewer\pdfviewerfontcache.properties' with out manually deleting the file and restarted the viewer. - * - * {@link org.icepdf.ri.common.fonts.FindFontsTask} - * @since 6.1.3 - */ -@SuppressWarnings("serial") -public class FontDialog extends EscapeJDialog implements ActionListener, WindowListener { - - // refresh rate of gui elements - private static final int TIMER_REFRESH = 20; - - // pointer to document which will be searched - private Document document; - private SwingController controller; - - // list box to hold search results - private JTree tree; - private DefaultMutableTreeNode rootTreeNode; - private DefaultTreeModel treeModel; - // font look up start on creation, but ok button will kill the the process and close the dialog. - private JButton okButton; - // clear and rescan system for fonts and rewrite file. - private JButton resetFontCacheButton; - - // task to complete in separate thread - protected FindFontsTask findFontsTask; - - // status label for font search - protected JLabel findMessage = new JLabel(); - - // time class to manage gui updates - protected Timer timer; - - // flag indicating if search is under way. - private boolean isFindignFonts; - - // message bundle for internationalization - private ResourceBundle messageBundle; - private MessageFormat typeMessageForm; - private MessageFormat encodingMessageForm; - private MessageFormat actualTypeMessageForm; - private MessageFormat actualFontMessageForm; - - // layouts constraint - private GridBagConstraints constraints; - - /** - * Create a new instance of SearchPanel. - * - * @param controller root SwingController - */ - public FontDialog(Frame frame, SwingController controller, boolean isModal) { - super(frame, isModal); - setFocusable(true); - this.controller = controller; - this.messageBundle = this.controller.getMessageBundle(); - setGui(); - setDocument(controller.getDocument()); - } - - public void setDocument(Document doc) { - // First have to stop any existing font searches, this shouldn't happen... - if (timer != null) - timer.stop(); - if (findFontsTask != null) { - findFontsTask.stop(); - while (findFontsTask.isCurrentlySearching()) { - try { - Thread.sleep(50L); - } catch (Exception e) { - // intentional - } - } - } - document = doc; - if (rootTreeNode != null) { - resetTree(); - // set title - String docTitle = getDocumentTitle(); - rootTreeNode.setUserObject(docTitle); - rootTreeNode.setAllowsChildren(true); - tree.setRootVisible((docTitle != null)); - } - // setup the new worker task. - if (findMessage != null) { - findMessage.setText(""); - } - - // start the task and the timer - findFontsTask = new FindFontsTask(this, controller, messageBundle); - findFontsTask.go(); - timer.start(); - isFindignFonts = true; - } - - /** - * Construct the GUI layout. - */ - private void setGui() { - - typeMessageForm = - new MessageFormat(messageBundle.getString("viewer.dialog.fonts.info.type.label")); - encodingMessageForm = - new MessageFormat(messageBundle.getString("viewer.dialog.fonts.info.encoding.label")); - actualTypeMessageForm = - new MessageFormat(messageBundle.getString("viewer.dialog.fonts.info.substitution.type.label")); - actualFontMessageForm = - new MessageFormat(messageBundle.getString("viewer.dialog.fonts.info.substitution.path.label")); - - setTitle(messageBundle.getString("viewer.dialog.fonts.title")); - setResizable(true); - - addWindowListener(this); - - // build the supporting tree objects - rootTreeNode = new DefaultMutableTreeNode(); - treeModel = new DefaultTreeModel(rootTreeNode); - - // build and customize the JTree - tree = new JTree(treeModel); - tree.setRootVisible(true); - tree.setExpandsSelectedPaths(true); - tree.setShowsRootHandles(true); - tree.setScrollsOnExpand(true); - tree.getSelectionModel().setSelectionMode( - TreeSelectionModel.SINGLE_TREE_SELECTION); - - // set look and feel to match outline style, consider revising with font type icons. - DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); - renderer.setOpenIcon(new ImageIcon(Images.get("page.gif"))); - renderer.setClosedIcon(new ImageIcon(Images.get("page.gif"))); - renderer.setLeafIcon(new ImageIcon(Images.get("page.gif"))); - tree.setCellRenderer(renderer); - - JScrollPane scrollPane = new JScrollPane(tree); - scrollPane.setPreferredSize(new Dimension(150, 75)); - - // setup refresh timer for the font scan progress. - timer = new Timer(TIMER_REFRESH, new TimerListener()); - - /** - * Build search GUI - */ - // content Panel - JPanel fontPropertiesPanel = new JPanel(new GridBagLayout()); - fontPropertiesPanel.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.dialog.fonts.border.label"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - this.setLayout(new BorderLayout(15, 15)); - this.add(fontPropertiesPanel, BorderLayout.CENTER); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.weighty = 0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(10, 15, 1, 15); - - // add the lit to scroll pane - constraints.fill = GridBagConstraints.BOTH; - constraints.insets = new Insets(10, 15, 10, 15); - constraints.weightx = 1.0; - constraints.weighty = 1.0; - addGB(fontPropertiesPanel, scrollPane, 0, 1, 2, 1); - - // add find message - constraints.insets = new Insets(2, 10, 2, 10); - constraints.weighty = 0; - constraints.fill = GridBagConstraints.NONE; - constraints.anchor = GridBagConstraints.WEST; - findMessage.setAlignmentX(JLabel.RIGHT_ALIGNMENT); - addGB(fontPropertiesPanel, findMessage, 0, 2, 2, 1); - - resetFontCacheButton = new JButton(messageBundle.getString("viewer.dialog.fonts.resetCache.label")); - resetFontCacheButton.setToolTipText(messageBundle.getString("viewer.dialog.fonts.resetCache.tip")); - resetFontCacheButton.addActionListener(this); - constraints.insets = new Insets(2, 10, 2, 10); - constraints.weighty = 0; - constraints.fill = GridBagConstraints.NONE; - constraints.anchor = GridBagConstraints.WEST; - addGB(fontPropertiesPanel, resetFontCacheButton, 0, 3, 1, 1); - - okButton = new JButton(messageBundle.getString("viewer.button.ok.label")); - okButton.addActionListener(this); - constraints.insets = new Insets(2, 10, 2, 10); - constraints.weighty = 0; - constraints.fill = GridBagConstraints.NONE; - constraints.anchor = GridBagConstraints.EAST; - addGB(fontPropertiesPanel, okButton, 1, 4, 1, 1); - - setSize(640, 480); - setLocationRelativeTo(getOwner()); - } - - /** - * Adds a new node item to the treeModel. - * - * @param font font used to build node properties. - */ - public void addFoundEntry(Font font) { - DefaultMutableTreeNode fontNode = new DefaultMutableTreeNode(font.getBaseFont(), true); - // add type sub node for type - insertNode(font.getSubType(), typeMessageForm, fontNode); - // add encoding. - insertNode(font.getEncoding(), encodingMessageForm, fontNode); - // add font substitution info. - if (font.isFontSubstitution() && font.getFont() != null) { - insertNode(font.getFont().getName(), actualTypeMessageForm, fontNode); - insertNode(font.getFont().getSource(), actualFontMessageForm, fontNode); - } - addObject(rootTreeNode, fontNode); - - // expand the root node, we only do this once. - tree.expandPath(new TreePath(rootTreeNode)); - } - - /** - * Utility to aid in the creation of a new font properties node. - * @param label label for node. - * @param messageFormat message formatter - * @param parent parent node. - */ - private void insertNode(Object label, MessageFormat messageFormat, DefaultMutableTreeNode parent) { - if (label != null) { - Object[] messageArguments = {label.toString()}; - label = messageFormat.format(messageArguments); - DefaultMutableTreeNode encodingNode = new DefaultMutableTreeNode(label, true); - addObject(parent, encodingNode); - } - } - - /** - * Utility for adding a tree node. - * - * @param parent parent to add the node too. - * @param childNode node to add. - */ - private void addObject(DefaultMutableTreeNode parent, - DefaultMutableTreeNode childNode) { - if (parent == null) { - parent = rootTreeNode; - } - //It is key to invoke this on the TreeModel, and NOT DefaultMutableTreeNode - treeModel.insertNodeInto(childNode, parent, - parent.getChildCount()); - } - - // quick and dirty expand all. - protected void expandAllNodes() { - int rowCount = tree.getRowCount(); - int i = 0; - while (i < rowCount) { - tree.expandRow(i); - i += 1; - rowCount = tree.getRowCount(); - } - } - - /** - * Reset the tree, insuring it's empty - */ - protected void resetTree() { - tree.setSelectionPath(null); - rootTreeNode.removeAllChildren(); - treeModel.nodeStructureChanged(rootTreeNode); - } - - /** - * Utility for getting the document title. - * - * @return document title, if non title then a simple search results - * label is returned; - */ - private String getDocumentTitle() { - String documentTitle = null; - if (document != null && document.getInfo() != null) { - documentTitle = document.getInfo().getTitle(); - } - if ((documentTitle == null) || (documentTitle.trim().length() == 0)) { - return null; - } - return documentTitle; - } - - /** - * Insure the font search process is killed when the dialog is closed via the 'esc' key. - */ - @Override - public void dispose() { - super.dispose(); - closeWindowOperations(); - } - - /** - * Two main actions are handle here, search and clear search. - * - * @param event awt action event. - */ - public void actionPerformed(ActionEvent event) { - if (event.getSource() == okButton) { - // clean up the timer and worker thread. - closeWindowOperations(); - dispose(); - } else if (event.getSource() == resetFontCacheButton) { - // reset the font properties cache. - resetFontCacheButton.setEnabled(false); - SwingWorker worker = new SwingWorker() { - public Object construct() { - PropertiesManager properties = new PropertiesManager( - System.getProperties(), - ResourceBundle.getBundle(PropertiesManager.DEFAULT_MESSAGE_BUNDLE)); - FontPropertiesManager fontPropertiesManager = new FontPropertiesManager(properties, - System.getProperties(), messageBundle); - fontPropertiesManager.clearProperties(); - fontPropertiesManager.readDefaulFontPaths(null); - fontPropertiesManager.saveProperties(); - resetFontCacheButton.setEnabled(true); - - Runnable doSwingWork = new Runnable() { - public void run() { - resetFontCacheButton.setEnabled(true); - } - }; - SwingUtilities.invokeLater(doSwingWork); - return null; - } - }; - worker.setThreadPriority(Thread.MIN_PRIORITY); - worker.start(); - } - } - - protected void closeWindowOperations() { - // clean up the timer and worker thread. - if (timer != null && timer.isRunning()) timer.stop(); - if (findFontsTask != null && findFontsTask.isCurrentlySearching()) findFontsTask.stop(); - setVisible(false); - } - - - /** - * Gridbag constructor helper - * - * @param panel parent adding component too. - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan rowspane of field - * @param colSpan colspane of field. - */ - private void addGB(JPanel panel, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - panel.add(component, constraints); - } - - - public void windowOpened(WindowEvent e) { - - } - - public void windowClosing(WindowEvent e) { - closeWindowOperations(); - } - - public void windowClosed(WindowEvent e) { - closeWindowOperations(); - } - - public void windowIconified(WindowEvent e) { - - } - - public void windowDeiconified(WindowEvent e) { - - } - - public void windowActivated(WindowEvent e) { - - } - - public void windowDeactivated(WindowEvent e) { - - } - - /** - * The actionPerformed method in this class - * is called each time the Timer "goes off". - */ - class TimerListener implements ActionListener { - public void actionPerformed(ActionEvent evt) { - String s = findFontsTask.getMessage(); - if (s != null) { - findMessage.setText(s); - } - // update the text when the search is completed - if (findFontsTask.isDone() || !isFindignFonts) { - // update search status, blank it. - findMessage.setText(""); - timer.stop(); - findFontsTask.stop(); - } - } - } - - /** - * An Entry objects represents the found pages - */ - - @SuppressWarnings("serial") - class FontEntry extends DefaultMutableTreeNode { - - // The text to be displayed on the screen for this item. - String title; - - - /** - * Creates a new instance of a FindEntry. - * - * @param title display title - * @param pageNumber page number where the hit(s) occured - */ - FontEntry(String title, int pageNumber) { - super(); - this.title = title; - setUserObject(title); - } - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/search/DocumentSearchControllerImpl.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/search/DocumentSearchControllerImpl.java deleted file mode 100644 index cdab218bef..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/search/DocumentSearchControllerImpl.java +++ /dev/null @@ -1,551 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.search; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.graphics.text.LineText; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.pobjects.graphics.text.WordText; -import org.icepdf.core.search.DocumentSearchController; -import org.icepdf.core.search.SearchTerm; -import org.icepdf.ri.common.SwingController; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Document search controller used to manage document searches. This class - * class takes care of many of the performance issues of doing searches on - * larges documents and is also used by PageViewComponentImpl to highlight - * search results. - *

      - * This implementation uses simple search algorithm that will work well for most - * users. This class can be extended and the method {@link #searchHighlightPage(int)} - * can be overridden for custom search implementations. - *

      - * The DocumentSearchControllerImpl can be constructed to be used with the - * Viewer RI source code via the constructor that takes a SwingController as - * a parameter. The second variation is ended for a headless environment where - * Swing is not needed, the constructor for this instance takes a Document - * as a parameter. - * - * @since 4.0 - */ -public class DocumentSearchControllerImpl implements DocumentSearchController { - - private static final Logger logger = - Logger.getLogger(DocumentSearchControllerImpl.class.toString()); - - // search model contains caching and memory optimizations. - protected DocumentSearchModelImpl searchModel; - // parent controller used to get at RI controllers and models. - protected SwingController viewerController; - // assigned document for headless searching. - protected Document document; - - /** - * Create a news instance of search controller. A search model is created - * for this instance. - * - * @param viewerController parent controller/mediator. - */ - public DocumentSearchControllerImpl(SwingController viewerController) { - this.viewerController = viewerController; - searchModel = new DocumentSearchModelImpl(); - } - - /** - * Create a news instance of search controller intended to be used in a - * headless environment. A search model is created for this instance. - * - * @param document document to search. - */ - public DocumentSearchControllerImpl(Document document) { - searchModel = new DocumentSearchModelImpl(); - this.document = document; - } - - /** - * Searches the given page using the specified term and properties. The - * search model is updated to store the pages Page text as a weak reference - * which can be queried using isSearchHighlightNeeded to efficiently make - * sure that a pages text is highlighted even after a dispose/init cycle. - * If the text state is no longer present then the search should be executed - * again. - *

      - * This method clears the search results for the page before it searches. If - * you wish to have cumulative search results then searches terms should - * be added with {@link #addSearchTerm(String, boolean, boolean)} and the - * method {@link #searchPage(int)} should be called after each term is - * added or after all have been added. - * - * @param pageIndex page to search - * @param caseSensitive if true use case sensitive searches - * @param wholeWord if true use whole word searches - * @param term term to search for - * @return number for hits for this page. - */ - public int searchHighlightPage(int pageIndex, String term, - boolean caseSensitive, boolean wholeWord) { - // clear previous search - clearSearchHighlight(pageIndex); - // add the search term - addSearchTerm(term, caseSensitive, wholeWord); - // start the search and return the hit count. - return searchHighlightPage(pageIndex); - } - - /** - * Searches the page index given the search terms that have been added - * with {@link #addSearchTerm(String, boolean, boolean)}. If search - * hits where detected then the Page's PageText is added to the cache. - *

      - * This method represent the core search algorithm for this - * DocumentSearchController implementation. This method can be over riden - * if a different search algorithm or functionality is needed. - * - * @param pageIndex page index to search - * @return number of hits found for this page. - */ - public int searchHighlightPage(int pageIndex) { - - // get search terms from model and search for each occurrence. - Collection terms = searchModel.getSearchTerms(); - - // search hit count - int hitCount = 0; - - // get our our page text reference - PageText pageText = getPageText(pageIndex); - - // some pages just don't have any text. - if (pageText == null) { - return 0; - } - - // we need to do the search for each term. - for (SearchTerm term : terms) { - - // found word index to keep track of when we have found a hit - int searchPhraseHitCount = 0; - int searchPhraseFoundCount = term.getTerms().size(); - // list of found words for highlighting, as hits can span - // lines and pages - ArrayList searchPhraseHits = - new ArrayList(searchPhraseFoundCount); - - // start iteration over words. - ArrayList pageLines = pageText.getPageLines(); - if (pageLines != null) { - for (LineText pageLine : pageLines) { - java.util.List lineWords = pageLine.getWords(); - // compare words against search terms. - String wordString; - for (WordText word : lineWords) { - // apply case sensitivity rule. - wordString = term.isCaseSensitive() ? word.toString() : - word.toString().toLowerCase(); - // word matches, we have to match full word hits - if (term.isWholeWord()) { - if (wordString.equals( - term.getTerms().get(searchPhraseHitCount))) { - // add word to potentials - searchPhraseHits.add(word); - searchPhraseHitCount++; - } - // else if (wordString.length() == 1 && - // WordText.isPunctuation(wordString.charAt(0))){ - // // ignore punctuation - // searchPhraseHitCount++; - // } - // reset the counters. - else { - searchPhraseHits.clear(); - searchPhraseHitCount = 0; - } - } - // otherwise we look for an index of hits - else { - // found a potential hit, depends on the length - // of searchPhrase. - if (wordString.contains(term.getTerms().get(searchPhraseHitCount))) { - // add word to potentials - searchPhraseHits.add(word); - searchPhraseHitCount++; - } - // else if (wordString.length() == 1 && - // WordText.isPunctuation(wordString.charAt(0))){ - // // ignore punctuation - // searchPhraseHitCount++; - // } - // reset the counters. - else { - searchPhraseHits.clear(); - searchPhraseHitCount = 0; - } - - } - // check if we have found what we're looking for - if (searchPhraseHitCount == searchPhraseFoundCount) { - // iterate of found, highlighting words - for (WordText wordHit : searchPhraseHits) { - wordHit.setHighlighted(true); - wordHit.setHasHighlight(true); - } - - // rest counts and start over again. - hitCount++; - searchPhraseHits.clear(); - searchPhraseHitCount = 0; - } - - } - } - } - } - - // if we have a hit we'll add it to the model cache - if (hitCount > 0) { - searchModel.addPageSearchHit(pageIndex, pageText); - if (logger.isLoggable(Level.FINE)) { - logger.fine("Found search hits on page " + pageIndex + - " hit count " + hitCount); - } - } - - return hitCount; - } - - /** - * Searches the page index given the search terms that have been added - * with {@link #addSearchTerm(String, boolean, boolean)}. If search - * hits where detected then the Page's PageText is added to the cache. - *

      - * This class differences from {@link #searchHighlightPage(int)} in that - * is returns a list of lineText fragments for each hit but the LinText - * is padded by pre and post words that surround the hit in the page - * context. - *

      - * This method represent the core search algorithm for this - * DocumentSearchController implementation. This method can be over riden - * if a different search algorithm or functionality is needed. - * - * @param pageIndex page index to search - * @param wordPadding word padding on either side of hit to give context - * to found words in the returned LineText - * @return list of contextual hits for the give page. If no hits an empty - * list is returned. - */ - public ArrayList searchHighlightPage(int pageIndex, int wordPadding) { - // get search terms from model and search for each occurrence. - Collection terms = searchModel.getSearchTerms(); - - // search hit list - ArrayList searchHits = new ArrayList(); - - // get our our page text reference - PageText pageText = getPageText(pageIndex); - - // some pages just don't have any text. - if (pageText == null) { - return searchHits; - } - - // we need to do the search for each term. - for (SearchTerm term : terms) { - - // found word index to keep track of when we have found a hit - int searchPhraseHitCount = 0; - int searchPhraseFoundCount = term.getTerms().size(); - // list of found words for highlighting, as hits can span - // lines and pages - ArrayList searchPhraseHits = - new ArrayList(searchPhraseFoundCount); - - // start iteration over words. - ArrayList pageLines = pageText.getPageLines(); - if (pageLines != null) { - for (LineText pageLine : pageLines) { - java.util.List lineWords = pageLine.getWords(); - // compare words against search terms. - String wordString; - WordText word; - for (int i = 0, max = lineWords.size(); i < max; i++) { - word = lineWords.get(i); - - // apply case sensitivity rule. - wordString = term.isCaseSensitive() ? word.toString() : - word.toString().toLowerCase(); - // word matches, we have to match full word hits - if (term.isWholeWord()) { - if (wordString.equals( - term.getTerms().get(searchPhraseHitCount))) { - // add word to potentials - searchPhraseHits.add(word); - searchPhraseHitCount++; - } - // reset the counters. - else { - searchPhraseHits.clear(); - searchPhraseHitCount = 0; - } - } - // otherwise we look for an index of hits - else { - // found a potential hit, depends on the length - // of searchPhrase. - if (wordString.contains(term.getTerms().get(searchPhraseHitCount))) { - // add word to potentials - searchPhraseHits.add(word); - searchPhraseHitCount++; - } - // reset the counters. - else { - searchPhraseHits.clear(); - searchPhraseHitCount = 0; - } - - } - // check if we have found what we're looking for - if (searchPhraseHitCount == searchPhraseFoundCount) { - - LineText lineText = new LineText(); - int lineWordsSize = lineWords.size(); - java.util.List hitWords = lineText.getWords(); - // add pre padding - int start = i - searchPhraseHitCount - wordPadding + 1; - start = start < 0 ? 0 : start; - int end = i - searchPhraseHitCount + 1; - end = end < 0 ? 0 : end; - for (int p = start; p < end; p++) { - hitWords.add(lineWords.get(p)); - } - - // iterate of found, highlighting words - for (WordText wordHit : searchPhraseHits) { - wordHit.setHighlighted(true); - wordHit.setHasHighlight(true); - } - hitWords.addAll(searchPhraseHits); - - // add word padding to front of line - start = i + 1; - start = start > lineWordsSize ? lineWordsSize : start; - end = start + wordPadding; - end = end > lineWordsSize ? lineWordsSize : end; - for (int p = start; p < end; p++) { - hitWords.add(lineWords.get(p)); - } - - // add the hits to our list. - searchHits.add(lineText); - - searchPhraseHits.clear(); - searchPhraseHitCount = 0; - } - - } - } - } - } - - // if we have a hit we'll add it to the model cache - if (searchHits.size() > 0) { - searchModel.addPageSearchHit(pageIndex, pageText); - if (logger.isLoggable(Level.FINE)) { - logger.fine("Found search hits on page " + pageIndex + - " hit count " + searchHits.size()); - } - } - - return searchHits; - } - - /** - * Search page but only return words that are hits. Highlighting is till - * applied but this method can be used if other data needs to be extracted - * from the found words. - * - * @param pageIndex page to search - * @return list of words that match the term and search properties. - */ - public ArrayList searchPage(int pageIndex) { - - int hits = searchHighlightPage(pageIndex); - if (hits > 0) { - PageText searchText = searchModel.getPageTextHit(pageIndex); - if (searchText != null) { - ArrayList words = new ArrayList(hits); - ArrayList pageLines = searchText.getPageLines(); - if (pageLines != null) { - for (LineText pageLine : pageLines) { - java.util.List lineWords = pageLine.getWords(); - if (lineWords != null) { - for (WordText word : lineWords) { - if (word.isHighlighted()) { - words.add(word); - } - } - } - } - } - return words; - } - } - return null; - } - - /** - * Add the search term to the list of search terms. The term is split - * into words based on white space and punctuation. No checks are done - * for duplication. - *

      - * A new search needs to be executed for this change to take place. - * - * @param term single word or phrase to search for. - * @param caseSensitive is search case sensitive. - * @param wholeWord is search whole word sensitive. - * @return searchTerm newly create search term. - */ - public SearchTerm addSearchTerm(String term, boolean caseSensitive, - boolean wholeWord) { - // keep origional copy - String origionalTerm = String.valueOf(term); - - // check criteria for case sensitivity. - if (!caseSensitive) { - term = term.toLowerCase(); - } - // parse search term out into words, so we can match - // them against WordText - ArrayList searchPhrase = searchPhraseParser(term); - // finally add the search term to the list and return it for management - SearchTerm searchTerm = - new SearchTerm(origionalTerm, searchPhrase, caseSensitive, wholeWord); - searchModel.addSearchTerm(searchTerm); - return searchTerm; - } - - /** - * Removes the specified search term from the search. A new search needs - * to be executed for this change to take place. - * - * @param searchTerm search term to remove. - */ - public void removeSearchTerm(SearchTerm searchTerm) { - searchModel.removeSearchTerm(searchTerm); - } - - /** - * Clear all searched items for specified page. - * - * @param pageIndex page indext to clear - */ - public void clearSearchHighlight(int pageIndex) { - // clear cache and terms list - searchModel.clearSearchResults(pageIndex); - } - - /** - * Clears all highlighted text states for this this document. This optimized - * to use the the SearchHighlightModel to only clear pages that still have - * selected states. - */ - public void clearAllSearchHighlight() { - searchModel.clearSearchResults(); - } - - /** - * Test to see if a search highlight is needed. This is done by first - * check if there is a hit for this page and if the PageText object is the - * same as the one specified as a param. If they are not the same PageText - * object then we need to do refresh as the page was disposed and - * reinitialized with new content. - * - * @param pageIndex page index to text for results. - * @param pageText current pageText object associated with the pageIndex. - * @return true if refresh is needed, false otherwise. - */ - public boolean isSearchHighlightRefreshNeeded(int pageIndex, PageText pageText) { - - // check model to see if pages pagTex still has reference - return searchModel.isPageTextMatch(pageIndex, pageText); - } - - /** - * Disposes controller clearing resources. - */ - public void dispose() { - searchModel.clearSearchResults(); - } - - /** - * Gets teh page text for the given page index. - * - * @param pageIndex page index of page to extract text. - * @return page's page text, can be null. - */ - protected PageText getPageText(int pageIndex) { - PageText pageText = null; - try { - if (viewerController != null) { - // get access to currently open document instance. - pageText = viewerController.getDocument().getPageViewText(pageIndex); - } else if (document != null) { - pageText = document.getPageViewText(pageIndex); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("PageText extraction thread was interrupted."); - } - return pageText; - } - - /** - * Utility for breaking the pattern up into searchable words. Breaks are - * done on white spaces and punctuation. - * - * @param phrase pattern to search words for. - * @return list of words that make up phrase, words, spaces, punctuation. - */ - protected ArrayList searchPhraseParser(String phrase) { - // trim white space, not really useful. - phrase = phrase.trim(); - // found words. - ArrayList words = new ArrayList(); - char c; - char cPrev = 0; - for (int start = 0, curs = 0, max = phrase.length(); curs < max; curs++) { - c = phrase.charAt(curs); - if (WordText.isWhiteSpace(c) || (WordText.isPunctuation(c) && !WordText.isDigit(cPrev))) { - // add word segment - if (start != curs) { - words.add(phrase.substring(start, curs)); - } - // add white space as word too. - words.add(phrase.substring(curs, curs + 1)); - // start - start = curs + 1 < max ? curs + 1 : start; - } else if (curs + 1 == max) { - words.add(phrase.substring(start, curs + 1)); - } - cPrev = c; - } - return words; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/search/DocumentSearchModelImpl.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/search/DocumentSearchModelImpl.java deleted file mode 100644 index 68ed53095b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/search/DocumentSearchModelImpl.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.search; - -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.search.SearchTerm; - -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Set; - -/** - * Document search model is used by the DocumentSearchController as a way to - * cache search results. PDF document in general can be to big to keep all - * data in memory at once. ICEpdf uses a dispose/initialization on Page data - * as memory is needed. When this happens the selected text data will be lost - * and we have to research the page in question the next time it is viewed. - *

      - * This model can be used in two ways; the first is to store search terms and - * the second is to keep a record of page indexes that have search results. The - * later uses weak references to make sure we don't leak any memory. If the - * page has no data available in its weak reference then we can get it. If - * a there is no value for a given page index then we know the page had no - * search hits and we can ignore it. - * - * @since 4.0 - */ -public class DocumentSearchModelImpl { - - // cache to detect page dispose/initialize cycle so that we can research when - // needed. - private HashMap> searchResultCache; - - // list of terms that made up the full search, usually just one, but - // you never know. - private ArrayList searchTerms; - - /** - * Creates a new instance with empty search terms and search result caches. - */ - public DocumentSearchModelImpl() { - searchResultCache = new HashMap>(256); - searchTerms = new ArrayList(); - } - - /** - * Gets a list of search terms that make up a given search. - * - * @return list of search term, maybe empty but not null. - */ - public ArrayList getSearchTerms() { - return searchTerms; - } - - /** - * Add a search term to the model. - * - * @param searchTerm search term, no checking is done for invalid data. - */ - public void addSearchTerm(SearchTerm searchTerm) { - searchTerms.add(searchTerm); - } - - /** - * Remove the specified search term from the model. - * - * @param searchTerm search term to remove. - */ - public void removeSearchTerm(SearchTerm searchTerm) { - searchTerms.remove(searchTerm); - } - - /** - * Add a search result hit for a given page. A page can have 1 or more - * hits but all that matters is that there is at least one hit to manage. - * The index and PageText Object is stored in the cache. - * - * @param pageIndex page index of search hit(s) - * @param pageText PageText for the given page index. - */ - public void addPageSearchHit(int pageIndex, PageText pageText) { - searchResultCache.put(pageIndex, new WeakReference(pageText)); - } - - /** - * Gets a set of page hit page indexes. That is to say a list of all page - * indexes that have search hits. This list can be used to clear searches - * or to iterate more quickly of the results set. - * - * @return set of page indexes that have a least one search result hit. - */ - public Set getPageSearchHits() { - return searchResultCache.keySet(); - } - - /** - * Check the page index to see if there is a search result. - * - * @param pageIndex index of page to search - * @return true if page has search result, false otherwise. - */ - public boolean isPageSearchHit(int pageIndex) { - return searchResultCache.get(pageIndex) != null; - } - - public PageText getPageTextHit(int pageIndex) { - WeakReference ref = searchResultCache.get(pageIndex); - if (ref.get() != null) { - return ref.get(); - } else { - return null; - } - } - - /** - * When we know a page has a hit but aren't sure if pageText is still in a - * highlighted state we can use this method to check. If the weak reference - * for the pageIndex exists we can compare it against the parameter pageText. - * If the objects are equal there is no need to search again. If reference - * is null or not equal then we have to do the search again to get the - * highlight state back. Pages searches in general are extremely fast and - * performs better then trying to keep everything in memory. - *

      - * - * @param pageIndex page index to look at PageText results - * @param pageText current Page objects PageText object we want to check - * against whats in the cache. - * @return false if the search for this page should be done again, otherwise - * true then we should be ok and don't need to refresh the text state. - */ - public boolean isPageTextMatch(int pageIndex, PageText pageText) { - WeakReference ref = searchResultCache.get(pageIndex); - if (ref == null) { - return false; - } - PageText matchText = ref.get(); - return matchText == null || !matchText.equals(pageText); - } - - /** - * Clears cached search results for this page index and clears the highlighted - * state for this page. - * - * @param page page index to clear search results from. - */ - public void clearSearchResults(int page) { - // clear highlighted state for this page index. - WeakReference pageReference = searchResultCache.get(page); - if (pageReference != null) { - PageText currentPageText = pageReference.get(); - if (currentPageText != null) { - currentPageText.clearHighlighted(); - } - } - // clear caches. - searchResultCache.remove(page); - } - - /** - * Clears all search results and highlight states found in the research - * results cache. This method is especially useful for large documents. - */ - public void clearSearchResults() { - - // reset highlights - // get list of searched results and clear pages. - Collection> pagTextHits = searchResultCache.values(); - PageText currentPageText; - for (WeakReference pageIndex : pagTextHits) { - currentPageText = pageIndex.get(); - if (currentPageText != null) { - currentPageText.clearHighlighted(); - } - } - // clear caches. - searchResultCache.clear(); - searchTerms.clear(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/AnnotationSelectionHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/AnnotationSelectionHandler.java deleted file mode 100644 index f130a78386..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/AnnotationSelectionHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; - -/** - * The AnnotationSelectionHandler is responsible for deselecting all annotations - * when the a mouse click event has been fired. - * - * @since 5.0 - */ -public class AnnotationSelectionHandler extends MouseAdapter - implements ToolHandler { - - protected DocumentViewController documentViewController; - protected DocumentViewModel documentViewModel; - protected AbstractPageViewComponent pageViewComponent; - - public AnnotationSelectionHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - this.documentViewController = documentViewController; - this.documentViewModel = documentViewModel; - this.pageViewComponent = pageViewComponent; - } - - public void mouseClicked(MouseEvent e) { - documentViewController.clearSelectedAnnotations(); - if (pageViewComponent != null) - pageViewComponent.requestFocus(); - } - - public void paintTool(Graphics g) { - // nothing to paint - } - - public void mouseDragged(MouseEvent e) { - - } - - public void mouseMoved(MouseEvent e) { - - } - - public void installTool() { - - } - - public void uninstallTool() { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/CircleAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/CircleAnnotationHandler.java deleted file mode 100644 index dbee6b8b3f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/CircleAnnotationHandler.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.AnnotationFactory; -import org.icepdf.core.pobjects.annotations.CircleAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.AnnotationCallback; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.AnnotationComponentFactory; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.Ellipse2D; - -/** - * CircleAnnotationHandler tool is responsible for painting representation of - * a circle on the screen during a click and drag mouse event. The box - * created by this mouse event will be used to draw circle within its bounds. - *

      - * Once the mouseReleased event is fired this handler will create new - * CircleAnnotation and respective AnnotationComponent. The addition of the - * Annotation object to the page is handled by the annotation callback. - * - * @since 5.0 - */ -public class CircleAnnotationHandler extends SquareAnnotationHandler { - public CircleAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - } - - /** - * Paint a rough circle representing what the annotation will look like - * when created. - * - * @param g graphics context - */ - public void paintTool(Graphics g) { - if (rectangle != null) { - - Ellipse2D.Double circle = new Ellipse2D.Double( - rectangle.getMinX(), - rectangle.getMinY(), - rectangle.getWidth(), - rectangle.getHeight()); - - Graphics2D gg = (Graphics2D) g; - Color oldColor = gg.getColor(); - Stroke oldStroke = gg.getStroke(); - gg.setStroke(stroke); -// gg.setColor(internalColor); -// gg.fill(circle); - gg.setColor(lineColor); - gg.draw(circle); - g.setColor(oldColor); - gg.setStroke(oldStroke); - } - } - - /** - * Create the annotation objects need to draw and manipulated the annotation - * using the GUI properties panels. - * - * @param e mouse event. - */ - public void mouseReleased(MouseEvent e) { - updateSelectionSize(e.getX(),e.getY(), pageViewComponent); - - // convert the rectangle to page space - rectangle = convertToPageSpace(rectangle); - - // check to make sure the bbox isn't zero height or width - rectToDraw.setRect(rectToDraw.getX() - DEFAULT_STROKE_WIDTH, - rectToDraw.getY() - DEFAULT_STROKE_WIDTH, - rectToDraw.getWidth() + DEFAULT_STROKE_WIDTH * 2, - rectToDraw.getHeight() + DEFAULT_STROKE_WIDTH * 2); - - // convert tBbox - Rectangle tBbox = convertToPageSpace(rectToDraw); - - // create annotations types that that are rectangle based; - // which is actually just link annotations - CircleAnnotation annotation = (CircleAnnotation) - AnnotationFactory.buildAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - Annotation.SUBTYPE_CIRCLE, - tBbox); - annotation.setColor(lineColor); - if (annotation.isFillColor()) { - annotation.setFillColor(internalColor); - } - annotation.setRectangle(rectangle); - annotation.setBorderStyle(borderStyle); - - // pass outline shapes and bounds to create the highlight shapes - annotation.setBBox(new Rectangle(0, 0, tBbox.width, tBbox.height)); - annotation.resetAppearanceStream(getPageTransform()); - - // create the annotation object. - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, - documentViewController, - pageViewComponent, documentViewModel); - // set the bounds and refresh the userSpace rectangle - Rectangle bbox = new Rectangle(rectToDraw.x, rectToDraw.y, - rectToDraw.width, rectToDraw.height); - comp.setBounds(bbox); - // resets user space rectangle to match bbox converted to page space - comp.refreshAnnotationRect(); - - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - - // set the annotation tool to he select tool - documentViewController.getParentController().setDocumentToolMode( - DocumentViewModel.DISPLAY_TOOL_SELECTION); - - rectangle = null; - // clear the rectangle - clearRectangle(pageViewComponent); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/CommonToolHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/CommonToolHandler.java deleted file mode 100644 index ea7350be08..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/CommonToolHandler.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.geom.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Common logic to all annotation handlers. - * - * @since 5.0 - */ -public class CommonToolHandler { - - private static final Logger logger = - Logger.getLogger(CommonToolHandler.class.toString()); - - // parent page component - protected AbstractPageViewComponent pageViewComponent; - protected DocumentViewController documentViewController; - protected DocumentViewModel documentViewModel; - - /** - * Create a new common tool handler. The tool handle can operate on a view or at the page level. If the - * handler only operates at the view level then pageViewComponent can be set to null; - * - * @param documentViewController parent view controller - * @param pageViewComponent page view component tool acts on, can be null for view tool handlers. - * @param documentViewModel parent document model - */ - public CommonToolHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - this.pageViewComponent = pageViewComponent; - this.documentViewController = documentViewController; - this.documentViewModel = documentViewModel; - } - - protected AffineTransform getPageTransform() { - return getPageTransform(pageViewComponent); - } - - protected AffineTransform getPageTransform(AbstractPageViewComponent pageViewComponent) { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error page space transform", e); - } - return at; - } - - - /** - * Convert the shapes that make up the annotation to page space so that - * they will scale correctly at different zooms. - * - * @return transformed bBox. - */ - protected Shape convertToPageSpace(Shape shape) { - return convertToPageSpace(pageViewComponent, shape); - } - - protected Shape convertToPageSpace(AbstractPageViewComponent pageViewComponent, Shape shape) { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error converting to page space", e); - } - shape = at.createTransformedShape(shape); - return shape; - - } - - protected Point2D[] convertToPageSpace(Point2D start, Point2D end) { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error converting to page space", e); - } - at.transform(start, start); - at.transform(end, end); - - return new Point2D[]{start, end}; - } - - /** - * Convert the mouse coordinates to the space specified by the pageTransform - * matrix. This is a utility method for converting the mouse coordinates - * to page space so that it can be used in a contains calculation for text - * selection. - * - * @param mousePoint point to convert space of - * @param pageTransform transform - * @return page space mouse coordinates. - */ - protected Point2D.Float convertMouseToPageSpace(Point mousePoint, - AffineTransform pageTransform) { - Point2D.Float pageMouseLocation = new Point2D.Float(); - try { - pageTransform.createInverse().transform( - mousePoint, pageMouseLocation); - } catch (NoninvertibleTransformException e) { - logger.log(Level.SEVERE, - "Error converting mouse point to page space.", e); - } - return pageMouseLocation; - } - - /** - * Converts the rectangle to the space specified by the page transform. This - * is a utility method for converting a selection rectangle to page space - * so that an intersection can be calculated to determine a selected state. - * - * @param mouseRect rectangle to convert space of - * @param pageTransform page transform - * @return converted rectangle. - */ - protected Rectangle2D convertRectangleToPageSpace(Rectangle mouseRect, - AffineTransform pageTransform) { - GeneralPath shapePath; - try { - AffineTransform transform = pageTransform.createInverse(); - shapePath = new GeneralPath(mouseRect); - shapePath.transform(transform); - return shapePath.getBounds2D(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.SEVERE, - "Error converting mouse point to page space.", e); - } - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/DynamicZoomHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/DynamicZoomHandler.java deleted file mode 100644 index eb88c59093..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/DynamicZoomHandler.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.ri.common.views.DocumentViewController; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.util.logging.Logger; - -/** - * Handles dynamic zoom which picks up on the mouse wheel rotation to zoom - * in or out depending on the direction. - * - * @since 5.0 - */ -public class DynamicZoomHandler implements ToolHandler, MouseWheelListener { - - private static final Logger logger = - Logger.getLogger(ZoomOutPageHandler.class.toString()); - - private DocumentViewController documentViewController; - protected JScrollPane documentScrollPane; - - public DynamicZoomHandler(DocumentViewController documentViewController, - JScrollPane documentScrollPane) { - this.documentViewController = documentViewController; - this.documentScrollPane = documentScrollPane; - } - - /** - * Handles ctl-wheel mouse for document zooming. - * - * @param e mouse wheel event. - */ - public void mouseWheelMoved(MouseWheelEvent e) { - int rotation = e.getWheelRotation(); - // turn off scroll on zoom and then back on again next time - // the wheel is used with out the ctrl mask. - documentScrollPane.setWheelScrollingEnabled(false); - Point offset = documentScrollPane.getViewport().getViewPosition(); - int viewWidth = documentScrollPane.getViewport().getWidth() / 2; - int viewHeight = documentScrollPane.getViewport().getHeight() / 2; - offset.setLocation(offset.x + viewWidth, offset.y + viewHeight); - if (rotation > 0) { - documentViewController.setZoomOut(offset); - } else { - documentViewController.setZoomIn(offset); - } - - } - - - public void mouseClicked(MouseEvent e) { - - } - - public void mouseDragged(MouseEvent e) { - } - - public void mouseMoved(MouseEvent e) { - } - - public void mousePressed(MouseEvent e) { - - } - - public void mouseReleased(MouseEvent e) { - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void paintTool(Graphics g) { - - } - - public void installTool() { - documentScrollPane.setWheelScrollingEnabled(false); - documentScrollPane.addMouseWheelListener(this); - } - - public void uninstallTool() { - documentScrollPane.setWheelScrollingEnabled(true); - documentScrollPane.removeMouseWheelListener(this); - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/FreeTextAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/FreeTextAnnotationHandler.java deleted file mode 100644 index c9bd8e4d6f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/FreeTextAnnotationHandler.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.PDate; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.AnnotationFactory; -import org.icepdf.core.pobjects.annotations.FreeTextAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.AnnotationCallback; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.AnnotationComponentFactory; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.util.Date; -import java.util.logging.Logger; - -/** - * FreeTextAnnotationHandler tool is responsible for painting representation of - * a FreeTextAnnotationHandler on the screen during a click and drag mouse event. - * The box created by this mouse event will be used be used as the bounding - * box of the annotation that will be created. - *

      - * Once the mouseReleased event is fired this handler will create new - * FreeTextAnnotationHandler and respective AnnotationComponent. The addition - * of the Annotation object to the page is handled by the annotation callback. - * - * @since 5.0 - */ -public class FreeTextAnnotationHandler extends SelectionBoxHandler - implements ToolHandler { - - private static final Logger logger = - Logger.getLogger(LineAnnotationHandler.class.toString()); - - /** - * New Text selection handler. Make sure to correctly and and remove - * this mouse and text listeners. - * - * @param pageViewComponent page component that this handler is bound to. - * @param documentViewModel view model. - */ - public FreeTextAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - } - - @Override - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - - } - - public void paintTool(Graphics g) { - paintSelectionBox(g, rectToDraw); - } - - public void mouseClicked(MouseEvent e) { - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } - - public void mousePressed(MouseEvent e) { - - } - - public void mouseReleased(MouseEvent e) { - updateSelectionSize(e.getX(),e.getY(), pageViewComponent); - - // check the bounds on rectToDraw to try and avoid creating - // an annotation that is very small. - if (rectToDraw.getWidth() < 5 || rectToDraw.getHeight() < 5) { - rectToDraw.setSize(new Dimension(15, 25)); - } - - // create a fixed sized box based on the default font size. - Rectangle tBbox = convertToPageSpace(rectToDraw).getBounds(); - - // create annotations types that that are rectangle based; - // which is actually just link annotations - FreeTextAnnotation annotation = (FreeTextAnnotation) - AnnotationFactory.buildAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - Annotation.SUBTYPE_FREE_TEXT, - tBbox); - annotation.setCreationDate(PDate.formatDateTime(new Date())); - annotation.setTitleText(System.getProperty("user.name")); - annotation.setFontSize(24); - annotation.setFontName("Helvetica"); - annotation.setContents(" "); - - // create the annotation object. - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, - documentViewController, - pageViewComponent, documentViewModel); - // set the bounds and refresh the userSpace rectangle - comp.setBounds(rectToDraw); - // resets user space rectangle to match bbox converted to page space - comp.refreshAnnotationRect(); - - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - - // request focus so that editing can take place. - comp.requestFocus(); - - // set the annotation tool to he select tool - documentViewController.getParentController().setDocumentToolMode( - DocumentViewModel.DISPLAY_TOOL_SELECTION); - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void mouseDragged(MouseEvent e) { - updateSelectionSize(e.getX(),e.getY(), pageViewComponent); - } - - public void mouseMoved(MouseEvent e) { - - } - - public void installTool() { - - } - - public void uninstallTool() { - - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/HighLightAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/HighLightAnnotationHandler.java deleted file mode 100644 index db140e929f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/HighLightAnnotationHandler.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.PDate; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.AnnotationFactory; -import org.icepdf.core.pobjects.annotations.TextMarkupAnnotation; -import org.icepdf.core.pobjects.graphics.text.GlyphText; -import org.icepdf.core.pobjects.graphics.text.LineText; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.pobjects.graphics.text.WordText; -import org.icepdf.core.util.Defs; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.AnnotationCallback; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.AnnotationComponentFactory; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.util.ArrayList; -import java.util.Date; - -/** - * HighLightAnnotationHandler tool extends TextSelectionPageHandler which - * takes care visually selected text as the mouse is dragged across text on the - * current page. - *

      - * Once the mouseReleased event is fired this handler will create new - * HighLightAnnotation and respective AnnotationComponent. The addition of the - * Annotation object to the page is handled by the annotation callback. Once - * create the handler will deselect the text and the newly created annotation - * will be displayed. - * - * @since 5.0 - */ -public class HighLightAnnotationHandler extends TextSelectionPageHandler { - - /** - * Property when enabled will set the /contents key value to the selected text of the markup annotation. - */ - private static boolean enableHighlightContents; - - static { - try { - enableHighlightContents = Defs.booleanProperty( - "org.icepdf.core.views.page.annotation.highlightContent.enabled", false); - } catch (NumberFormatException e) { - logger.warning("Error reading highlight selection content enabled property."); - } - } - - protected Name highLightType; - - public HighLightAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - // default type - highLightType = Annotation.SUBTYPE_HIGHLIGHT; - } - - /** - * Override the base functionality as we don't want to support double and - * triple click work selection for highlights. - * - * @param e mouse event - */ - public void mouseClicked(MouseEvent e) { - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } - - /** - * Invoked when a mouse button has been released on a component. - */ - public void mouseReleased(MouseEvent e) { - - // get the selection bounds - ArrayList highlightBounds = getSelectedTextBounds(); - - // clear the selection - super.mouseReleased(e); - - // create the text markup annotation. - createTextMarkupAnnotation(highlightBounds); - - // set the annotation tool to he select tool -// documentViewController.getParentController().setDocumentToolMode( -// DocumentViewModel.DISPLAY_TOOL_SELECTION); - } - - - public void createTextMarkupAnnotation(ArrayList highlightBounds) { - // mke sure we don't create a highlight annotation for every word in the - // document when first selecting the tool for highlighted next. . - if (documentViewModel.isSelectAll()) { - documentViewController.clearSelectedText(); - } - - // get the geometric path of the selected text - if (highlightBounds == null) { - highlightBounds = getSelectedTextBounds(); - } - // grab the selected text - String contents = enableHighlightContents && highlightBounds != null ? getSelectedText() : ""; - - // clear the selected text - documentViewController.clearSelectedText(); - - if (highlightBounds != null) { - - // bound of the selected text - GeneralPath highlightPath = new GeneralPath(); - for (Shape bounds : highlightBounds) { - highlightPath.append(bounds, false); - } - // get the bounds before convert to page space - Rectangle bounds = highlightPath.getBounds(); - - Rectangle tBbox = convertToPageSpace(highlightBounds, highlightPath); - - // create annotations types that that are rectangle based; - // which is actually just link annotations - TextMarkupAnnotation annotation = (TextMarkupAnnotation) - AnnotationFactory.buildAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - highLightType, - tBbox); - - // pass outline shapes and bounds to create the highlight shapes - if (TextMarkupAnnotation.SUBTYPE_HIGHLIGHT.equals(highLightType)) { - annotation.setOpacity(TextMarkupAnnotation.HIGHLIGHT_ALPHA); - } - annotation.setContents(contents != null && enableHighlightContents ? contents : highLightType.toString()); - annotation.setColor(annotation.getTextMarkupColor()); - annotation.setCreationDate(PDate.formatDateTime(new Date())); - annotation.setTitleText(System.getProperty("user.name")); - annotation.setMarkupBounds(highlightBounds); - annotation.setMarkupPath(highlightPath); - annotation.setBBox(tBbox); - // finalized the appearance properties. - annotation.resetAppearanceStream(getPageTransform()); - - // create new annotation given the general path - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, - documentViewController, - pageViewComponent, documentViewModel); - - // convert to user rect to page space along with the bounds. - comp.setBounds(bounds); - comp.refreshAnnotationRect(); - - // create component and add it to the page. - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - } - pageViewComponent.repaint(); - } - - private String getSelectedText() { - Page currentPage = pageViewComponent.getPage(); - String selectedText = null; - try { - selectedText = currentPage.getViewText().getSelected().toString(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("HighLightAnnotation initialization interrupted."); - } - return selectedText; - } - - private ArrayList getSelectedTextBounds() { - Page currentPage = pageViewComponent.getPage(); - ArrayList highlightBounds = null; - if (currentPage != null && currentPage.isInitiated()) { - try { - PageText pageText = currentPage.getViewText(); - if (pageText != null) { - // get page transformation - AffineTransform pageTransform = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - // paint the sprites - GeneralPath textPath; - ArrayList pageLines = pageText.getPageLines(); - if (pageLines != null) { - for (LineText lineText : pageLines) { - java.util.List words = lineText.getWords(); - if (words != null) { - for (WordText wordText : words) { - // paint whole word - if (wordText.isSelected() || wordText.isHighlighted()) { - textPath = new GeneralPath(wordText.getBounds()); - textPath.transform(pageTransform); - // paint highlight over any selected - if (wordText.isSelected()) { - if (highlightBounds == null) { - highlightBounds = new ArrayList(); - } - highlightBounds.add(textPath.getBounds2D()); - } - } - // check children - else { - for (GlyphText glyph : wordText.getGlyphs()) { - if (glyph.isSelected()) { - textPath = new GeneralPath(glyph.getBounds()); - textPath.transform(pageTransform); - if (highlightBounds == null) { - highlightBounds = new ArrayList(); - } - highlightBounds.add(textPath.getBounds2D()); - } - } - } - } - } - } - } - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("HighLightAnnotation selected text bounds calculation interrupted."); - } - } - return highlightBounds; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/InkAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/InkAnnotationHandler.java deleted file mode 100644 index eb4a67ce28..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/InkAnnotationHandler.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.AnnotationFactory; -import org.icepdf.core.pobjects.annotations.BorderStyle; -import org.icepdf.core.pobjects.annotations.InkAnnotation; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.AnnotationCallback; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.AnnotationComponentFactory; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.GeneralPath; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * InkAnnotationHandler tool is responsible for painting representation of - * a ink on the screen as the mouse is dragged around the page. The points - * that make up the mouse path are then used to create the InkAnnotation and - * respective annotation component. - *

      - * The addition of the Annotation object to the page is handled by the - * annotation callback. - * - * @since 5.0 - */ -public class InkAnnotationHandler extends CommonToolHandler implements ToolHandler { - - private static final Logger logger = - Logger.getLogger(LineAnnotationHandler.class.toString()); - - // need to make the stroke cap, thickness configurable. Or potentially - // static from the lineAnnotationHandle so it would look like the last - // settings where remembered. - protected static BasicStroke stroke = new BasicStroke(1.0f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 1.0f); - - protected static Color lineColor; - - static { - - // sets annotation ink line colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.ink.line.color", "#00ff00"); - int colorValue = ColorUtil.convertColor(color); - lineColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("00ff00", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading Ink Annotation line colour"); - } - } - } - - // start and end point - protected GeneralPath inkPath; - - protected BorderStyle borderStyle = new BorderStyle(); - - /** - * New Text selection handler. Make sure to correctly and and remove - * this mouse and text listeners. - * - * @param pageViewComponent page component that this handler is bound to. - * @param documentViewModel view model. - */ - public InkAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - } - - public void paintTool(Graphics g) { - if (inkPath != null) { - Graphics2D gg = (Graphics2D) g; - Color oldColor = gg.getColor(); - Stroke oldStroke = gg.getStroke(); - gg.setColor(lineColor); - gg.setStroke(stroke); - gg.draw(inkPath); - gg.setColor(oldColor); - gg.setStroke(oldStroke); - } - } - - public void mouseClicked(MouseEvent e) { - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } - - public void mousePressed(MouseEvent e) { - // annotation selection box. - if (inkPath == null) { - inkPath = new GeneralPath(); - } - inkPath.moveTo(e.getX(), e.getY()); - pageViewComponent.repaint(); - } - - public void mouseReleased(MouseEvent e) { - - inkPath.moveTo(e.getX(), e.getY()); - - // convert bbox and start and end line points. - Rectangle bBox = inkPath.getBounds(); - // check to make sure the bbox isn't zero height or width - bBox.setRect(bBox.getX() - 5, bBox.getY() - 5, - bBox.getWidth() + 10, bBox.getHeight() + 10); - Rectangle tBbox = convertToPageSpace(bBox).getBounds(); - // get the ink path in page space then we need to translate it relative to the bbox. - Shape tInkPath = convertToPageSpace(inkPath); - - // create annotations types that that are rectangle based; - // which is actually just link annotations - InkAnnotation annotation = (InkAnnotation) - AnnotationFactory.buildAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - Annotation.SUBTYPE_INK, - tBbox); - - annotation.setColor(lineColor); - annotation.setBorderStyle(borderStyle); - annotation.setInkPath(tInkPath); - - // pass outline shapes and bounds to create the highlight shapes - annotation.setBBox(tBbox); - annotation.resetAppearanceStream(getPageTransform()); - - // create the annotation object. - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, - documentViewController, - pageViewComponent, documentViewModel); - // set the bounds and refresh the userSpace rectangle - comp.setBounds(bBox); - - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - - // set the annotation tool to he select tool - documentViewController.getParentController().setDocumentToolMode( - DocumentViewModel.DISPLAY_TOOL_SELECTION); - - // clear the path - inkPath = null; - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void installTool() { - - } - - public void uninstallTool() { - - } - - public void mouseDragged(MouseEvent e) { - inkPath.lineTo(e.getX(), e.getY()); - pageViewComponent.repaint(); - } - - public void mouseMoved(MouseEvent e) { - - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/LineAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/LineAnnotationHandler.java deleted file mode 100644 index f82ca41d99..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/LineAnnotationHandler.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.PDate; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.AnnotationFactory; -import org.icepdf.core.pobjects.annotations.BorderStyle; -import org.icepdf.core.pobjects.annotations.LineAnnotation; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.AnnotationCallback; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.AnnotationComponentFactory; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Point2D; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * LineAnnotationHandler tool is responsible for painting representation of - * a line on the screen during a click and drag mouse event. The first point - * is recorded on mousePressed and the line is drawn from first point the current - * location of the mouse. - *

      - * Once the mouseReleased event is fired this handler will create new - * LineAnnotation and respective AnnotationComponent. The addition of the - * Annotation object to the page is handled by the annotation callback. - * - * @since 5.0 - */ -public class LineAnnotationHandler extends SelectionBoxHandler implements ToolHandler { - - - private static final Logger logger = - Logger.getLogger(LineAnnotationHandler.class.toString()); - - // need to make the stroke cap, thickness configurable. Or potentially - // static from the lineAnnotationHandle so it would look like the last - // settings where remembered. - protected static BasicStroke stroke = new BasicStroke(1.0f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 1.0f); - - protected static Color lineColor; - protected static Color internalColor; - - static { - - // sets annotation link stroke colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.line.stroke.color", "#ff0000"); - int colorValue = ColorUtil.convertColor(color); - lineColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("ff0000", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading line Annotation stroke colour"); - } - } - - // sets annotation link fill colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.line.fill.color", "#ff0000"); - int colorValue = ColorUtil.convertColor(color); - internalColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("ff0000", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading line Annotation fill colour"); - } - } - } - - protected static Name startLineEnding = LineAnnotation.LINE_END_NONE; - protected static Name endLineEnding = LineAnnotation.LINE_END_NONE; - - // start and end point - protected Point2D startOfLine; - protected Point2D endOfLine; - - protected BorderStyle borderStyle = new BorderStyle(); - - /** - * New Text selection handler. Make sure to correctly and and remove - * this mouse and text listeners. - * - * @param pageViewComponent page component that this handler is bound to. - * @param documentViewModel view model. - */ - public LineAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - startLineEnding = LineAnnotation.LINE_END_NONE; - endLineEnding = LineAnnotation.LINE_END_NONE; - } - - public void paintTool(Graphics g) { - if (startOfLine != null && endOfLine != null) { - Graphics2D gg = (Graphics2D) g; - Color oldColor = gg.getColor(); - Stroke oldStroke = gg.getStroke(); - g.setColor(lineColor); - gg.setStroke(stroke); - g.drawLine((int) startOfLine.getX(), (int) startOfLine.getY(), - (int) endOfLine.getX(), (int) endOfLine.getY()); - g.setColor(oldColor); - gg.setStroke(oldStroke); - } - } - - public void mousePressed(MouseEvent e) { - startOfLine = e.getPoint(); - // annotation selection box. - int x = e.getX(); - int y = e.getY(); - currentRect = new Rectangle(x, y, 0, 0); - updateDrawableRect(pageViewComponent.getWidth(), - pageViewComponent.getHeight()); - pageViewComponent.repaint(); - } - - public void mouseReleased(MouseEvent e) { - endOfLine = e.getPoint(); - updateSelectionSize(e.getX(),e.getY(), pageViewComponent); - - // add a little padding or the end point icon types - rectToDraw.setRect(rectToDraw.getX() - 8, rectToDraw.getY() - 8, - rectToDraw.getWidth() + 16, rectToDraw.getHeight() + 16); - - // convert bbox and start and end line points. - Rectangle tBbox = convertToPageSpace(rectToDraw).getBounds(); - // convert start of line and end of line to page space - Point2D[] points = convertToPageSpace(startOfLine, endOfLine); - - // create annotations types that are rectangle based; - LineAnnotation annotation = (LineAnnotation) - AnnotationFactory.buildAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - Annotation.SUBTYPE_LINE, - tBbox); - annotation.setStartArrow(startLineEnding); - annotation.setEndArrow(endLineEnding); - annotation.setStartOfLine(points[0]); - annotation.setEndOfLine(points[1]); - annotation.setBorderStyle(borderStyle); - annotation.setColor(lineColor); - annotation.setInteriorColor(internalColor); - - // setup the markup properties. - annotation.setContents(annotation.getSubType().toString()); - annotation.setCreationDate(PDate.formatDateTime(new Date())); - annotation.setTitleText(System.getProperty("user.name")); - - // pass outline shapes and bounds to create the highlight shapes - annotation.setBBox(tBbox); - annotation.resetAppearanceStream(getPageTransform()); - - // create the annotation object. - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, - documentViewController, - pageViewComponent, documentViewModel); - // set the bounds and refresh the userSpace rectangle - Rectangle bbox = new Rectangle(rectToDraw.x, rectToDraw.y, - rectToDraw.width, rectToDraw.height); - comp.setBounds(bbox); - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - - // set the annotation tool to he select tool - documentViewController.getParentController().setDocumentToolMode( - DocumentViewModel.DISPLAY_TOOL_SELECTION); - - // clear the rectangle - clearRectangle(pageViewComponent); - startOfLine = endOfLine = null; - } - - public void mouseDragged(MouseEvent e) { - updateSelectionSize(e.getX(),e.getY(), pageViewComponent); - endOfLine = e.getPoint(); - pageViewComponent.repaint(); - } - - /** - * Convert the shapes that make up the annotation to page space so that - * they will scale correctly at different zooms. - * - * @return transformed bBox. - */ - protected Rectangle convertToPageSpace() { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error converting to page space.", e); - } - // convert the two points as well as the bbox. - Rectangle tBbox = new Rectangle(rectToDraw.x, rectToDraw.y, - rectToDraw.width, rectToDraw.height); - - tBbox = at.createTransformedShape(tBbox).getBounds(); - - // convert the points - startOfLine = at.transform(startOfLine, null); - endOfLine = at.transform(endOfLine, null); - - return tBbox; - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseClicked(MouseEvent e) { - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } - - public void mouseExited(MouseEvent e) { - - } - - public void mouseMoved(MouseEvent e) { - - } - - public void installTool() { - - } - - public void uninstallTool() { - - } - - @Override - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/LineArrowAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/LineArrowAnnotationHandler.java deleted file mode 100644 index 3aaacf239b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/LineArrowAnnotationHandler.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.annotations.LineAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; - -/** - * LineArrowAnnotationHandler tool is responsible for painting representation of - * a line arrow on the screen during a click and drag mouse event. The first point - * is recorded on mousePressed and the line is drawn from first point the current - * location of the mouse. An open arrow is drawn at the starting point. - *

      - * Once the mouseReleased event is fired this handler will create new - * LineArrowAnnotation and respective AnnotationComponent. The addition of the - * Annotation object to the page is handled by the annotation callback. - * - * @since 5.0 - */ -public class LineArrowAnnotationHandler extends LineAnnotationHandler { - - - public LineArrowAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - - startLineEnding = LineAnnotation.LINE_END_OPEN_ARROW; - endLineEnding = LineAnnotation.LINE_END_NONE; - } - - public void paintTool(Graphics g) { - if (startOfLine != null && endOfLine != null) { - Graphics2D gg = (Graphics2D) g; - Color oldColor = gg.getColor(); - Stroke oldStroke = gg.getStroke(); - g.setColor(lineColor); - gg.setStroke(stroke); - - // draw the line - gg.drawLine((int) startOfLine.getX(), (int) startOfLine.getY(), - (int) endOfLine.getX(), (int) endOfLine.getY()); - // draw start cap - if (!startLineEnding.equals(LineAnnotation.LINE_END_NONE)) { - LineAnnotation.drawLineStart(gg, startLineEnding, startOfLine, - endOfLine, lineColor, internalColor); - } - // draw end cap - if (!endLineEnding.equals(LineAnnotation.LINE_END_NONE)) { - LineAnnotation.drawLineEnd(gg, endLineEnding, endOfLine, - endOfLine, lineColor, internalColor); - } - g.setColor(oldColor); - gg.setStroke(oldStroke); - } - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/LinkAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/LinkAnnotationHandler.java deleted file mode 100644 index 14896f520d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/LinkAnnotationHandler.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.AnnotationFactory; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.AnnotationCallback; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.AnnotationComponentFactory; - -import javax.swing.event.MouseInputListener; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.util.logging.Logger; - -/** - * Handles the creation of a new link annotation. A rectangle is - * drawn on mouse pressed and on mouse released the selection box is - * used as the bounds for a new link annotation. - * - * @since 5.0 - */ -public class LinkAnnotationHandler extends SelectionBoxHandler - implements ToolHandler, MouseInputListener { - - private static final Logger logger = - Logger.getLogger(LinkAnnotationHandler.class.toString()); - - public LinkAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - selectionBoxColour = Color.GRAY; - } - - public void mouseClicked(MouseEvent e) { - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } - - public void mousePressed(MouseEvent e) { - // annotation selection box. - int x = e.getX(); - int y = e.getY(); - currentRect = new Rectangle(x, y, 0, 0); - updateDrawableRect(pageViewComponent.getWidth(), - pageViewComponent.getHeight()); - pageViewComponent.repaint(); - } - - public void mouseReleased(MouseEvent e) { - updateSelectionSize(e.getX(),e.getY(), pageViewComponent); - - // check the bounds on rectToDraw to try and avoid creating - // an annotation that is very small. - if (rectToDraw.getWidth() < 5 || rectToDraw.getHeight() < 5) { - rectToDraw.setSize(new Dimension(15, 25)); - } - - Rectangle tBbox = convertToPageSpace(rectToDraw).getBounds(); - - // create annotations types that that are rectangle based; - // which is actually just link annotations - Annotation annotation = AnnotationFactory.buildAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - Annotation.SUBTYPE_LINK, - tBbox); - - // create the annotation object. - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, - documentViewController, - pageViewComponent, documentViewModel); - comp.setBounds(rectToDraw); - comp.refreshAnnotationRect(); - - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - - // set the annotation tool to he select tool - documentViewController.getParentController().setDocumentToolMode( - DocumentViewModel.DISPLAY_TOOL_SELECTION); - - // clear the rectangle - clearRectangle(pageViewComponent); - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void mouseDragged(MouseEvent e) { - updateSelectionSize(e.getX(),e.getY(), pageViewComponent); - } - - public void mouseMoved(MouseEvent e) { - - } - - public void installTool() { - - } - - public void uninstallTool() { - - } - - @Override - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - - } - - public void paintTool(Graphics g) { - paintSelectionBox(g, rectToDraw); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/MouseWheelZoom.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/MouseWheelZoom.java deleted file mode 100644 index e82c93acae..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/MouseWheelZoom.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.ri.common.views.DocumentViewController; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.InputEvent; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; - -/** - * The MouseWheelZoom allows the zoom any any page view to be controlled by - * holding down the ctr key and rotating the mouse wheel. - * - * @since 4.0 - */ -public class MouseWheelZoom implements MouseWheelListener { - - protected DocumentViewController documentViewController; - protected JScrollPane documentScrollPane; - - public MouseWheelZoom(DocumentViewController documentViewController, - JScrollPane documentScrollPane) { - this.documentScrollPane = documentScrollPane; - this.documentViewController = documentViewController; - } - - /** - * Handles ctl-wheel mouse for document zooming. - * - * @param e mouse wheel event. - */ - public void mouseWheelMoved(MouseWheelEvent e) { - int rotation = e.getWheelRotation(); - // turn off scroll on zoom and then back on again next time - // the wheel is used with out the ctrl mask. - if ((e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK - || - (e.getModifiers() & InputEvent.META_MASK) == InputEvent.META_MASK) { - documentScrollPane.setWheelScrollingEnabled(false); - Point offset = documentScrollPane.getViewport().getViewPosition(); - int viewWidth = documentScrollPane.getViewport().getWidth() / 2; - int viewHeight = documentScrollPane.getViewport().getHeight() / 2; - offset.setLocation(offset.x + viewWidth, offset.y + viewHeight); - if (rotation > 0) { - documentViewController.setZoomOut(offset); - } else { - documentViewController.setZoomIn(offset); - } - } else { - documentScrollPane.setWheelScrollingEnabled(true); - } - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/PanningHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/PanningHandler.java deleted file mode 100644 index 331260aa26..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/PanningHandler.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.ri.common.views.AbstractDocumentView; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.event.MouseEvent; - -/** - * Container logic used for view panning via mouse dragging for page views. - * Panning can be handle in the view and doesn't need to be handled by the - * page components. - * - * @since 4.0 - */ -public class PanningHandler implements ToolHandler { - - - // page mouse event manipulation - private Point lastMousePosition = new Point(); - - private DocumentViewController documentViewController; - private DocumentViewModel documentViewModel; - private AbstractDocumentView parentComponent; - - public PanningHandler(DocumentViewController documentViewController, - DocumentViewModel documentViewModel, - AbstractDocumentView parentComponent) { - this.documentViewController = documentViewController; - this.documentViewModel = documentViewModel; - this.parentComponent = parentComponent; - } - - /** - * Mouse dragged, initiates page panning if the tool is selected. - * - * @param e awt mouse event - */ - public void mouseDragged(MouseEvent e) { - if (documentViewController != null) { - - // Get data about the current view port position - Adjustable verticalScrollbar = - documentViewController.getVerticalScrollBar(); - Adjustable horizontalScrollbar = - documentViewController.getHorizontalScrollBar(); - - if (verticalScrollbar != null && horizontalScrollbar != null) { - // calculate how much the view port should be moved - Point p = new Point( - (int) e.getPoint().getX() - horizontalScrollbar.getValue(), - (int) e.getPoint().getY() - verticalScrollbar.getValue()); - int x = (int) (horizontalScrollbar.getValue() - (p.getX() - lastMousePosition.getX())); - int y = (int) (verticalScrollbar.getValue() - (p.getY() - lastMousePosition.getY())); - - // apply the pan - horizontalScrollbar.setValue(x); - verticalScrollbar.setValue(y); - - // update last position holder - lastMousePosition.setLocation(p); - } - } - } - - public void mouseMoved(MouseEvent e) { - if (documentViewController != null) { - - Adjustable verticalScrollbar = - documentViewController.getVerticalScrollBar(); - Adjustable horizontalScrollbar = - documentViewController.getHorizontalScrollBar(); - - lastMousePosition.setLocation( - e.getPoint().getX() - horizontalScrollbar.getValue(), - e.getPoint().getY() - verticalScrollbar.getValue()); - } - } - - /** - * Invoked when the mouse button has been clicked (pressed - * and released) on a component. - */ - public void mouseClicked(MouseEvent e) { - documentViewController.clearSelectedAnnotations(); - if (parentComponent != null) { - parentComponent.requestFocus(); - } - } - - /** - * Invoked when a mouse button has been pressed on a component. - */ - public void mousePressed(MouseEvent e) { - - if (documentViewController != null && - documentViewController.getDocumentViewModel() - .isViewToolModeSelected(DocumentViewModel.DISPLAY_TOOL_PAN)) { - documentViewController.setViewCursor(DocumentViewController.CURSOR_HAND_CLOSE); - } - } - - /** - * Invoked when a mouse button has been released on a component. - */ - public void mouseReleased(MouseEvent e) { - if (documentViewController != null && - documentViewController.getDocumentViewModel().getViewToolMode() - == DocumentViewModel.DISPLAY_TOOL_PAN) { - documentViewController.setViewCursor(DocumentViewController.CURSOR_HAND_OPEN); - } - } - - /** - * Invoked when the mouse enters a component. - */ - public void mouseEntered(MouseEvent e) { - - } - - /** - * Invoked when the mouse exits a component. - */ - public void mouseExited(MouseEvent e) { - - } - - public void paintTool(Graphics g) { - // nothing to paint for paning. - } - - public void installTool() { - - } - - public void uninstallTool() { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/SelectionBoxHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/SelectionBoxHandler.java deleted file mode 100644 index 0d3556ffdf..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/SelectionBoxHandler.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.PageViewComponentImpl; - -import java.awt.*; -import java.awt.event.MouseEvent; - -/** - * Handles the drawing of a selection box commonly used for selection - * type tools. - * - * @since 4.0 - */ -public abstract class SelectionBoxHandler extends CommonToolHandler { - - // dashed selection rectangle stroke - protected static float dash1[] = {1.0f}; - protected static BasicStroke stroke = new BasicStroke(1.0f, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 1.0f, dash1, 0.0f); - - // selection rectangle used for glyph intersection aka text selection - protected Rectangle currentRect = null; - protected Rectangle rectToDraw = null; - protected Rectangle previousRectDrawn = new Rectangle(); - - protected static Color selectionBoxColour = Color.lightGray; - - protected SelectionBoxHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - } - - public abstract void setSelectionRectangle(Point cursorLocation, Rectangle selection); - - public static void paintSelectionBox(Graphics g, Rectangle rectToDraw) { - Graphics2D gg = (Graphics2D) g; - Color oldColor = gg.getColor(); - Stroke oldStroke = gg.getStroke(); - if (rectToDraw != null) { - //Draw a rectangle on top of the image. - oldColor = g.getColor(); - gg.setColor(selectionBoxColour); - gg.setStroke(stroke); - gg.drawRect(rectToDraw.x, rectToDraw.y, - rectToDraw.width - 1, rectToDraw.height - 1); - gg.setColor(oldColor); - } - - gg.setColor(oldColor); - gg.setStroke(oldStroke); - } - - public void resetRectangle(int x, int y) { - currentRect = new Rectangle(x, y, 0, 0); - } - - public Rectangle getCurrentRect() { - return currentRect; - } - - public void setCurrentRect(Rectangle currentRect) { - this.currentRect = currentRect; - } - - public Rectangle getRectToDraw() { - return rectToDraw; - } - - public void setRectToDraw(Rectangle rectToDraw) { - this.rectToDraw = rectToDraw; - } - - public void clearRectangle(Component component) { - // clear the rectangle - currentRect = new Rectangle(0, 0, 0, 0); - updateDrawableRect(component.getWidth(), - component.getHeight()); - } - - /** - * Update the size of the selection rectangle. - * - * @param x x-coordinate of the selection size update. - * @param y y-coordinate of the selection size update. - */ - public void updateSelectionSize(int x, int y, Component component) { - // dragging across pages will result in null pointer if don't init. - if (currentRect == null) { - currentRect = new Rectangle(x, y, 0, 0); - } - currentRect.setSize(x - currentRect.x, - y - currentRect.y); - - if (component != null) { - updateDrawableRect(component.getWidth(), component.getHeight()); - Rectangle totalRepaint = rectToDraw.union(previousRectDrawn); - component.repaint(totalRepaint.x, totalRepaint.y, - totalRepaint.width + 10, totalRepaint.height + 10); - } - } - - public void setSelectionSize(Rectangle rect, Component component) { - - currentRect = rect; - - updateDrawableRect(component.getWidth(), component.getHeight()); - Rectangle totalRepaint = rectToDraw.union(previousRectDrawn); - component.repaint(totalRepaint.x, totalRepaint.y, - totalRepaint.width, totalRepaint.height); - } - - /** - * Update the drawable rectangle so that it does not extend bast the edge - * of the page. - * - * @param compWidth width of component being selected - * @param compHeight height of component being selected. - */ - public void updateDrawableRect(int compWidth, int compHeight) { - int x = currentRect.x; - int y = currentRect.y; - int width = currentRect.width; - int height = currentRect.height; - - //Make the width and height positive, if necessary. - if (width < 0) { - width = 0 - width; - x = x - width + 1; - if (x < 0) { - width += x; - x = 0; - } - } - if (height < 0) { - height = 0 - height; - y = y - height + 1; - if (y < 0) { - height += y; - y = 0; - } - } - - //The rectangle shouldn't extend past the drawing area. - if ((x + width) > compWidth) { - width = compWidth - x; - } - if ((y + height) > compHeight) { - height = compHeight - y; - } - - //Update rectToDraw after saving old value. - if (rectToDraw != null) { - previousRectDrawn.setBounds( - rectToDraw.x, rectToDraw.y, - rectToDraw.width, rectToDraw.height); - rectToDraw.setBounds(x, y, width, height); - } else { - rectToDraw = new Rectangle(x, y, width, height); - } - } - - /** - * Utility method for determining if the mouse event occurred over a - * page in the page view. - * - * @param e mouse event in this coordinates space - * @return component that mouse event is over or null if not over a page. - */ - protected PageViewComponentImpl isOverPageComponent(Container container, MouseEvent e) { - // mouse -> page broadcast . - Component comp = container.findComponentAt(e.getPoint()); - if (comp instanceof PageViewComponentImpl) { - return (PageViewComponentImpl) comp; - } else { - return null; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/SquareAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/SquareAnnotationHandler.java deleted file mode 100644 index 790befb65c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/SquareAnnotationHandler.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.AnnotationFactory; -import org.icepdf.core.pobjects.annotations.BorderStyle; -import org.icepdf.core.pobjects.annotations.SquareAnnotation; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.AnnotationCallback; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.AnnotationComponentFactory; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * SquareAnnotationHandler tool is responsible for painting representation of - * a square on the screen during a click and drag mouse event. The box - * created by this mouse event will be used to draw square within its bounds. - *

      - * Once the mouseReleased event is fired this handler will create new - * SquareAnnotation and respective AnnotationComponent. The addition of the - * Annotation object to the page is handled by the annotation callback. - * - * @since 5.0 - */ -public class SquareAnnotationHandler extends SelectionBoxHandler implements ToolHandler { - - private static final Logger logger = - Logger.getLogger(SquareAnnotationHandler.class.toString()); - - protected final static float DEFAULT_STROKE_WIDTH = 3.0f; - - protected static BasicStroke stroke; - protected static float strokeWidth; - protected static Color lineColor; - protected static Color internalColor; - protected static boolean useInternalColor; - - static { - - // sets annotation squareCircle stroke colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.squareCircle.stroke.color", "#ff0000"); - int colorValue = ColorUtil.convertColor(color); - lineColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("ff0000", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading squareCircle Annotation stroke colour"); - } - } - - // sets annotation link squareCircle colour - useInternalColor = Defs.booleanProperty( - "org.icepdf.core.views.page.annotation.squareCircle.fill.enabled", false); - - // sets annotation link squareCircle colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.squareCircle.fill.color", "#ffffff"); - int colorValue = ColorUtil.convertColor(color); - internalColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("ffffff", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading squareCircle Annotation fill colour"); - } - } - - strokeWidth = (float) Defs.doubleProperty("org.icepdf.core.views.page.annotation.squareCircle.stroke.width", - DEFAULT_STROKE_WIDTH); - - // need to make the stroke cap, thickness configurable. Or potentially - // static from the AnnotationHandle so it would look like the last - // settings where remembered. - stroke = new BasicStroke(strokeWidth, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 1.0f); - } - - // start and end point - protected Rectangle rectangle; - - protected BorderStyle borderStyle = new BorderStyle(); - - /** - * New Text selection handler. Make sure to correctly and and remove - * this mouse and text listeners. - * - * @param pageViewComponent page component that this handler is bound to. - * @param documentViewModel view model. - */ - public SquareAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - borderStyle.setStrokeWidth(DEFAULT_STROKE_WIDTH); - } - - public void paintTool(Graphics g) { - if (rectangle != null) { - Graphics2D gg = (Graphics2D) g; - Color oldColor = gg.getColor(); - Stroke oldStroke = gg.getStroke(); - gg.setStroke(stroke); - if (useInternalColor) { - gg.setColor(internalColor); - gg.fill(rectangle); - } - gg.setColor(lineColor); - gg.draw(rectangle); - g.setColor(oldColor); - gg.setStroke(oldStroke); - } - } - - public void mousePressed(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - if (rectangle == null) { - rectangle = new Rectangle(); - } - currentRect = new Rectangle(x, y, 0, 0); - updateDrawableRect(pageViewComponent.getWidth(), - pageViewComponent.getHeight()); - rectangle.setRect(currentRect); - pageViewComponent.repaint(); - } - - public void mouseReleased(MouseEvent e) { - updateSelectionSize(e.getX(), e.getY(), pageViewComponent); - - // convert the rectangle to page space - rectangle = convertToPageSpace(rectangle); - - // check to make sure the bbox isn't zero height or width - rectToDraw.setRect(rectToDraw.getX() - DEFAULT_STROKE_WIDTH, - rectToDraw.getY() - DEFAULT_STROKE_WIDTH, - rectToDraw.getWidth() + DEFAULT_STROKE_WIDTH * 2, - rectToDraw.getHeight() + DEFAULT_STROKE_WIDTH * 2); - - // convert tBbox - Rectangle tBbox = convertToPageSpace(rectToDraw); - - // create annotations types that that are rectangle based; - // which is actually just link annotations - SquareAnnotation annotation = (SquareAnnotation) - AnnotationFactory.buildAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - Annotation.SUBTYPE_SQUARE, - tBbox); - annotation.setColor(lineColor); - if (annotation.isFillColor() || useInternalColor) { - annotation.setFillColor(internalColor); - if (!annotation.isFillColor()) { - annotation.setFillColor(true); - } - } - borderStyle.setStrokeWidth(strokeWidth); - annotation.setRectangle(rectangle); - annotation.setBorderStyle(borderStyle); - - // pass outline shapes and bounds to create the highlight shapes - annotation.setBBox(new Rectangle(0, 0, tBbox.width, tBbox.height)); - annotation.resetAppearanceStream(getPageTransform()); - - // create the annotation object. - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, - documentViewController, - pageViewComponent, documentViewModel); - // set the bounds and refresh the userSpace rectangle - Rectangle bbox = new Rectangle(rectToDraw.x, rectToDraw.y, - rectToDraw.width, rectToDraw.height); - comp.setBounds(bbox); - // resets user space rectangle to match bbox converted to page space - comp.refreshAnnotationRect(); - - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - - // set the annotation tool to he select tool - documentViewController.getParentController().setDocumentToolMode( - DocumentViewModel.DISPLAY_TOOL_SELECTION); - - rectangle = null; - // clear the rectangle - clearRectangle(pageViewComponent); - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void mouseClicked(MouseEvent e) { - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } - - public void mouseMoved(MouseEvent e) { - - } - - public void installTool() { - - } - - public void uninstallTool() { - - } - - public void mouseDragged(MouseEvent e) { - updateSelectionSize(e.getX(), e.getY(), pageViewComponent); - rectangle.setRect(rectToDraw); - pageViewComponent.repaint(); - } - - /** - * Convert the shapes that make up the annotation to page space so that - * they will scale correctly at different zooms. - * - * @return transformed bBox. - */ - protected Rectangle convertToPageSpace(Rectangle rect) { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error converting to page space.", e); - } - // convert the two points as well as the bbox. - Rectangle tBbox = new Rectangle(rect.x, rect.y, - rect.width, rect.height); - - tBbox = at.createTransformedShape(tBbox).getBounds(); - - return tBbox; - - } - - @Override - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/StrikeOutAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/StrikeOutAnnotationHandler.java deleted file mode 100644 index a1913cf13e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/StrikeOutAnnotationHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.annotations.TextMarkupAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -/** - * StrikeOutAnnotationHandler tool extends TextSelectionPageHandler which - * takes care visually selected text as the mouse is dragged across text on the - * current page. - *

      - * Once the mouseReleased event is fired this handler will create new - * StrikeOutAnnotation and respective AnnotationComponent. The addition of the - * Annotation object to the page is handled by the annotation callback. Once - * create the handler will deselect the text and the newly created annotation - * will be displayed. - * - * @since 5.0 - */ -public class StrikeOutAnnotationHandler extends HighLightAnnotationHandler { - - public StrikeOutAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - highLightType = TextMarkupAnnotation.SUBTYPE_STRIKE_OUT; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextAnnotationHandler.java deleted file mode 100644 index 9aab00cab4..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextAnnotationHandler.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.PDate; -import org.icepdf.core.pobjects.PObject; -import org.icepdf.core.pobjects.StateManager; -import org.icepdf.core.pobjects.annotations.*; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.Library; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.AnnotationCallback; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.AnnotationComponentFactory; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * TextAnnotationHandler tool is responsible creating a new comment type - * TextAnnotation when a mouse click event is thrown on the page. The new - * TextAnnotation is placed at the point of the page where the click took place. - * The default icon state is set to comment and the respective PopupAnnotation - * is also created and shown. - *

      - * The addition of the - * Annotation object to the page is handled by the annotation callback. - * - * @since 5.0 - */ -public class TextAnnotationHandler extends CommonToolHandler implements ToolHandler { - - private static final Logger logger = - Logger.getLogger(TextAnnotationHandler.class.toString()); - protected static Color defaultFillColor; - static { - - // sets annotation text fill colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.text.fill.color", "#ffff00"); - int colorValue = ColorUtil.convertColor(color); - defaultFillColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("ffff00", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading text annotation fill colour"); - } - } - } - - protected static final Dimension ICON_SIZE = new Dimension(23, 23); - - public TextAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - } - - public void paintTool(Graphics g) { - - } - - public void mouseClicked(MouseEvent e) { - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } - - public void mousePressed(MouseEvent e) { - - } - - public static TextAnnotation createTextAnnotation(Library library, Rectangle bbox, - AffineTransform pageSpace) { - TextAnnotation textAnnotation = (TextAnnotation) - AnnotationFactory.buildAnnotation( - library, - Annotation.SUBTYPE_TEXT, - bbox); - textAnnotation.setCreationDate(PDate.formatDateTime(new Date())); - textAnnotation.setTitleText(System.getProperty("user.name")); - textAnnotation.setContents(""); - - // setup some default state - textAnnotation.setIconName(TextAnnotation.COMMENT_ICON); - textAnnotation.setState(TextAnnotation.STATE_UNMARKED); - textAnnotation.setColor(defaultFillColor); - - // set the content stream - textAnnotation.setBBox(new Rectangle(0, 0, bbox.width, bbox.height)); - textAnnotation.resetAppearanceStream(pageSpace); - - return textAnnotation; - } - - public static PopupAnnotation createPopupAnnotation(Library library, Rectangle bbox, - MarkupAnnotation parent, - AffineTransform pageSpace) { - // text annotation are special as the annotation has fixed size. - PopupAnnotation popupAnnotation = (PopupAnnotation) - AnnotationFactory.buildAnnotation( - library, - Annotation.SUBTYPE_POPUP, - bbox); - // save the annotation - StateManager stateManager = library.getStateManager(); - stateManager.addChange(new PObject(popupAnnotation, - popupAnnotation.getPObjectReference())); - library.addObject(popupAnnotation, popupAnnotation.getPObjectReference()); - - // setup up some default values - popupAnnotation.setOpen(true); - popupAnnotation.setParent(parent); - parent.setPopupAnnotation(popupAnnotation); - popupAnnotation.resetAppearanceStream(0, 0, pageSpace); - return popupAnnotation; - } - - public void mouseReleased(MouseEvent e) { - - AffineTransform pageTransform = getPageTransform(); - AffineTransform pageInverseTransform = new AffineTransform(); - try { - pageInverseTransform = pageTransform.createInverse(); - } catch (NoninvertibleTransformException ex) { - logger.log(Level.FINE, "Error converting to page space.", ex); - } - Dimension scaledSize = new Dimension( - (int) Math.abs(ICON_SIZE.width * pageInverseTransform.getScaleX()), - (int) Math.abs(ICON_SIZE.height * pageInverseTransform.getScaleY())); - - // convert bbox and start and end line points. - Rectangle bBox = new Rectangle(e.getX(), e.getY(), scaledSize.width, scaledSize.height); - Rectangle tBbox = convertToPageSpace(bBox).getBounds(); - - // text annotation are special as the annotation has fixed size. - TextAnnotation markupAnnotation = - createTextAnnotation(documentViewModel.getDocument().getPageTree().getLibrary(), - tBbox, pageTransform); - - // create the annotation object. - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - markupAnnotation, - documentViewController, - pageViewComponent, documentViewModel); - // set the bounds and refresh the userSpace rectangle - comp.setBounds(bBox); - // resets user space rectangle to match bbox converted to page space - comp.refreshAnnotationRect(); - - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - - /** - * now create the respective popup annotation - */ - - // position the new popup on the icon center. - Rectangle bBox2 = new Rectangle(e.getX() + scaledSize.width / 2, - e.getY() + scaledSize.height / 2, - (int) Math.abs(215 * pageInverseTransform.getScaleX()), - (int) Math.abs(150 * pageInverseTransform.getScaleY())); - - // make sure the popup stays within the page bounds. - Rectangle pageBounds = pageViewComponent.getBounds(); - if (!pageBounds.contains(bBox2.getX(), bBox2.getY(), - bBox2.getWidth(), bBox2.getHeight())) { - // center on the icon as before but take into account height width - // and it will be drawn more or less on the page. - bBox2.setLocation(bBox2.x - bBox2.width, bBox2.y - bBox2.height); - } - - // convert bbox and start and end line points. - Rectangle tBbox2 = convertToPageSpace(bBox2).getBounds(); - - // text annotation are special as the annotation has fixed size. - PopupAnnotation popupAnnotation = createPopupAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - tBbox2, markupAnnotation, pageTransform); - - // create the annotation object. - AbstractAnnotationComponent comp2 = AnnotationComponentFactory.buildAnnotationComponent( - popupAnnotation, - documentViewController, - pageViewComponent, documentViewModel); - // set the bounds and refresh the userSpace rectangle - comp2.setBounds(bBox2); - // resets user space rectangle to match bbox converted to page space - comp2.refreshAnnotationRect(); - - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp2); - } - - // set the annotation tool to he select tool - documentViewController.getParentController().setDocumentToolMode( - DocumentViewModel.DISPLAY_TOOL_SELECTION); - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void mouseDragged(MouseEvent e) { - - } - - public void mouseMoved(MouseEvent e) { - - } - - public void installTool() { - - } - - public void uninstallTool() { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextSelection.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextSelection.java deleted file mode 100644 index 5ff864bc8e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextSelection.java +++ /dev/null @@ -1,1048 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.text.GlyphText; -import org.icepdf.core.pobjects.graphics.text.LineText; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.pobjects.graphics.text.WordText; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.PageViewComponentImpl; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.icepdf.ri.common.tools.TextSelection.enableMarginExclusion; - -/** - * TextSelection is a utility class that captures most of the work needed to do basic text, word and line selection. - */ -public class TextSelection extends SelectionBoxHandler { - - protected static final Logger logger = - Logger.getLogger(TextSelection.class.toString()); - - public int selectedCount; - - protected Point lastMousePressedLocation; - protected Point lastMouseLocation; - - private GlyphLocation glyphStartLocation; - private GlyphLocation glyphEndLocation; - - private GlyphLocation lastGlyphStartLocation; - private GlyphLocation lastGlyphEndLocation; - - // todo configurable system property to switch to rightToLeft. - private boolean leftToRight = true; - - // todo make configurable - protected int topMargin = 75; - protected int bottomMargin = 75; - protected static boolean enableMarginExclusion; - protected static boolean enableMarginExclusionBorder; - protected Rectangle2D topMarginExclusion; - protected Rectangle2D bottomMarginExclusion; - - // Pointer to make sure the GC doesn't collect a page while selection state is present - protected Page pageLock; - - - static { - try { - enableMarginExclusion = Defs.booleanProperty( - "org.icepdf.core.views.page.marginExclusion.enabled", false); - } catch (NumberFormatException e) { - logger.warning("Error reading margin exclusion enabled property."); - } - try { - enableMarginExclusionBorder = Defs.booleanProperty( - "org.icepdf.core.views.page.marginExclusionBorder.enabled", false); - } catch (NumberFormatException e) { - logger.warning("Error reading margin exclusion boarder enabled property."); - } - } - - // first page that was selected - private boolean isFirst; - - public TextSelection(DocumentViewController documentViewController, AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - } - - /** - * Handles double and triple left mouse clicks to select a word or line of text respectively. - * - * @param clickCount number of mouse clicks to interpret for line or word selection. - * @param clickPoint point that mouse was clicked. - */ - public void wordLineSelection(int clickCount, Point clickPoint, AbstractPageViewComponent pageViewComponent) { - // double click we select the whole line. - try { - if (clickCount == 3) { - Page currentPage = pageViewComponent.getPage(); - // handle text selection mouse coordinates - Point mouseLocation = (Point) clickPoint.clone(); - lineSelectHandler(currentPage, mouseLocation); - } - // single click we select word that was clicked. - else if (clickCount == 2) { - Page currentPage = pageViewComponent.getPage(); - // handle text selection mouse coordinates - Point mouseLocation = (Point) clickPoint.clone(); - wordSelectHandler(currentPage, mouseLocation); - } - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } catch (InterruptedException e) { - logger.fine("Text selection page access interrupted"); - } - } - - /** - * Selection started so we want to record the position and update the selection rectangle. - * - * @param startPoint starting selection position. - */ - public void selectionStart(Point startPoint, AbstractPageViewComponent pageViewComponent, boolean isFirst) { - try { - Page currentPage = pageViewComponent.getPage(); - this.isFirst = isFirst; - if (currentPage != null) { - // get page text - PageText pageText = currentPage.getViewText(); - // get page transform, same for all calculations - AffineTransform pageTransform = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - - // create exclusion boxes - calculateTextSelectionExclusion(pageTransform); - - ArrayList pageLines = pageText.getPageLines(); - Point2D.Float dragStartLocation = convertMouseToPageSpace(startPoint, pageTransform); - glyphStartLocation = GlyphLocation.findGlyphLocation(pageLines, dragStartLocation, true, false, null, - topMarginExclusion, bottomMarginExclusion); - glyphEndLocation = null; - } - - // text selection box. - currentRect = new Rectangle(startPoint.x, startPoint.y, 0, 0); - updateDrawableRect(pageViewComponent.getWidth(), pageViewComponent.getHeight()); - pageViewComponent.repaint(); - } catch (InterruptedException e) { - logger.fine("Text selection page access interrupted"); - } - } - - /** - * Selection ended so we want to stop record the position and update the selection. - */ - public void selectionEnd(Point endPoint, AbstractPageViewComponent pageViewComponent) { - - try { - // write out selected text. - if (pageViewComponent != null && logger.isLoggable(Level.FINE)) { - Page currentPage = pageViewComponent.getPage(); - // handle text selection mouse coordinates - if (currentPage.getViewText() != null) { - logger.fine(currentPage.getViewText().getSelected().toString()); - } - } - - if (selectedCount > 0) { - - // add the page to the page as it is marked for selection - documentViewModel.addSelectedPageText(pageViewComponent); - documentViewController.firePropertyChange( - PropertyConstants.TEXT_SELECTED, - null, null); - } - - // clear the rectangle - clearRectangle(pageViewComponent); - - if (pageViewComponent != null) { - pageViewComponent.repaint(); - } - } catch (InterruptedException e) { - logger.fine("Text selection page access interrupted"); - } - } - - public void clearSelection() { - - // release the page lock so the Reference API can take care of collecting the page post selection. - pageLock = null; - - lastGlyphStartLocation = null; - lastGlyphEndLocation = null; - - glyphStartLocation = null; - glyphEndLocation = null; - - selectedCount = 0; - } - - public void clearSelectionState() { - java.util.List pages = documentViewModel.getPageComponents(); - for (AbstractPageViewComponent page : pages) { - ((PageViewComponentImpl)page).getTextSelectionPageHandler().clearSelection(); - } - } - - public void selection(Point dragPoint, AbstractPageViewComponent pageViewComponent, - boolean isDown, boolean isMovingRight) { - try { - if (pageViewComponent != null) { - - // acquire a page lock. - pageLock = pageViewComponent.getPage(); - - boolean isLocalDown; - if (lastMouseLocation != null) { - // double check we're actually moving down - isLocalDown = lastMouseLocation.y <= dragPoint.y; - } else { - isLocalDown = isDown; - } - multiLineSelectHandler(pageViewComponent, dragPoint, isDown, isLocalDown, isMovingRight); - - lastMouseLocation = dragPoint; - } - } catch (InterruptedException e) { - logger.fine("Text selection page access interrupted"); - } - } - - public void selectionIcon(Point mouseLocation, AbstractPageViewComponent pageViewComponent) { - try { - Page currentPage = pageViewComponent.getPage(); - if (currentPage != null) { - // get page text - PageText pageText = currentPage.getViewText(); - if (pageText != null) { - - // get page transform, same for all calculations - AffineTransform pageTransform = currentPage.getPageTransform( - Page.BOUNDARY_CROPBOX, - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - - // create exclusion boxes - calculateTextSelectionExclusion(pageTransform); - - ArrayList pageLines = pageText.getPageLines(); - if (pageLines != null) { - boolean found = false; - Point2D.Float pageMouseLocation = - convertMouseToPageSpace(mouseLocation, pageTransform); - - for (LineText pageLine : pageLines) { - // check for containment, if so break into words. - if (pageLine.getBounds().contains(pageMouseLocation) - && ((topMarginExclusion == null || bottomMarginExclusion == null) - || (!topMarginExclusion.contains(pageMouseLocation) - && !bottomMarginExclusion.contains(pageMouseLocation)))) { - found = true; - documentViewController.setViewCursor( - DocumentViewController.CURSOR_TEXT_SELECTION); - break; - } - } - if (!found) { - documentViewController.setViewCursor( - DocumentViewController.CURSOR_SELECT); - } - } - } - } - } catch (InterruptedException e) { - logger.fine("Text selection page access interrupted"); - } - } - - protected void calculateTextSelectionExclusion(AffineTransform pageTransform) { - if (enableMarginExclusion) { - Rectangle2D mediaBox = pageViewComponent.getPage().getCropBox(); - topMarginExclusion = new Rectangle2D.Float( - (int) mediaBox.getX(), - (int) mediaBox.getY() - topMargin, - (int) mediaBox.getWidth(), topMargin); - bottomMarginExclusion = new Rectangle2D.Float( - (int) mediaBox.getX(), - (int) (mediaBox.getY() - mediaBox.getHeight()), - (int) mediaBox.getWidth(), bottomMargin); - } - } - - /** - * Paints any text that is selected in the page wrapped by a pageViewComponent. - * - * @param g graphics context to paint to. - * @param pageViewComponent page view component to paint selected to on. - * @param documentViewModel document model contains view properties such as zoom and rotation. - */ - public static void paintSelectedText(Graphics g, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) throws InterruptedException{ - // ready outline paint - Graphics2D gg = (Graphics2D) g; - AffineTransform prePaintTransform = gg.getTransform(); - Color oldColor = gg.getColor(); - Stroke oldStroke = gg.getStroke(); -// gg.setComposite(BlendComposite.getInstance(BlendComposite.BlendingMode.MULTIPLY, 1.0f)); - gg.setComposite(AlphaComposite.getInstance( - AlphaComposite.SRC_OVER, - Page.SELECTION_ALPHA)); - gg.setColor(Page.selectionColor); - gg.setStroke(new BasicStroke(1.0f)); - - Page currentPage = pageViewComponent.getPage(); - if (currentPage != null) { - PageText pageText = currentPage.getViewText(); - if (pageText != null) { - // get page transformation - AffineTransform pageTransform = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - // paint the sprites - GeneralPath textPath; - ArrayList visiblePageLines = pageText.getPageLines(); - if (visiblePageLines != null) { - for (LineText lineText : visiblePageLines) { - for (WordText wordText : lineText.getWords()) { - // paint whole word - if (wordText.isSelected() || wordText.isHighlighted()) { - textPath = new GeneralPath(wordText.getBounds()); - textPath.transform(pageTransform); - // paint highlight over any selected - if (wordText.isSelected()) { - gg.setColor(Page.selectionColor); - gg.fill(textPath); - } - if (wordText.isHighlighted()) { - gg.setColor(Page.highlightColor); - gg.fill(textPath); - } - } - // check children - else { - for (GlyphText glyph : wordText.getGlyphs()) { - if (glyph.isSelected()) { - textPath = new GeneralPath(glyph.getBounds()); - textPath.transform(pageTransform); - gg.setColor(Page.selectionColor); - gg.fill(textPath); - } - } - } - } - } - } - } - } -// gg.setComposite(BlendComposite.getInstance(BlendComposite.BlendingMode.NORMAL, 1.0f)); - // restore graphics state to where we left it. - gg.setTransform(prePaintTransform); - gg.setStroke(oldStroke); - gg.setColor(oldColor); - - // paint words for bounds test. -// paintTextBounds(g); - - } - - /** - * Utility for painting text bounds. - * - * @param g graphics context to paint to. - */ - protected void paintTextBounds(Graphics g) throws InterruptedException{ - Page currentPage = pageViewComponent.getPage(); - // get page transformation - AffineTransform pageTransform = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - Graphics2D gg = (Graphics2D) g; - Color oldColor = g.getColor(); - g.setColor(Color.red); - - PageText pageText = currentPage.getViewText(); - if (pageText != null) { - ArrayList pageLines = pageText.getPageLines(); - if (pageLines != null) { - for (LineText lineText : pageLines) { - - for (WordText wordText : lineText.getWords()) { - for (GlyphText glyph : wordText.getGlyphs()) { - g.setColor(Color.black); - GeneralPath glyphSpritePath = - new GeneralPath(glyph.getBounds()); - glyphSpritePath.transform(pageTransform); - gg.draw(glyphSpritePath); - } - - // if (!wordText.isWhiteSpace()) { - // g.setColor(Color.blue); - // GeneralPath glyphSpritePath = - // new GeneralPath(wordText.getBounds()); - // glyphSpritePath.transform(pageTransform); - // gg.draw(glyphSpritePath); - // } - } - g.setColor(Color.red); - GeneralPath glyphSpritePath = - new GeneralPath(lineText.getBounds()); - glyphSpritePath.transform(pageTransform); - gg.draw(glyphSpritePath); - } - } - } - g.setColor(oldColor); - } - - /** - * Entry point for multiline text selection. Contains logic for moving from once page to the next which boils - * down to defining a start position when a new page is entered. - * - * @param pageViewComponent page view that is being acted. - * @param mouseLocation current mouse location already normalized to page space. . - * @param isDown general selection trent is down, if false it's up. - * @param isMovingRight general selection trent is right, if alse it's left. - */ - protected void multiLineSelectHandler(AbstractPageViewComponent pageViewComponent, Point mouseLocation, - boolean isDown, boolean isLocalDown, boolean isMovingRight) throws InterruptedException{ - Page currentPage = pageViewComponent.getPage(); - selectedCount = 0; - - if (currentPage != null) { - // get page text - PageText pageText = currentPage.getViewText(); - if (pageText != null) { - - // clear the currently selected state, ignore highlighted. - pageText.clearSelected(); - - // get page transform, same for all calculations - AffineTransform pageTransform = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - - ArrayList pageLines = pageText.getPageLines(); - - // create exclusion boxes - calculateTextSelectionExclusion(pageTransform); - - // normalize the mouse coordinates to page space - Point2D.Float draggingMouseLocation = convertMouseToPageSpace(mouseLocation, pageTransform); - - // dragging mouse into a page or from white space, neither glyphStart or glyphEnd will be initialized. - if (glyphStartLocation == null) { - glyphStartLocation = GlyphLocation.findFirstGlyphLocation(pageLines, draggingMouseLocation, isDown, isLocalDown, - lastGlyphEndLocation, topMarginExclusion, bottomMarginExclusion); - // if we're close to something mark the isFirst=false. - if (glyphStartLocation != null) { - glyphEndLocation = new GlyphLocation(glyphStartLocation); - isFirst = false; - } - } else if (glyphStartLocation != null) { - // should already have start but no end. - glyphEndLocation = GlyphLocation.findGlyphLocation(pageLines, draggingMouseLocation, isDown, isLocalDown, - lastGlyphEndLocation, topMarginExclusion, bottomMarginExclusion); - } - - // normal page selection, fill in the the highlight between start and end. - if (glyphStartLocation != null && glyphEndLocation != null) { - selectedCount = GlyphLocation.highLightGlyphs(pageLines, glyphStartLocation, glyphEndLocation, leftToRight, - isDown, isLocalDown, isMovingRight, topMarginExclusion, bottomMarginExclusion); - lastGlyphStartLocation = glyphStartLocation; - lastGlyphEndLocation = glyphEndLocation; - } - // check if last draw are still around and draw them. - else if (lastGlyphStartLocation != null && lastGlyphEndLocation != null) { - selectedCount = GlyphLocation.highLightGlyphs(pageLines, lastGlyphStartLocation, lastGlyphEndLocation, leftToRight, - isDown, isLocalDown, isMovingRight, topMarginExclusion, bottomMarginExclusion); - } - } - pageViewComponent.repaint(); - } - } - - /** - * Utility for selecting multiple lines via rectangle like tool. The - * selection works based on the intersection of the rectangle and glyph - * bounding box. - *

      - * This method should only be called from within a locked page content - * - * @param currentPage page to looking for text intersection on. - * @param mouseLocation location of mouse. - */ - protected void wordSelectHandler(Page currentPage, Point mouseLocation) throws InterruptedException { - - if (currentPage != null) { - // get page text - PageText pageText = currentPage.getViewText(); - if (pageText != null) { - - // clear the currently selected state, ignore highlighted. - pageText.clearSelected(); - - // get page transform, same for all calculations - AffineTransform pageTransform = currentPage.getPageTransform( - Page.BOUNDARY_CROPBOX, - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - - Point2D.Float pageMouseLocation = - convertMouseToPageSpace(mouseLocation, pageTransform); - ArrayList pageLines = pageText.getPageLines(); - if (pageLines != null) { - for (LineText pageLine : pageLines) { - // check for containment, if so break into words. - if (pageLine.getBounds().contains(pageMouseLocation)) { - pageLine.setHasSelected(true); - java.util.List lineWords = pageLine.getWords(); - for (WordText word : lineWords) { - // if (word.contains(pageTransform, mouseLocation)) { - if (word.getBounds().contains(pageMouseLocation)) { - word.selectAll(); - // let the ri know we have selected text. - documentViewModel.addSelectedPageText(pageViewComponent); - documentViewController.firePropertyChange( - PropertyConstants.TEXT_SELECTED, - null, null); - pageViewComponent.repaint(); - break; - } - } - } - } - } - } - } - } - - /** - * Utility for selecting a LineText which is usually a sentence in the - * document. This is usually triggered by a triple click of the mouse - * - * @param currentPage page to select - * @param mouseLocation location of mouse - */ - protected void lineSelectHandler(Page currentPage, Point mouseLocation) throws InterruptedException { - if (currentPage != null) { - // get page text - PageText pageText = currentPage.getViewText(); - if (pageText != null) { - - // clear the currently selected state, ignore highlighted. - pageText.clearSelected(); - - // get page transform, same for all calculations - AffineTransform pageTransform = currentPage.getPageTransform( - Page.BOUNDARY_CROPBOX, - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - - Point2D.Float pageMouseLocation = - convertMouseToPageSpace(mouseLocation, pageTransform); - ArrayList pageLines = pageText.getPageLines(); - if (pageLines != null) { - for (LineText pageLine : pageLines) { - // check for containment, if so break into words. - if (pageLine.getBounds().contains(pageMouseLocation)) { - pageLine.selectAll(); - - // let the ri know we have selected text. - documentViewModel.addSelectedPageText(pageViewComponent); - documentViewController.firePropertyChange( - PropertyConstants.TEXT_SELECTED, - null, null); - - pageViewComponent.repaint(); - break; - } - } - } - } - } - } - - @Override - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - } - - /** - * Sets the top margin used to define an exclusion zone for text selection. For this value - * to be applied the system property -Dorg.icepdf.core.views.page.marginExclusion.enabled=true - * must be set. - * - * @param topMargin top margin height in pixels. - */ - public void setTopMargin(int topMargin) { - this.topMargin = topMargin; - } - - /** - * Sets the bottom margin used to define an exclusion zone for text selection. For this value - * to be applied the system property -Dorg.icepdf.core.views.page.marginExclusion.enabled=true - * must be set. - * - * @param bottomMargin bottom margin height in pixels. - */ - public void setBottomMargin(int bottomMargin) { - this.bottomMargin = bottomMargin; - } -} - -class GlyphLocation { - - private int line, word, glyph; - - public GlyphLocation(int line, int word, int glyph) { - this.line = line; - this.word = word; - this.glyph = glyph; - } - - public GlyphLocation(GlyphLocation glyphLocation) { - this.line = glyphLocation.line; - this.word = glyphLocation.word; - this.glyph = glyphLocation.glyph; - } - - @Override - public String toString() { - return "GlyphLocation{" + - "line=" + line + - ", word=" + word + - ", glyph=" + glyph + - '}'; - } - - public static WordText getWord(ArrayList pageLines, GlyphLocation location) { - return pageLines.get(location.line).getWords().get(location.word); - } - - public static GlyphText getGlyph(ArrayList pageLines, GlyphLocation location) { - return pageLines.get(location.line).getWords().get(location.word).getGlyphs().get(location.glyph); - } - - public static GlyphLocation multiPageSelectGlyphLocation(ArrayList pageLines, - Point2D.Float mouseLocation, - boolean isDown, boolean leftToRight, - Shape topMarginExclusion, Shape bottomMarginExclusion) { - if (pageLines == null) return null; - // find first glyph of first line - if (isDown && leftToRight) { - for (int i = 0, max = pageLines.size(); i < max; i++) { - if (isLineTextIncluded(pageLines.get(i), topMarginExclusion, bottomMarginExclusion) && - findMouseContainedWithInLine(mouseLocation, pageLines.get(i))) { - return new GlyphLocation(i, 0, 0); - } - } - } - // first line and last glyph - else if (isDown) { - for (int i = 0, max = pageLines.size(); i < max; i++) { - if (isLineTextIncluded(pageLines.get(i), topMarginExclusion, bottomMarginExclusion) && - findMouseContainedWithInLine(mouseLocation, pageLines.get(i))) { - int lastWordIndex = pageLines.get(i).getWords().size() - 1; - WordText lastWord = pageLines.get(i).getWords().get(lastWordIndex); - return new GlyphLocation(i, lastWordIndex, lastWord.getGlyphs().size() - 1); - } - } - } - // going up is always right to left. - else { - for (int i = pageLines.size() - 1; i >= 0; i--) { - if (isLineTextIncluded(pageLines.get(i), topMarginExclusion, bottomMarginExclusion) - && findMouseContainedWithInLine(mouseLocation, pageLines.get(i))) { - int lastWordIndex = pageLines.get(i).getWords().size() - 1; - WordText lastWord = pageLines.get(i).getWords().get(lastWordIndex); - return new GlyphLocation(i, lastWordIndex, lastWord.getGlyphs().size() - 1); - } - } - } - return null; - } - - public static boolean isLineTextIncluded(LineText lineText, Shape topMarginExclusion, Shape bottomMarginExclusion) { - if (enableMarginExclusion) { - return !(topMarginExclusion.contains(lineText.getBounds()) || - bottomMarginExclusion.contains(lineText.getBounds())); - } - return true; - } - - public static GlyphLocation findGlyphLocation(ArrayList pageLines, Point2D.Float cursorLocation, - boolean isDown, boolean isLocalDown, GlyphLocation lastGlyphEndLocation, - Shape topMarginExclusion, Shape bottomMarginExclusion) { - if (pageLines != null) { - // check for a direct intersection. - GlyphLocation glyphLocation = - findGlyphIntersection(pageLines, cursorLocation, topMarginExclusion, bottomMarginExclusion); - if (glyphLocation != null) return glyphLocation; - - // check mouse location against y-coordinate of a line and grab the last line - // this is buggy if the lines aren't sorted via !org.icepdf.core.views.page.text.preserveColumns. - if ((isLocalDown && isDown) || isLocalDown) { - int lastGlyphEndLine = 0; - if (lastGlyphEndLocation != null) { - lastGlyphEndLine = lastGlyphEndLocation.line; - } - // get the next line last word. - int lineIndex = lastGlyphEndLine; - for (int lineMax = pageLines.size(); lineIndex < lineMax - 1; lineIndex++) { - float y1 = pageLines.get(lineIndex).getBounds().y; - float y2 = pageLines.get(lineIndex + 1).getBounds().y; - if (cursorLocation.y < y1 && cursorLocation.y >= y2) { - LineText lineText = pageLines.get(lineIndex + 1); - if (isLineTextIncluded(lineText, topMarginExclusion, bottomMarginExclusion)) { - java.util.List words = lineText.getWords(); - return new GlyphLocation(lineIndex + 1, words.size() - 1, - words.get(words.size() - 1).getGlyphs().size() - 1); - } - } - } - // else fill the line - if (lastGlyphEndLine < pageLines.size() && lastGlyphEndLine > pageLines.size() - 5) { - LineText lineText = pageLines.get(lastGlyphEndLine); - if (isLineTextIncluded(lineText, topMarginExclusion, bottomMarginExclusion)) { - java.util.List words = lineText.getWords(); - return new GlyphLocation(lastGlyphEndLine, words.size() - 1, - words.get(words.size() - 1).getGlyphs().size() - 1); - } - } - } else { - if (lastGlyphEndLocation != null) { - // find left most world. - int lineIndex = lastGlyphEndLocation.line; - for (; lineIndex > 0; lineIndex--) { - float y1 = pageLines.get(lineIndex).getBounds().y; - float y2 = pageLines.get(lineIndex - 1).getBounds().y; - if (cursorLocation.y >= y1 && cursorLocation.y < y2) { - LineText lineText = pageLines.get(lineIndex - 1); - if (isLineTextIncluded(lineText, topMarginExclusion, bottomMarginExclusion)) { - return new GlyphLocation(lineIndex - 1, 0, 0); - } - } - } - // else fill the line - // todo setup loop to find line closed to the exclusion, not just the first line. - if (lastGlyphEndLocation.line < 5) { - LineText lineText = pageLines.get(lastGlyphEndLocation.line); - if (isLineTextIncluded(lineText, topMarginExclusion, bottomMarginExclusion)) { - return new GlyphLocation(lastGlyphEndLocation.line, 0, 0); - } - } - } - } - } - return null; - } - - public static GlyphLocation findGlyphIntersection(ArrayList pageLines, Point2D.Float cursorLocation, - Shape topMarginExclusion, Shape bottomMarginExclusion) { - LineText pageLine; - // check for a direct intersection. - for (int lineIndex = 0, lineMax = pageLines.size(); lineIndex < lineMax; lineIndex++) { - pageLine = pageLines.get(lineIndex); - if (pageLine.intersects(cursorLocation) && isLineTextIncluded(pageLine, topMarginExclusion, bottomMarginExclusion)) { - java.util.List lineWords = pageLines.get(lineIndex).getWords(); - WordText currentWord; - for (int wordIndex = 0, wordMax = lineWords.size(); wordIndex < wordMax; wordIndex++) { - currentWord = lineWords.get(wordIndex); - if (currentWord.intersects(cursorLocation)) { - ArrayList glyphs = currentWord.getGlyphs(); - for (int glyphIndex = 0, glyphMax = glyphs.size(); glyphIndex < glyphMax; glyphIndex++) { - GlyphText currentGlyph = glyphs.get(glyphIndex); - if (currentGlyph.intersects(cursorLocation)) { - return new GlyphLocation(lineIndex, wordIndex, glyphIndex); - } - } - } - } - } - } - return null; - } - - public static GlyphLocation findFirstGlyphLocation(ArrayList pageLines, Point2D.Float cursorLocation, - boolean isDown, boolean isLocalDown, GlyphLocation lastGlyphEndLocation, - Shape topMarginExclusion, Shape bottomMarginExclusion) { - if (pageLines != null) { - // check mouse location against y-coordinate of a line and depending on direction pick - // first or last world a line. - if (isDown) { - // find first word of first y line - int lineIndex = 0; - for (int lineMax = pageLines.size() - 1; lineIndex < lineMax; lineIndex++) { - float y1 = pageLines.get(lineIndex).getBounds().y; - float y2 = pageLines.get(lineIndex + 1).getBounds().y; - if (cursorLocation.y < (y1 + pageLines.get(lineIndex).getBounds().height) - && cursorLocation.y >= (y2 + pageLines.get(lineIndex + 1).getBounds().height)) { - LineText lineText = pageLines.get(lineIndex); - if (isLineTextIncluded(lineText, topMarginExclusion, bottomMarginExclusion)) { - return new GlyphLocation(lineIndex, 0, 0); - } - } - } - } - // going up so check against y bottom up and then pick last work. - else { - // find left most world. - int lineIndex = pageLines.size() - 1; - for (; lineIndex > 0; lineIndex--) { - float y1 = pageLines.get(lineIndex - 1).getBounds().y; - float y2 = pageLines.get(lineIndex).getBounds().y; - if (cursorLocation.y < (y1 + pageLines.get(lineIndex - 1).getBounds().height) - && cursorLocation.y >= (y2 + pageLines.get(lineIndex).getBounds().height)) { - LineText lineText = pageLines.get(lineIndex); - if (isLineTextIncluded(lineText, topMarginExclusion, bottomMarginExclusion)) { - java.util.List words = lineText.getWords(); - return new GlyphLocation(lineIndex, words.size() - 1, - words.get(words.size() - 1).getGlyphs().size() - 1); - } - } - } - } - } - return null; - } - - public static boolean findMouseContainedWithInLine(Point2D.Float mouseLocation, LineText pageLines) { - return pageLines.getBounds().contains(mouseLocation); - } - - public static int highLightGlyphs(ArrayList pageLines, GlyphLocation start, GlyphLocation end, - boolean leftToRight, boolean isDown, boolean isLocalDown, boolean isRight, - Shape topMarginExclusion, Shape bottomMarginExclusion) { - if (pageLines == null) return 0; - int selectedCount = fillFirstLine(pageLines.get(start.line), start, end, isDown, isRight, leftToRight); - // fill middle, if any - selectedCount += fillMiddleLines(pageLines, start, end, topMarginExclusion, bottomMarginExclusion); - // fill last line, last line if any - selectedCount += fillLastLine(pageLines.get(end.line), start, end, isDown, isRight, leftToRight); - return selectedCount; - } - - - public static int fillFirstLine(LineText pageLine, GlyphLocation start, GlyphLocation end, - boolean isDown, boolean isRight, boolean isLTR) { - pageLine.setHasHighlight(true); - java.util.List lineWords = pageLine.getWords(); - int selectedCount = 0; - // last half of the first word - selectedCount += fillFirstWord(lineWords, start, end, isRight, isDown); - // first half of the last word - selectedCount += fillLastWord(lineWords, start, end, isRight, isDown); - - if (start.line == end.line) { - if (isRight && end.word > start.word) { - // fill left to right - for (int wordIndex = start.word + 1; wordIndex <= end.word - 1; wordIndex++) { - lineWords.get(wordIndex).selectAll(); - selectedCount++; - } - } else { - // fill right to left - for (int wordIndex = start.word - 1; wordIndex >= end.word + 1; wordIndex--) { - lineWords.get(wordIndex).selectAll(); - selectedCount++; - } - } - } else if ((isRight && isDown) || (!isRight && isDown)) { - // fill right to end of line - for (int wordIndex = start.word + 1; wordIndex < lineWords.size(); wordIndex++) { - lineWords.get(wordIndex).selectAll(); - selectedCount++; - } - } else {// if ((isRight && !isDown) || (!isRight && !isDown)){ - // fill left to start of line - for (int wordIndex = start.word - 1; wordIndex >= 0; wordIndex--) { - lineWords.get(wordIndex).selectAll(); - selectedCount++; - } - } - return selectedCount; - } - - public static int fillFirstWord(java.util.List words, GlyphLocation start, GlyphLocation end, - boolean isRight, boolean isDown) { - int selectedCount = 0; - if (end != null && start.line == end.line) { - if (start.word == end.word) { - if (isRight) { - // same word so we move to select start->end. - WordText word = words.get(start.word); - word.setHasSelected(true); - for (int glyphIndex = start.glyph; glyphIndex <= end.glyph; glyphIndex++) { - word.getGlyphs().get(glyphIndex).setSelected(true); - selectedCount++; - } - - } else { - WordText word = words.get(start.word); - word.setHasSelected(true); - for (int glyphIndex = start.glyph; glyphIndex >= end.glyph; glyphIndex--) { - word.getGlyphs().get(glyphIndex).setSelected(true); - selectedCount++; - } - } - } else { - if (isRight && end.word > start.word) { - WordText word = words.get(start.word); - word.setHasSelected(true); - for (int glyphIndex = start.glyph; glyphIndex < word.getGlyphs().size(); glyphIndex++) { - word.getGlyphs().get(glyphIndex).setSelected(true); - selectedCount++; - } - } else { - WordText word = words.get(start.word); - word.setHasSelected(true); - for (int glyphIndex = start.glyph; glyphIndex >= 0; glyphIndex--) { - word.getGlyphs().get(glyphIndex).setSelected(true); - selectedCount++; - } - } - } - } else if ((isRight && isDown) || (!isRight && isDown)) { - WordText word = words.get(start.word); - word.setHasSelected(true); - for (int glyphIndex = start.glyph; glyphIndex < word.getGlyphs().size(); glyphIndex++) { - word.getGlyphs().get(glyphIndex).setSelected(true); - selectedCount++; - } - } else {//if ((isRight && !isDown) || (!isRight && !isDown)) { - WordText word = words.get(start.word); - word.setHasSelected(true); - for (int glyphIndex = start.glyph; glyphIndex >= 0; glyphIndex--) { - word.getGlyphs().get(glyphIndex).setSelected(true); - } - } - return selectedCount; - - } - - public static int fillLastWord(java.util.List words, GlyphLocation start, GlyphLocation end, - boolean isRight, boolean isDown) { - int selectedCount = 0; - if (isRight && end.word > start.word) { - // same word so we move to select start->end. - if (start.word == end.word && start.line == end.line) { - // nothing to do handled by the first word. - } - // at least two words so we can do the last half of start and first half of end. - else if (start.line == end.line) { - WordText word = words.get(end.word); - word.setHasSelected(true); - for (int glyphIndex = 0; glyphIndex <= end.glyph; glyphIndex++) { - word.getGlyphs().get(glyphIndex).setSelected(true); - selectedCount++; - } - } - } else { - // same word so we move to select start->end. - if (start.word == end.word && start.line == end.line) { - WordText word = words.get(end.word); - word.setHasSelected(true); - for (int glyphIndex = start.glyph; glyphIndex >= end.glyph; glyphIndex--) { - word.getGlyphs().get(glyphIndex).setSelected(true); - selectedCount++; - } - } - // at least two words so we can do the last half of start and first half of end. - else if (start.line == end.line) { - WordText word = words.get(end.word); - word.setHasSelected(true); - for (int glyphIndex = word.getGlyphs().size() - 1; glyphIndex >= end.glyph; glyphIndex--) { - word.getGlyphs().get(glyphIndex).setSelected(true); - selectedCount++; - } - } - } - return selectedCount; - } - - public static int fillLastLine(LineText pageLine, GlyphLocation start, GlyphLocation end, - boolean isDown, boolean isRight, boolean isLTR) { - java.util.List lineWords = pageLine.getWords(); - int selectedCount = 0; - if (start.line != end.line) { - pageLine.setHasHighlight(true); - if (isDown) { - WordText word = lineWords.get(end.word); - word.setHasSelected(true); - for (int glyphIndex = 0; glyphIndex <= end.glyph; glyphIndex++) { - word.getGlyphs().get(glyphIndex).setSelected(true); - selectedCount++; - } - for (int wordIndex = 0; wordIndex < end.word; wordIndex++) { - lineWords.get(wordIndex).selectAll(); - selectedCount++; - } - } else { - selectedCount += fillFirstWord(lineWords, end, null, isRight, true); - // - for (int wordIndex = end.word + 1; wordIndex < lineWords.size(); wordIndex++) { - lineWords.get(wordIndex).selectAll(); - selectedCount++; - } - } - } - return selectedCount; - } - - public static int fillMiddleLines(ArrayList pageLines, GlyphLocation start, GlyphLocation end, - Shape topMarginExclusion, Shape bottomMarginExclusion) { - GlyphLocation startLocal = new GlyphLocation(start); - GlyphLocation endLocal = new GlyphLocation(end); - if (startLocal.line > endLocal.line) { - GlyphLocation tmp = startLocal; - startLocal = end; - endLocal = tmp; - } - int selectedCount = 0; - for (int lineIndex = startLocal.line + 1; lineIndex < endLocal.line; lineIndex++) { - if (isLineTextIncluded(pageLines.get(lineIndex), topMarginExclusion, bottomMarginExclusion)) { - pageLines.get(lineIndex).selectAll(); - selectedCount++; - } - } - return selectedCount; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextSelectionPageHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextSelectionPageHandler.java deleted file mode 100644 index ef07b5b396..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextSelectionPageHandler.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.NoninvertibleTransformException; -import java.util.ArrayList; -import java.util.logging.Level; - -/** - * Handles Paint and mouse/keyboard logic around text selection and search - * highlighting. there is on text handler isntance of each pageComponent - * used to dispaly the document. - *

      - * The highlight colour by default is #FFF600 but can be set using color or - * hex values names using the system property "org.icepdf.core.views.page.text.highlightColor" - *

      - * The highlight colour by default is #FFF600 but can be set using color or - * hex values names using the system property "org.icepdf.core.views.page.text.selectionColor" - *

      - * - * @since 4.0 - */ -public class TextSelectionPageHandler extends TextSelection - implements ToolHandler { - - /** - * New Text selection handler. Make sure to correctly and and remove - * this mouse and text listeners. - * - * @param pageViewComponent page component that this handler is bound to. - * @param documentViewModel view model. - */ - public TextSelectionPageHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - } - - public void setDocumentViewController(DocumentViewController documentViewController) { - this.documentViewController = documentViewController; - } - - /** - * When mouse is double clicked we select the word the mouse if over. When - * the mouse is triple clicked we select the line of text that the mouse - * is over. - */ - public void mouseClicked(MouseEvent e) { - wordLineSelection(e.getClickCount(), e.getPoint(), pageViewComponent); - } - - /** - * Invoked when a mouse button has been pressed on a component. - */ - public void mousePressed(MouseEvent e) { - - lastMousePressedLocation = e.getPoint(); - - selectionStart(e.getPoint(), pageViewComponent, true); - } - - /** - * Invoked when a mouse button has been released on a component. - */ - public void mouseReleased(MouseEvent e) { - selectionEnd(e.getPoint(), pageViewComponent); - } - - /** - * Invoked when a mouse button is pressed on a component and then - * dragged. MOUSE_DRAGGED events will continue to be - * delivered to the component where the drag originated until the - * mouse button is released (regardless of whether the mouse position - * is within the bounds of the component). - *

      - * Due to platform-dependent Drag&Drop implementations, - * MOUSE_DRAGGED events may not be delivered during a native - * Drag&Drop operation. - */ - public void mouseDragged(MouseEvent e) { - Point point = e.getPoint(); - updateSelectionSize(point.x, point.y, pageViewComponent); - boolean isMovingDown = true; - boolean isMovingRight = true; - if (lastMousePressedLocation != null) { - isMovingDown = lastMousePressedLocation.y <= e.getPoint().y; - isMovingRight = lastMousePressedLocation.x <= e.getPoint().x; - } - selection(e.getPoint(), pageViewComponent, isMovingDown, isMovingRight); - } - - /** - * Invoked when the mouse enters a component. - */ - public void mouseEntered(MouseEvent e) { - - } - - /** - * Invoked when the mouse exits a component. - */ - public void mouseExited(MouseEvent e) { - - } - - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - - // rectangle select tool - setSelectionSize(selection, pageViewComponent); - - } - - /** - * Invoked when the mouse cursor has been moved onto a component - * but no buttons have been pushed. - */ - public void mouseMoved(MouseEvent e) { - // change state of mouse from pointer to text selection icon - selectionIcon(e.getPoint(), pageViewComponent); - } - - public void installTool() { - - } - - public void uninstallTool() { - - } - - public void paintTool(Graphics g) { - if (enableMarginExclusionBorder && topMarginExclusion != null && bottomMarginExclusion != null) { - - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - - ((Graphics2D)g).transform(at); - g.setColor(Color.RED); - paintSelectionBox(g, topMarginExclusion.getBounds()); - g.setColor(Color.BLUE); - paintSelectionBox(g, bottomMarginExclusion.getBounds()); - } - } - - /** - * Convert the shapes that make up the annotation to page space so that - * they will scale correctly at different zooms. - * - * @return transformed bBox. - */ - protected Rectangle convertToPageSpace(ArrayList bounds, - GeneralPath path) { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error converting to page space.", e); - } - // convert the two points as well as the bbox. - Rectangle tBbox = at.createTransformedShape(path).getBounds(); - - // convert the points - Shape bound; - for (int i = 0; i < bounds.size(); i++) { - bound = bounds.get(i); - bound = at.createTransformedShape(bound); - bounds.set(i, bound); -// bound.setRect(tBound.getX(), tBound.getY(), -// tBound.getWidth(), tBound.getHeight()); - } - - path.transform(at); - - return tBbox; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextSelectionViewHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextSelectionViewHandler.java deleted file mode 100644 index 69f603a4e8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/TextSelectionViewHandler.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.PageViewComponentImpl; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; -import java.awt.event.MouseWheelListener; -import java.util.ArrayList; -import java.util.logging.Logger; - -/** - * TextSelectionViewHandler propagates text selection events into the the - * views child page components. This handle is required for multi-page text - * selection. On mouse click all text selection states are removed. - * - * @since 5.0 - */ -public class TextSelectionViewHandler extends TextSelection - implements ToolHandler, MouseWheelListener { - - protected static final Logger logger = - Logger.getLogger(TextSelectionViewHandler.class.toString()); - - protected JComponent parentComponent; - - protected boolean isDragging; - - public TextSelectionViewHandler(DocumentViewController documentViewController, - DocumentViewModel documentViewModel, - JComponent parentComponent) { - super(documentViewController, null, documentViewModel); - this.parentComponent = parentComponent; - } - - public void mouseClicked(MouseEvent e) { - - // clear all selected text. - documentViewController.clearSelectedText(); - clearSelectionState(); - - // check if we are over a page - PageViewComponentImpl pageComponent = isOverPageComponent(parentComponent, e); - - if (pageComponent != null) { - pageComponent.requestFocus(); - // click word and line selection - MouseEvent modeEvent = SwingUtilities.convertMouseEvent(parentComponent, e, pageComponent); - pageComponent.getTextSelectionPageHandler().wordLineSelection( - modeEvent.getClickCount(), modeEvent.getPoint(), pageComponent); - } - } - - public void mousePressed(MouseEvent e) { - // clear all selected text. - documentViewController.clearSelectedText(); - clearSelectionState(); - - lastMousePressedLocation = e.getPoint(); - - // start selection box. - resetRectangle(e.getX(), e.getY()); - - // check if we are over a page - PageViewComponentImpl pageComponent = isOverPageComponent(parentComponent, e); - if (pageComponent != null) { - pageComponent.requestFocus(); - MouseEvent modeEvent = SwingUtilities.convertMouseEvent(parentComponent, e, pageComponent); - pageComponent.getTextSelectionPageHandler().selectionStart(modeEvent.getPoint(), pageComponent, true); - } - } - - public void mouseReleased(MouseEvent e) { - - isDragging = false; - - // deselect rectangles on other selected pages. - ArrayList selectedPages = - documentViewModel.getSelectedPageText(); - - // check if we are over a page - AbstractPageViewComponent pageComponent = - isOverPageComponent(parentComponent, e); - - if (pageComponent != null) { - MouseEvent modeEvent = SwingUtilities.convertMouseEvent( - parentComponent, e, pageComponent); - - if (selectedPages != null && - selectedPages.size() > 0) { - PageViewComponentImpl pageComp; - for (AbstractPageViewComponent selectedPage : selectedPages) { - pageComp = (PageViewComponentImpl)selectedPage; - if (pageComp != null) { - pageComp.getTextSelectionPageHandler().selectionEnd(modeEvent.getPoint(), pageComp); - } - } - } - } - // finally if we have selected any text then fire a property change event - if (selectedPages != null && selectedPages.size() > 0) { - documentViewController.firePropertyChange( - PropertyConstants.TEXT_SELECTED, - null, null); - } - - // clear the rectangle - clearRectangle(parentComponent); - } - - public void mouseWheelMoved(MouseWheelEvent e) { - - if (isDragging) { - Component target = documentViewController.getViewPort().getView(); - Point p = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), target); - MouseEvent m = new MouseEvent(target, - 0, e.getWhen(), e.getModifiers(), - p.x, p.y, - e.getClickCount(), e.isPopupTrigger(), e.getButton()); - mouseDragged(m); - } - } - - public void mouseDragged(MouseEvent e) { - - // handle text selection drags. - if (documentViewController != null) { - isDragging = true; - - // update the currently parentComponent box - updateSelectionSize(e.getX(), e.getY(), parentComponent); - - // clear previously selected pages - documentViewModel.clearSelectedPageText(); - - // add selection box to child pages - if (documentViewModel != null) { - java.util.List pages = - documentViewModel.getPageComponents(); - for (AbstractPageViewComponent page : pages) { - Rectangle tmp = SwingUtilities.convertRectangle( - parentComponent, getRectToDraw(), page); - if (page.getBounds().intersects(tmp)) { - // add the page to the page as it is marked for selection - documentViewModel.addSelectedPageText(page); - - Point modEvent = SwingUtilities.convertPoint(parentComponent, - e.getPoint(), page); - - // set the selected region. - page.setSelectionRectangle(modEvent, tmp); - - // pass the selection movement on to the page. - boolean isMovingDown = lastMousePressedLocation.y <= e.getPoint().y; - boolean isMovingRight = lastMousePressedLocation.x <= e.getPoint().x; - ((PageViewComponentImpl)page).getTextSelectionPageHandler().selection(modEvent, page, isMovingDown, isMovingRight); - - } else { - documentViewModel.removeSelectedPageText(page); - page.clearSelectedText(); - page.repaint(); - } - } - } - } - - } - - public void mouseMoved(MouseEvent e) { - - PageViewComponentImpl pageComponent = isOverPageComponent(parentComponent, e); - if (pageComponent != null) { - // assign the correct icon state for the cursor. - MouseEvent modeEvent = SwingUtilities.convertMouseEvent(parentComponent, e, pageComponent); - pageComponent.getTextSelectionPageHandler().selectionIcon(modeEvent.getPoint(), pageComponent); - } - - } - - public void paintTool(Graphics g) { -// paintSelectionBox(g, rectToDraw); - } - - @Override - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - - } - - public void installTool() { - - } - - public void uninstallTool() { - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ToolHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ToolHandler.java deleted file mode 100644 index 09c28b691f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ToolHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import javax.swing.event.MouseInputListener; -import java.awt.*; - -/** - * The ToolHandler interface should be implemented by any tool handler that - * needs to paints to the screen. - */ -public interface ToolHandler extends MouseInputListener { - - /** - * Paints the tools pre-annotation creation state. - * - * @param g graphics context - */ - void paintTool(Graphics g); - - - /** - * Callback code that allows post construct task to take place when the - * tool is selected via the - * {@link org.icepdf.ri.common.views.AbstractDocumentView#setToolMode(int)} - * call. - */ - void installTool(); - - /** - * Callback code that allows pre destroy task to take place when the - * tool is unselected via the - * {@link org.icepdf.ri.common.views.AbstractDocumentView#setToolMode(int)} - * call. - */ - void uninstallTool(); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/UnderLineAnnotationHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/UnderLineAnnotationHandler.java deleted file mode 100644 index a6ceb8455d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/UnderLineAnnotationHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.core.pobjects.annotations.TextMarkupAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -/** - * UnderLineAnnotationHandler tool extends TextSelectionPageHandler which - * takes care visually selected text as the mouse is dragged across text on the - * current page. - *

      - * Once the mouseReleased event is fired this handler will create new - * UnderLineAnnotation and respective AnnotationComponent. The addition of the - * Annotation object to the page is handled by the annotation callback. Once - * create the handler will deselect the text and the newly created annotation - * will be displayed. - * - * @since 5.0 - */ -public class UnderLineAnnotationHandler extends HighLightAnnotationHandler { - - public UnderLineAnnotationHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - highLightType = TextMarkupAnnotation.SUBTYPE_UNDERLINE; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ZoomInPageHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ZoomInPageHandler.java deleted file mode 100644 index df5f950f5a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ZoomInPageHandler.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.event.InputEvent; -import java.awt.event.MouseEvent; -import java.util.logging.Logger; - -/** - * Handles mouse click zoom in and scroll box zoom in. The zoom is handled at the - * AbstractDocumentView level as we accept mouse clicks from anywhere in the - * view. - * - * @since 4.0 - */ -public class ZoomInPageHandler extends SelectionBoxHandler implements ToolHandler { - - private static final Logger logger = - Logger.getLogger(ZoomInPageHandler.class.toString()); - - private Point initialPoint = new Point(); - - public ZoomInPageHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(documentViewController, pageViewComponent, documentViewModel); - - selectionBoxColour = Color.DARK_GRAY; - } - - public void mouseDragged(MouseEvent e) { - // handle text selection drags. - if (documentViewController != null) { - // update the currently selected box - updateSelectionSize(e.getX(),e.getY(), pageViewComponent); - } - } - - public void mouseClicked(MouseEvent e) { - if ((e.getModifiers() & MouseEvent.MOUSE_PRESSED) != 0) { - if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { - // zoom in - Point pageOffset = documentViewModel.getPageBounds( - pageViewComponent.getPageIndex()).getLocation(); - Point mouse = e.getPoint(); - mouse.setLocation(pageOffset.x + mouse.x, - pageOffset.y + mouse.y); - documentViewController.setZoomIn(mouse); - } - } - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } - - public void mousePressed(MouseEvent e) { - // start selection box. - if (documentViewController != null) { - resetRectangle(e.getX(), e.getY()); - initialPoint.setLocation(e.getPoint()); - } - } - - public void mouseReleased(MouseEvent e) { - if (documentViewController != null) { - // update selection rectangle - updateSelectionSize(e.getX(),e.getY(), pageViewComponent); - - // adjust the starting position of rectToDraw to match the actual - // view position of the rectangle as the mouseEven position is - // is relative to the page and now the view. - int pageIndex = pageViewComponent.getPageIndex(); - Rectangle pageOffset = documentViewModel.getPageBounds(pageIndex); - Rectangle absoluteRectToDraw = new Rectangle( - pageOffset.x + rectToDraw.x, - pageOffset.y + rectToDraw.y, - rectToDraw.width, rectToDraw.height); - - if (documentViewController.getViewPort() != null && - absoluteRectToDraw.getWidth() > 0 && - absoluteRectToDraw.getHeight() > 0) { - // zoom in on rectangle bounds. - float zoom = ZoomInPageHandler.calculateZoom(documentViewController, - absoluteRectToDraw, documentViewModel); - - // calculate the delta relative to current page position - Point delta = new Point( - absoluteRectToDraw.x - pageOffset.x, - absoluteRectToDraw.y - pageOffset.y); - documentViewController.setZoomToViewPort(zoom, delta, pageIndex, true); - } - // clear the rectangle - clearRectangle(pageViewComponent); - } - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void mouseMoved(MouseEvent e) { - - } - - @Override - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - // rectangle select tool - setSelectionSize(selection, pageViewComponent); - } - - public void paintTool(Graphics g) { - paintSelectionBox(g, rectToDraw); - } - - public void installTool() { - - } - - public void uninstallTool() { - - } - - public static float calculateZoom(DocumentViewController documentViewController, - Rectangle rectToDraw, - DocumentViewModel documentViewModel) { - - Dimension viewport = documentViewController.getViewPort().getParent().getSize(); - int selectionMax = rectToDraw.width; - int screenMax = viewport.width; - // find the largest dimension of the selection rectangle. - if (screenMax < viewport.getHeight()) { - screenMax = viewport.height; - } - if (selectionMax < rectToDraw.getHeight()) { - selectionMax = rectToDraw.height; - } - // figure out the zoom ratio - return (screenMax / (float) selectionMax) * documentViewModel.getViewZoom(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ZoomInViewHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ZoomInViewHandler.java deleted file mode 100644 index caf452221e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ZoomInViewHandler.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.ri.common.views.AbstractDocumentView; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.InputEvent; -import java.awt.event.MouseEvent; -import java.util.List; -import java.util.logging.Logger; - -/** - * ZoomInViewHandler handles selection box zoom features when the mouse is - * dragged creating box which will be used to calculate a corresponding zoom - * level. - * - * @since 5.0 - */ -public class ZoomInViewHandler extends SelectionBoxHandler implements ToolHandler { - - private static final Logger logger = - Logger.getLogger(ZoomInPageHandler.class.toString()); - - private AbstractDocumentView parentComponent; - - public ZoomInViewHandler(DocumentViewController documentViewController, - DocumentViewModel documentViewModel, - AbstractDocumentView parentComponent) { - super(documentViewController, null, documentViewModel); - this.parentComponent = parentComponent; - } - - public void mouseDragged(MouseEvent e) { - // handle text selection drags. - if (documentViewController != null) { - // update the currently selected box - updateSelectionSize(e.getX(),e.getY(), parentComponent); - - // add selection box to child pages - if (documentViewModel != null) { - java.util.List pages = - documentViewModel.getPageComponents(); - for (AbstractPageViewComponent page : pages) { - Rectangle tmp = SwingUtilities.convertRectangle( - parentComponent, getRectToDraw(), page); - if (page.getBounds().intersects(tmp)) { - - // convert the rectangle to the correct space - Rectangle selectRec = - SwingUtilities.convertRectangle(parentComponent, - rectToDraw, - page); - // set the selected region. - page.setSelectionRectangle( - SwingUtilities.convertPoint(parentComponent, - e.getPoint(), page), - selectRec); - } - } - } - } - } - - public void mouseClicked(MouseEvent e) { - if ((e.getModifiers() & MouseEvent.MOUSE_PRESSED) != 0) { - if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { - // zoom in - documentViewController.setZoomIn(e.getPoint()); - } - } - if (parentComponent != null) { - parentComponent.requestFocus(); - } - } - - public void mousePressed(MouseEvent e) { - // start selection box. - if (documentViewController != null) { - resetRectangle(e.getX(), e.getY()); - } - } - - public void mouseReleased(MouseEvent e) { - if (documentViewController != null) { - // update selection rectangle - updateSelectionSize(e.getX(),e.getY(), parentComponent); - - if (documentViewController.getViewPort() != null && - rectToDraw.getWidth() > 0 && - rectToDraw.getHeight() > 0) { - // zoom in on rectangle bounds. - float zoom = ZoomInPageHandler.calculateZoom( - documentViewController, rectToDraw, documentViewModel); - - // scale the zoom box center to the new location - Point center = new Point((int) rectToDraw.getCenterX(), - (int) rectToDraw.getCenterY()); - - documentViewController.setZoomCentered(zoom, center, true); - } - - // clear the rectangle - clearRectangle(parentComponent); - - // clear the child rectangle - // deselect rectangles on other selected pages. - // consider only repainting visible pages. - List selectedPages = - documentViewModel.getPageComponents(); - if (selectedPages != null && - selectedPages.size() > 0) { - for (AbstractPageViewComponent pageComp : selectedPages) { - if (pageComp != null && pageComp.isVisible()) { - pageComp.clearSelectionRectangle(); - } - } - } - } - } - - public void installTool() { - - } - - public void uninstallTool() { - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void mouseMoved(MouseEvent e) { - - } - - @Override - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - - } - - public void paintTool(Graphics g) { - paintSelectionBox(g, rectToDraw); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ZoomOutPageHandler.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ZoomOutPageHandler.java deleted file mode 100644 index 9534287bf2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/tools/ZoomOutPageHandler.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.tools; - -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.event.InputEvent; -import java.awt.event.MouseEvent; -import java.util.logging.Logger; - -/** - * Handles mouse click zoom out functionality. The zoom is handled at the - * AbstractDocumentView level as we accept mouse clicks from anywhere in the - * view. - * - * @since 4.0 - */ -public class ZoomOutPageHandler implements ToolHandler { - - private static final Logger logger = - Logger.getLogger(ZoomOutPageHandler.class.toString()); - - private AbstractPageViewComponent pageViewComponent; - private DocumentViewController documentViewController; - private DocumentViewModel documentViewModel; - - public ZoomOutPageHandler(DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - this.documentViewController = documentViewController; - this.pageViewComponent = pageViewComponent; - this.documentViewModel = documentViewModel; - } - - - public void mouseClicked(MouseEvent e) { - if ((e.getModifiers() & MouseEvent.MOUSE_PRESSED) != 0) { - if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0) { - // zoom in - Point pageOffset = documentViewModel.getPageBounds( - pageViewComponent.getPageIndex()).getLocation(); - Point mouse = e.getPoint(); - mouse.setLocation(pageOffset.x + mouse.x, - pageOffset.y + mouse.y); - documentViewController.setZoomOut(mouse); - } - } - if (pageViewComponent != null) { - pageViewComponent.requestFocus(); - } - } - - public void mouseDragged(MouseEvent e) { - } - - public void mouseMoved(MouseEvent e) { - } - - public void mousePressed(MouseEvent e) { - - } - - public void mouseReleased(MouseEvent e) { - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - public void paintTool(Graphics g) { - - } - - public void installTool() { - - } - - public void uninstallTool() { - - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/ActionsPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/ActionsPanel.java deleted file mode 100644 index 0ff19a38d0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/ActionsPanel.java +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.actions.ActionFactory; -import org.icepdf.core.pobjects.actions.GoToAction; -import org.icepdf.core.pobjects.actions.LaunchAction; -import org.icepdf.core.pobjects.actions.URIAction; -import org.icepdf.core.pobjects.annotations.LinkAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.logging.Logger; - -/** - * Actions panel manages an annotations actions as annotation can have zero - * or more annotations. The pannel allows a user add, edit and remove - * actions for the selected annotation. - * - * @since 4.0 - */ -@SuppressWarnings("serial") -public class ActionsPanel extends AnnotationPanelAdapter - implements ListSelectionListener, ActionListener { - - private static final Logger logger = - Logger.getLogger(ActionsPanel.class.toString()); - - // actionList of action actions - private DefaultListModel actionListModel; - private JList actionList; - - // add, edit, remove buttons. - private JButton addAction; - private JButton editAction; - private JButton removeAction; - - // action type descriptions - private String destinationLabel; - private String uriActionLabel; - private String goToActionLabel; - private String launchActionLabel; - - // Goto action dialog - private GoToActionDialog goToActionDialog; - - public ActionsPanel(SwingController controller) { - super(controller); - setLayout(new GridLayout(2, 1, 5, 5)); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - this.setEnabled(false); - - // assign language values for supported action types - destinationLabel = messageBundle.getString("viewer.utilityPane.action.type.destination.label"); - uriActionLabel = messageBundle.getString("viewer.utilityPane.action.type.uriAction.label"); - goToActionLabel = messageBundle.getString("viewer.utilityPane.action.type.goToAction.label"); - launchActionLabel = messageBundle.getString("viewer.utilityPane.action.type.launchAction.label"); - } - - /** - * Sets the current annotation component. The current annotation component - * is used to build the associated action list and of which all action - * edits act on. - * - * @param annotation current action, should not be null. - */ - public void setAnnotationComponent(AnnotationComponent annotation) { - - currentAnnotationComponent = annotation; - - // remove previous old annotations - actionListModel.clear(); - - // get annotations from action - if (annotation.getAnnotation() != null && - annotation.getAnnotation().getAction() != null) { - addActionToList(annotation.getAnnotation().getAction()); - // select first item in list. - if (actionListModel.size() > 0) { - actionList.setSelectedIndex(0); - } - } - // check to see if the link annotation "dest" key is present. as - // we'll edit this field with the goToAction dialog - else if (annotation.getAnnotation() != null && - annotation.getAnnotation() instanceof LinkAnnotation) { - LinkAnnotation linkAnnotaiton = (LinkAnnotation) - annotation.getAnnotation(); - if (linkAnnotaiton.getDestination() != null) { - actionListModel.addElement(new ActionEntry(destinationLabel, null)); - } - } - // refresh add/edit/remove buttons. - refreshActionCrud(); - } - - /** - * Handlers for add, edit and delete commands. - * - * @param e awt action event - */ - public void actionPerformed(ActionEvent e) { - Object source = e.getSource(); - - if (currentAnnotationComponent == null) { - logger.warning("No annotation was selected, edit is not possible."); - return; - } - - if (source == addAction) { - // does all dialog work for adding new action. - addAction(); - } else if (source == editAction) { - // show the correct panel for the selected annotation - editAction(); - } else if (source == removeAction) { - // confirmation dialog - int option = JOptionPane.showConfirmDialog(controller.getViewerFrame(), - messageBundle.getString("viewer.utilityPane.action.dialog.delete.msgs"), - messageBundle.getString("viewer.utilityPane.action.dialog.delete.title"), - JOptionPane.YES_NO_OPTION); - // delete command. - if (JOptionPane.YES_OPTION == option) { - // start the delete process. - removeAction(); - } - // refresh button states - refreshActionCrud(); - } - updateCurrentAnnotation(); - } - - /** - * Changes events that occur when a user selects an annotation's action in - * the list actionList. - * - * @param e awt list event. - */ - public void valueChanged(ListSelectionEvent e) { - if (!e.getValueIsAdjusting()) { - if (actionList.getSelectedIndex() == -1) { - //No selection, disable fire button. - addAction.setEnabled(false); - editAction.setEnabled(false); - removeAction.setEnabled(false); - } else { - // we only can add one action to an annotation for now. - refreshActionCrud(); - } - } - } - - /** - * Shows new action selection dialog and then the appropriate action type - * dialog for creating/adding new actions to the current annotation. - */ - private void addAction() { - // show new action select dialog to select annotation type - // and ultimately the dialog edit panels. - Object[] possibilities = { - new ActionChoice( - messageBundle.getString( - "viewer.utilityPane.action.type.goToAction.label"), - ActionFactory.GOTO_ACTION), - new ActionChoice( - messageBundle.getString( - "viewer.utilityPane.action.type.launchAction.label"), - ActionFactory.LAUNCH_ACTION), - new ActionChoice( - messageBundle.getString( - "viewer.utilityPane.action.type.uriAction.label"), - ActionFactory.URI_ACTION)}; - ActionChoice actionType = (ActionChoice) JOptionPane.showInputDialog( - controller.getViewerFrame(), - messageBundle.getString("viewer.utilityPane.action.dialog.new.msgs"), - messageBundle.getString("viewer.utilityPane.action.dialog.new.title"), - JOptionPane.PLAIN_MESSAGE, null, - possibilities, null); - // create and show a new GOTO action - if (actionType != null && - actionType.getActionType() == ActionFactory.GOTO_ACTION) { - // create new instance of dialog if it hasn't been created. - showGoToActionDialog(); - } - // create and show a new URI action - else if (actionType != null && - actionType.getActionType() == ActionFactory.URI_ACTION) { - // show URI dialog - String uriString = showURIActionDialog(null); - // finally do all the lifting for adding a new action for the - // current action - if (uriString != null && currentAnnotationComponent != null) { - // create a new instance of the action type - org.icepdf.core.pobjects.actions.URIAction uriAction = (URIAction) - ActionFactory.buildAction( - currentAnnotationComponent.getAnnotation().getLibrary(), - ActionFactory.URI_ACTION); - // get action and add the new action - uriAction.setURI(uriString); - currentAnnotationComponent.getAnnotation().addAction(uriAction); - // add the new action to the list. - actionListModel.addElement(new ActionEntry( - messageBundle.getString( - "viewer.utilityPane.action.type.uriAction.label"), - uriAction)); - } - } - // create and show a new launch action - else if (actionType != null && - actionType.getActionType() == ActionFactory.LAUNCH_ACTION) { - // show URI dialog - String fileString = showLaunchActionDialog(null); - // finally do all the lifting for adding a new action for the - // current action - if (fileString != null && currentAnnotationComponent != null) { - // create a new instance of the action type - LaunchAction launchAction = (LaunchAction) - ActionFactory.buildAction( - currentAnnotationComponent.getAnnotation().getLibrary(), - ActionFactory.LAUNCH_ACTION); - // get action and add the new action - launchAction.setExternalFile(fileString); - currentAnnotationComponent.getAnnotation().addAction(launchAction); - // add the new action to the list. - actionListModel.addElement(new ActionEntry( - messageBundle.getString( - "viewer.utilityPane.action.type.launchAction.label"), - launchAction)); - } - } - } - - /** - * Shows the appropriate action type edit dialog. - */ - private void editAction() { - ActionEntry actionEntry = (ActionEntry) actionListModel.getElementAt( - actionList.getSelectedIndex()); - org.icepdf.core.pobjects.actions.Action action = - actionEntry.getAction(); - // show URI edit pane - if (action instanceof URIAction) { - URIAction uriAction = (URIAction) action; - String oldURIValue = uriAction.getURI(); - String newURIValue = showURIActionDialog(oldURIValue); - // finally do all the lifting to edit a uri change. - if (newURIValue != null && - !oldURIValue.equals(newURIValue)) { - // create a new instance of the action type - uriAction.setURI(newURIValue); - currentAnnotationComponent.getAnnotation().updateAction(uriAction); - } - } - // show goto dialog for goToAction or link annotation dest - else if (action instanceof GoToAction || action == null) { - // goToAction dialog handles the save action processing - showGoToActionDialog(); - } - // show URI edit pane - if (action instanceof LaunchAction) { - LaunchAction launchAction = (LaunchAction) action; - String oldLaunchValue = launchAction.getExternalFile(); - String newLaunchValue = showLaunchActionDialog(oldLaunchValue); - // finally do all the lifting to edit a launch change. - if (newLaunchValue != null && - !oldLaunchValue.equals(newLaunchValue)) { - // create a new instance of the action type - launchAction.setExternalFile(newLaunchValue); - currentAnnotationComponent.getAnnotation().updateAction(launchAction); - } - } - } - - /** - * Shows a confirmation dialog and if confirmed the action will be removed - * from the current annotation. - */ - private void removeAction() { - ActionEntry actionEntry = (ActionEntry) actionListModel.getElementAt( - actionList.getSelectedIndex()); - org.icepdf.core.pobjects.actions.Action action = - actionEntry.getAction(); - if (action != null) { - boolean success = - currentAnnotationComponent.getAnnotation().deleteAction(action); - if (success) { - actionListModel.removeElementAt(actionList.getSelectedIndex()); - actionList.setSelectedIndex(-1); - } - } - // we must have a destination and will try and delete it. - else if (currentAnnotationComponent.getAnnotation() instanceof LinkAnnotation) { - LinkAnnotation linkAnnotation = (LinkAnnotation) - currentAnnotationComponent.getAnnotation(); - // remove the dest key and save the action, currently we don't - // use the annotationState object to reflect his change. - linkAnnotation.getEntries().remove(LinkAnnotation.DESTINATION_KEY); - updateCurrentAnnotation(); - // update the list - actionListModel.removeElementAt(actionList.getSelectedIndex()); - actionList.setSelectedIndex(-1); - } - } - - /** - * Utility to show the URIAction dialog for add and edits. - * - * @param oldURIValue default value to show in dialog text field. - * @return new values typed by user. - */ - private String showURIActionDialog(String oldURIValue) { - return (String) JOptionPane.showInputDialog( - controller.getViewerFrame(), - messageBundle.getString( - "viewer.utilityPane.action.dialog.uri.msgs"), - messageBundle.getString( - "viewer.utilityPane.action.dialog.uri.title"), - JOptionPane.PLAIN_MESSAGE, null, null, - oldURIValue); - } - - /** - * Utility to show the LaunchAction dialog for add and edits. - * - * @param oldLaunchValue default value to show in dialog text field. - * @return new values typed by user. - */ - private String showLaunchActionDialog(String oldLaunchValue) { - return (String) JOptionPane.showInputDialog( - controller.getViewerFrame(), - messageBundle.getString( - "viewer.utilityPane.action.dialog.launch.msgs"), - messageBundle.getString( - "viewer.utilityPane.action.dialog.launch.title"), - JOptionPane.PLAIN_MESSAGE, null, null, - oldLaunchValue); - } - - - private void showGoToActionDialog() { - // create new instance of dialog if it hasn't been created. - if (goToActionDialog != null) { - goToActionDialog.dispose(); - } - goToActionDialog = new GoToActionDialog(controller, this); - // set the new annotation - goToActionDialog.setAnnotationComponent(currentAnnotationComponent); - // make it visible. - goToActionDialog.setVisible(true); - } - - /** - * Refreshes add,edit and remove button state based on the number of actions - * currently in the action list. - */ - private void refreshActionCrud() { - // we only can add one action to an annotation for now. - addAction.setEnabled(actionListModel.getSize() == 0); - editAction.setEnabled(actionListModel.getSize() > 0); - removeAction.setEnabled(actionListModel.getSize() > 0); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - // apply to child components. - actionList.setEnabled(enabled); - actionList.setSelectedIndex(-1); - // only enable if there is a selected index. - boolean isSelectedIndex = actionList.getSelectedIndex() != -1; - addAction.setEnabled(enabled && actionListModel.getSize() == 0); - editAction.setEnabled(enabled && isSelectedIndex); - removeAction.setEnabled(enabled && isSelectedIndex); - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - - // border for container. - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.action.selectionTitle"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - - // create the new list - actionListModel = new DefaultListModel(); - actionList = new JList(actionListModel); - actionList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); - actionList.setVisibleRowCount(-1); - actionList.addListSelectionListener(this); - JScrollPane listScroller = new JScrollPane(actionList); - listScroller.setPreferredSize(new Dimension(150, 50)); - add(listScroller); - - // create action manipulator buttons. - addAction = new JButton(messageBundle.getString( - "viewer.utilityPane.action.addAction")); - addAction.setEnabled(false); - addAction.addActionListener(this); - editAction = new JButton(messageBundle.getString( - "viewer.utilityPane.action.editAction")); - editAction.setEnabled(false); - editAction.addActionListener(this); - removeAction = new JButton(messageBundle.getString( - "viewer.utilityPane.action.removeAction")); - removeAction.setEnabled(false); - removeAction.addActionListener(this); - // panel for buttons - JPanel buttonPanel = new JPanel(new FlowLayout()); - buttonPanel.add(addAction); - buttonPanel.add(editAction); - buttonPanel.add(removeAction); - add(buttonPanel); - - revalidate(); - } - - /** - * Clear the action list of all action items. - */ - public void clearActionList() { - actionListModel.clear(); - } - - /** - * Add an action to the list. - * - * @param action action object to add. - */ - public void addActionToList(org.icepdf.core.pobjects.actions.Action action) { - if (action instanceof GoToAction) { - actionListModel.addElement(new ActionEntry(goToActionLabel, action)); - } else if (action instanceof URIAction) { - actionListModel.addElement(new ActionEntry(uriActionLabel, action)); - } else if (action instanceof LaunchAction) { - actionListModel.addElement(new ActionEntry(launchActionLabel, action)); - } - // todo check for an next entry - // todo add a "none" entry - } - - /** - * Action entries used with the actionList component. - */ - class ActionEntry { - - // The text to be displayed on the screen for this item. - String title; - - // The destination to be displayed when this item is activated - org.icepdf.core.pobjects.actions.Action action; - - /** - * Creates a new instance of a FindEntry. - * - * @param title of found entry - */ - ActionEntry(String title) { - super(); - this.title = title; - } - - ActionEntry(String title, org.icepdf.core.pobjects.actions.Action action) { - this.action = action; - this.title = title; - } - - org.icepdf.core.pobjects.actions.Action getAction() { - return action; - } - - public String toString() { - return title; - } - } - - /** - * An Entry objects for the different action types, used in dialog - * for creating/adding new actions. - */ - class ActionChoice { - - // The text to be displayed on the screen for this item. - String title; - - // The destination to be displayed when this item is activated - int actionType; - - - ActionChoice(String title, int actionType) { - super(); - this.actionType = actionType; - this.title = title; - } - - int getActionType() { - return actionType; - } - - public String toString() { - return title; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationDialogAdapter.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationDialogAdapter.java deleted file mode 100644 index 81b30b6e54..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationDialogAdapter.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.ri.common.EscapeJDialog; - -import javax.swing.*; -import java.awt.*; - -/** - * Common abstract class for all annotation dialogs. - * - * @since 4.0 - */ -public abstract class AnnotationDialogAdapter extends EscapeJDialog - implements AnnotationProperties { - - protected AnnotationDialogAdapter(JFrame owner, boolean modal) - throws HeadlessException { - super(owner, modal); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationPanel.java deleted file mode 100644 index 8c6f4be4bd..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationPanel.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.annotations.*; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; -import org.icepdf.ri.common.views.annotations.PopupAnnotationComponent; -import org.icepdf.ri.util.PropertiesManager; - -import javax.swing.*; -import java.awt.*; - -/** - * Annotation Panel is responsible for viewing and editing Annotation properties - * which also include annotation action properties. - *

      - * Currently only Link Annotation are supported and the Action types GoTo and - * URI. It will be quite easy to add more properties in the future given the - * factory nature of this class - */ -@SuppressWarnings("serial") -public class AnnotationPanel extends AnnotationPanelAdapter { - - private PropertiesManager propertiesManager; - - private JPanel annotationPanel; - private AnnotationPanelAdapter annotationPropertyPanel; - private ActionsPanel actionsPanel; - private BorderPanel borderPanel; - private FlagsPanel flagsPanel; - - public AnnotationPanel(SwingController controller) { - this(controller, null); - } - - public AnnotationPanel(SwingController controller, PropertiesManager propertiesManager) { - super(controller); - setLayout(new BorderLayout()); - this.propertiesManager = propertiesManager; - - // Setup the basics of the panel - setFocusable(true); - - // setup the action view with default UI components. - setGUI(); - - // Start the panel disabled until an action is clicked - this.setEnabled(false); - } - - public void setAnnotationUtilityToolbar(JToolBar annotationUtilityToolbar) { - addGB(annotationPanel, annotationUtilityToolbar, 0, 0, 1, 1); - } - - public AnnotationPanelAdapter buildAnnotationPropertyPanel(AnnotationComponent annotationComp) { - if (annotationComp != null) { - // check action type - Annotation annotation = annotationComp.getAnnotation(); - if (annotation != null && annotation instanceof LinkAnnotation) { - return new LinkAnnotationPanel(controller); - } else if (annotation != null && annotation instanceof TextMarkupAnnotation) { - return new TextMarkupAnnotationPanel(controller); - } else if (annotation != null && annotation instanceof LineAnnotation) { - return new LineAnnotationPanel(controller); - } else if (annotation != null && annotation instanceof SquareAnnotation) { - return new SquareAnnotationPanel(controller); - } else if (annotation != null && annotation instanceof CircleAnnotation) { - return new CircleAnnotationPanel(controller); - } else if (annotation != null && annotation instanceof InkAnnotation) { - return new InkAnnotationPanel(controller); - } else if (annotation != null && annotation instanceof TextAnnotation) { - return new TextAnnotationPanel(controller); - } else if (annotation != null && annotation instanceof FreeTextAnnotation) { - return new FreeTextAnnotationPanel(controller); - } - } - return null; - } - - /** - * Sets the current annotation component to edit, building the appropriate - * annotation panel and action panel. If the annotation is null default - * panels are created. - * - * @param annotation annotation properties to show in UI, can be null; - */ - public void setAnnotationComponent(AnnotationComponent annotation) { - - // remove and add the action panel for action type. - if (annotationPropertyPanel != null) { - annotationPanel.remove(annotationPropertyPanel); - } - annotationPropertyPanel = buildAnnotationPropertyPanel(annotation); - if (annotationPropertyPanel != null) { - annotationPropertyPanel.setAnnotationComponent(annotation); - addGB(annotationPanel, annotationPropertyPanel, 0, 1, 1, 1); - } - - // add the new action - actionsPanel.setAnnotationComponent(annotation); - // check if flags should be shown. - if (flagsPanel != null) { - flagsPanel.setAnnotationComponent(annotation); - } - borderPanel.setAnnotationComponent(annotation); - - // hide border panel for line components - if (annotationPropertyPanel instanceof LineAnnotationPanel || - annotationPropertyPanel instanceof SquareAnnotationPanel || - annotationPropertyPanel instanceof CircleAnnotationPanel || - annotationPropertyPanel instanceof InkAnnotationPanel || - annotationPropertyPanel instanceof FreeTextAnnotationPanel || - annotation instanceof PopupAnnotationComponent) { - borderPanel.setVisible(false); - } else { - borderPanel.setVisible(true); - } - - // hide actions panel for the popup annotation - if (annotation instanceof PopupAnnotationComponent) { - actionsPanel.setVisible(false); - flagsPanel.setVisible(false); - } else { - actionsPanel.setVisible(true); - flagsPanel.setVisible(true); - } - - // disable the component if the annotation is readonly. - if (!annotation.isEditable()) { - setEnabled(annotation.isEditable()); - } - - revalidate(); - } - - private void setGUI() { - annotationPanel = new JPanel(new GridBagLayout()); - add(annotationPanel, BorderLayout.NORTH); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(5, 1, 5, 1); - - // add everything back again. - annotationPropertyPanel = buildAnnotationPropertyPanel(null); - actionsPanel = new ActionsPanel(controller); - borderPanel = new BorderPanel(controller); - - if (propertiesManager == null || - PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_UTILITYPANE_ANNOTATION_FLAGS)) { - flagsPanel = new FlagsPanel(controller); - } - - // panels to add. - if (annotationPropertyPanel != null) { - addGB(annotationPanel, annotationPropertyPanel, 0, 1, 1, 1); - } - addGB(annotationPanel, borderPanel, 0, 2, 1, 1); - if (flagsPanel != null) { - addGB(annotationPanel, flagsPanel, 0, 3, 1, 1); - } - addGB(annotationPanel, actionsPanel, 0, 4, 1, 1); - - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - // apply to child components. - if (annotationPropertyPanel != null && actionsPanel != null) { - annotationPropertyPanel.setEnabled(enabled); - actionsPanel.setEnabled(enabled); - flagsPanel.setEnabled(enabled); - borderPanel.setEnabled(enabled); - } - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationPanelAdapter.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationPanelAdapter.java deleted file mode 100644 index bac59d9aff..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationPanelAdapter.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.annotations.BorderStyle; -import org.icepdf.core.pobjects.annotations.MarkupAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; -import org.icepdf.ri.common.views.DocumentViewController; - -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import java.awt.*; -import java.util.ResourceBundle; - -/** - * All annotation and action property panels have a common method for - * assigning the current annotation component. - * - * @since 4.0 - */ -public abstract class AnnotationPanelAdapter extends JPanel - implements AnnotationProperties { - - // layouts constraint - protected GridBagConstraints constraints; - - // action instance that is being edited - protected AnnotationComponent currentAnnotationComponent; - protected DocumentViewController documentViewController; - - protected SwingController controller; - protected ResourceBundle messageBundle; - - // border styles types. - protected static ValueLabelItem[] VISIBLE_TYPE_LIST; - protected static ValueLabelItem[] LINE_THICKNESS_LIST; - // line styles. - protected static ValueLabelItem[] LINE_STYLE_LIST; - - protected static final int TRANSPARENCY_MIN = 0; - protected static final int TRANSPARENCY_MAX = 255; - protected static final int TRANSPARENCY_INIT = 255; - - protected AnnotationPanelAdapter( - SwingController controller) { - setDoubleBuffered(true); - this.controller = controller; - this.documentViewController = controller.getDocumentViewController(); - this.messageBundle = controller.getMessageBundle(); - - // common selection lists. - // line thicknesses. - if (LINE_THICKNESS_LIST == null) { - LINE_THICKNESS_LIST = new ValueLabelItem[]{ - new ValueLabelItem(1f, - messageBundle.getString("viewer.common.number.one")), - new ValueLabelItem(2f, - messageBundle.getString("viewer.common.number.two")), - new ValueLabelItem(3f, - messageBundle.getString("viewer.common.number.three")), - new ValueLabelItem(4f, - messageBundle.getString("viewer.common.number.four")), - new ValueLabelItem(5f, - messageBundle.getString("viewer.common.number.five")), - new ValueLabelItem(10f, - messageBundle.getString("viewer.common.number.ten")), - new ValueLabelItem(15f, - messageBundle.getString("viewer.common.number.fifteen"))}; - } - // setup the menu - if (VISIBLE_TYPE_LIST == null) { - VISIBLE_TYPE_LIST = new ValueLabelItem[]{ - new ValueLabelItem(true, - messageBundle.getString("viewer.utilityPane.annotation.border.borderType.visibleRectangle")), - new ValueLabelItem(false, - messageBundle.getString("viewer.utilityPane.annotation.border.borderType.invisibleRectangle"))}; - } - if (LINE_STYLE_LIST == null) { - LINE_STYLE_LIST = new ValueLabelItem[]{ - new ValueLabelItem(BorderStyle.BORDER_STYLE_SOLID, - messageBundle.getString("viewer.utilityPane.annotation.border.solid")), - new ValueLabelItem(BorderStyle.BORDER_STYLE_DASHED, - messageBundle.getString("viewer.utilityPane.annotation.border.dashed"))}; - } - } - - /** - * Utility to update the action annotation when changes have been made to - * 'Dest' which has the same notation as 'GoTo'. It's the pre action way - * of doing things and is still very common of link Annotations. . - */ - protected void updateCurrentAnnotation() { - - if (documentViewController.getAnnotationCallback() != null) { - documentViewController.getAnnotationCallback() - .updateAnnotation(currentAnnotationComponent); - } - } - - /** - * Utility to build the transparency bar slider for changing a markup annotations stroking and non-stroking - * alpha values (/CA, /ca). - * - * @return new instance of a jSlider ranging from TRANSPARENCY_MIN to TRANSPARENCY_MAX. - */ - protected JSlider buildAlphaSlider() { - return new JSlider(JSlider.HORIZONTAL, - TRANSPARENCY_MIN, TRANSPARENCY_MAX, TRANSPARENCY_INIT); - } - - /** - * Handler for the alpha value update for an annotation's opacity updated. - * @param e change event. - * @param annotation annotation to apply the opacity value to. - */ - protected void alphaSliderChange(ChangeEvent e, MarkupAnnotation annotation){ - JSlider source = (JSlider)e.getSource(); - int alpha = source.getValue(); - if (!source.getValueIsAdjusting() && alpha != annotation.getOpacityNormalized()) { - // set the annotation value - annotation.setOpacity(alpha); - // send update to callback - updateCurrentAnnotation(); - // reset the appearance stream. - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - - /** - * Set the background colour of the various buttons that are used to show the colour picker as well as show - * the selected colour. - * @param button button to set colour of. - * @param color color ot set the buttons background. - */ - protected void setButtonBackgroundColor(JButton button, Color color){ - if (color != null) { - if (color.getAlpha() < 255) { - color = new Color(color.getRGB()); - } - button.setBackground(color); - button.setContentAreaFilled(false); - button.setOpaque(true); - } - } - - /** - * Gridbag constructor helper - * - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan - * @param colSpan - */ - protected void addGB(JPanel layout, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - layout.add(component, constraints); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationProperties.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationProperties.java deleted file mode 100644 index aa923d2bbd..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/AnnotationProperties.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.ri.common.views.AnnotationComponent; - -/** - * @since 4.0 - */ -public interface AnnotationProperties { - - public abstract void setAnnotationComponent(AnnotationComponent annotation); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/BorderPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/BorderPanel.java deleted file mode 100644 index 4e31eeb553..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/BorderPanel.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.BorderStyle; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * BorderPanel allows the configuration of an annotation's BorderStyle properties. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class BorderPanel extends AnnotationPanelAdapter implements ItemListener, - ActionListener { - - // default list values. - private static final int DEFAULT_LINK_TYPE = 1; - private static final int DEFAULT_LINE_THICKNESS = 0; - private static final int DEFAULT_LINE_STYLE = 0; - private static final Color DEFAULT_BORDER_COLOR = Color.BLACK; - - // line styles. - private static ValueLabelItem[] LINE_STYLE_LIST; - - // link action appearance properties. - private JComboBox linkTypeBox; - private JComboBox lineThicknessBox; - private JComboBox lineStyleBox; - private JButton colorButton; - - public BorderPanel(SwingController controller) { - super(controller); - setLayout(new GridLayout(4, 2, 5, 2)); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - /** - * Method that should be called when a new AnnotationComponent is selected by the user - * The associated object will be stored locally as currentAnnotation - * Then all of it's properties will be applied to the UI pane - * For example if the border was red, the color of the background button will - * be changed to red - * - * @param newAnnotation to set and apply to this UI - */ - public void setAnnotationComponent(AnnotationComponent newAnnotation) { - - if (newAnnotation == null || newAnnotation.getAnnotation() == null) { - setEnabled(false); - return; - } - // assign the new action instance. - this.currentAnnotationComponent = newAnnotation; - - // For convenience grab the Annotation object wrapped by the component - Annotation annotation = currentAnnotationComponent.getAnnotation(); - - // apply annotation values. - if (annotation.getLineThickness() == 0) { - applySelectedValue(linkTypeBox, Annotation.INVISIBLE_RECTANGLE); - } else { - applySelectedValue(linkTypeBox, Annotation.VISIBLE_RECTANGLE); - } - applySelectedValue(lineThicknessBox, annotation.getLineThickness()); - applySelectedValue(lineStyleBox, annotation.getLineStyle()); - setButtonBackgroundColor(colorButton, annotation.getColor()); - - // disable appearance input if we have a invisible rectangle - enableAppearanceInputComponents(annotation.getBorderType() == Annotation.VISIBLE_RECTANGLE); - } - - public void itemStateChanged(ItemEvent e) { - - // For convenience grab the Annotation object wrapped by the component - Annotation annotation = currentAnnotationComponent.getAnnotation(); - - ValueLabelItem item = (ValueLabelItem) e.getItem(); - if (e.getStateChange() == ItemEvent.SELECTED) { - if (e.getSource() == linkTypeBox) { - boolean linkVisible = (Boolean) item.getValue(); - if (linkVisible) { - annotation.getBorderStyle().setStrokeWidth(1f); - // on visible set a default colour so we can see it. - if (annotation.getColor() == null) { - annotation.setColor(Color.BLACK); - } - } else { - annotation.getBorderStyle().setStrokeWidth(0f); - } - applySelectedValue(lineThicknessBox, annotation.getLineThickness()); - // enable/disable fields based on types - enableAppearanceInputComponents(linkVisible); - } else if (e.getSource() == lineThicknessBox) { - float lineThickness = (Float) item.getValue(); - annotation.getBorderStyle().setStrokeWidth(lineThickness); - } else if (e.getSource() == lineStyleBox) { - Name lineStyle = (Name) item.getValue(); - annotation.getBorderStyle().setBorderStyle(lineStyle); - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - - currentAnnotationComponent.repaint(); - } - } - - public void actionPerformed(ActionEvent e) { - // For convenience grab the Annotation object wrapped by the component - Annotation annotation = currentAnnotationComponent.getAnnotation(); - if (e.getSource() == colorButton) { - Color chosenColor = - JColorChooser.showDialog(colorButton, - messageBundle.getString("viewer.utilityPane.annotation.border.colorChooserTitle"), - colorButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - colorButton.setBackground(chosenColor); - annotation.setColor(chosenColor); - - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.repaint(); - } - } - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - - // line styles. - if (LINE_STYLE_LIST == null) { - LINE_STYLE_LIST = new ValueLabelItem[]{ - new ValueLabelItem(BorderStyle.BORDER_STYLE_SOLID, - messageBundle.getString("viewer.utilityPane.annotation.border.solid")), - new ValueLabelItem(BorderStyle.BORDER_STYLE_DASHED, - messageBundle.getString("viewer.utilityPane.annotation.border.dashed")), - new ValueLabelItem(BorderStyle.BORDER_STYLE_BEVELED, - messageBundle.getString("viewer.utilityPane.annotation.border.beveled")), - new ValueLabelItem(BorderStyle.BORDER_STYLE_INSET, - messageBundle.getString("viewer.utilityPane.annotation.border.inset")), - new ValueLabelItem(BorderStyle.BORDER_STYLE_UNDERLINE, - messageBundle.getString("viewer.utilityPane.annotation.border.underline"))}; - } - // Create and setup an Appearance panel - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.border.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - // border type box - linkTypeBox = new JComboBox(VISIBLE_TYPE_LIST); - linkTypeBox.setSelectedIndex(DEFAULT_LINK_TYPE); - linkTypeBox.addItemListener(this); - add(new JLabel( - messageBundle.getString("viewer.utilityPane.annotation.border.linkType"))); - add(linkTypeBox); - // border thickness - lineThicknessBox = new JComboBox(LINE_THICKNESS_LIST); - lineThicknessBox.setSelectedIndex(DEFAULT_LINE_THICKNESS); - lineThicknessBox.addItemListener(this); - add(new JLabel(messageBundle.getString( - "viewer.utilityPane.annotation.border.lineThickness"))); - add(lineThicknessBox); - // border style - lineStyleBox = new JComboBox(LINE_STYLE_LIST); - lineStyleBox.setSelectedIndex(DEFAULT_LINE_STYLE); - lineStyleBox.addItemListener(this); - add(new JLabel( - messageBundle.getString("viewer.utilityPane.annotation.border.lineStyle"))); - add(lineStyleBox); - // border colour - colorButton = new JButton(" "); - colorButton.addActionListener(this); - colorButton.setOpaque(true); - colorButton.setBackground(DEFAULT_BORDER_COLOR); - add(new JLabel( - messageBundle.getString("viewer.utilityPane.annotation.border.colorLabel"))); - add(colorButton); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - - safeEnable(linkTypeBox, enabled); - safeEnable(lineThicknessBox, enabled); - safeEnable(lineStyleBox, enabled); - safeEnable(colorButton, enabled); - } - - /** - * Method to enable appearance input fields for an invisible rectangle - * - * @param visible invisible rectangle or visible, your pick. - */ - private void enableAppearanceInputComponents(boolean visible) { - if (!visible) { - // everything but highlight style and link type - safeEnable(linkTypeBox, true); - safeEnable(lineThicknessBox, false); - safeEnable(lineStyleBox, false); - safeEnable(colorButton, false); - } else { - // enable all fields. - safeEnable(linkTypeBox, true); - safeEnable(lineThicknessBox, true); - safeEnable(lineStyleBox, true); - safeEnable(colorButton, true); - } - } - - /** - * Convenience method to ensure a component is safe to toggle the enabled state on - * - * @param comp to toggle - * @param enabled the status to use - * @return true on success - */ - protected boolean safeEnable(JComponent comp, boolean enabled) { - if (comp != null) { - comp.setEnabled(enabled); - return true; - } - return false; - } - - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/CircleAnnotationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/CircleAnnotationPanel.java deleted file mode 100644 index 9d0be6967b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/CircleAnnotationPanel.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.CircleAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * CircleAnnotationPanel is a configuration panel for changing the properties - * of a CircleAnnotationComponent and the underlying annotation component. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class CircleAnnotationPanel extends AnnotationPanelAdapter implements ItemListener, ChangeListener, - ActionListener { - - // default list values. - private static final int DEFAULT_LINE_THICKNESS = 0; - private static final int DEFAULT_LINE_STYLE = 0; - private static final int DEFAULT_STROKE_TYPE = 0; - private static final Color DEFAULT_BORDER_COLOR = Color.RED; - private static final int DEFAULT_FILL_TYPE = 1; - private static final Color DEFAULT_INTERIOR_COLOR = new Color(1, 1, 1); - - // link action appearance properties. - private JComboBox lineThicknessBox; - private JComboBox lineStyleBox; - private JComboBox fillTypeBox; - private JButton colorFillButton; - private JButton colorBorderButton; - private JSlider transparencySlider; - - private CircleAnnotation annotation; - - public CircleAnnotationPanel(SwingController controller) { - super(controller); - - setLayout(new GridBagLayout()); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - - /** - * Method that should be called when a new AnnotationComponent is selected by the user - * The associated object will be stored locally as currentAnnotation - * Then all of it's properties will be applied to the UI pane - * For example if the border was red, the color of the background button will - * be changed to red - * - * @param newAnnotation to set and apply to this UI - */ - public void setAnnotationComponent(AnnotationComponent newAnnotation) { - - if (newAnnotation == null || newAnnotation.getAnnotation() == null) { - setEnabled(false); - return; - } - // assign the new action instance. - this.currentAnnotationComponent = newAnnotation; - - // For convenience grab the Annotation object wrapped by the component - annotation = (CircleAnnotation) - currentAnnotationComponent.getAnnotation(); - - applySelectedValue(lineThicknessBox, annotation.getLineThickness()); - applySelectedValue(lineStyleBox, annotation.getLineStyle()); - applySelectedValue(fillTypeBox, annotation.isFillColor()); - setButtonBackgroundColor(colorBorderButton, annotation.getColor()); - setButtonBackgroundColor(colorFillButton, annotation.getFillColor()); - transparencySlider.setValue(Math.round(annotation.getOpacity() * 255)); - - // disable appearance input if we have a invisible rectangle - safeEnable(lineThicknessBox, true); - safeEnable(lineStyleBox, true); - safeEnable(colorFillButton, true); - safeEnable(fillTypeBox, true); - safeEnable(colorBorderButton, true); - safeEnable(transparencySlider, true); - - setStrokeFillColorButtons(); - } - - private void setStrokeFillColorButtons() { - CircleAnnotation circleAnnotation = (CircleAnnotation) - currentAnnotationComponent.getAnnotation(); - if (annotation.isFillColor()) { - setButtonBackgroundColor(colorFillButton, circleAnnotation.getFillColor()); - safeEnable(colorFillButton, true); - } else { - safeEnable(colorFillButton, false); - } - } - - public void itemStateChanged(ItemEvent e) { - ValueLabelItem item = (ValueLabelItem) e.getItem(); - if (e.getStateChange() == ItemEvent.SELECTED) { - if (e.getSource() == lineThicknessBox) { - annotation.getBorderStyle().setStrokeWidth((Float) item.getValue()); - } else if (e.getSource() == lineStyleBox) { - annotation.getBorderStyle().setBorderStyle((Name) item.getValue()); - } else if (e.getSource() == fillTypeBox) { - annotation.setFillColor((Boolean) item.getValue()); - setStrokeFillColorButtons(); - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == colorBorderButton) { - Color chosenColor = - JColorChooser.showDialog(colorBorderButton, - messageBundle.getString( - "viewer.utilityPane.annotation.circle.colorBorderChooserTitle"), - colorBorderButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - setButtonBackgroundColor(colorBorderButton, chosenColor); - annotation.setColor(chosenColor); - } - } else if (e.getSource() == colorFillButton) { - Color chosenColor = - JColorChooser.showDialog(colorFillButton, - messageBundle.getString( - "viewer.utilityPane.annotation.circle.colorInteriorChooserTitle"), - colorFillButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - setButtonBackgroundColor(colorFillButton, chosenColor); - annotation.setFillColor(chosenColor); - } - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - - public void stateChanged(ChangeEvent e) { - alphaSliderChange(e, annotation); - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - - // Create and setup an Appearance panel - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.circle.appearance.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(1, 2, 1, 2); - - // Line thickness - lineThicknessBox = new JComboBox(LINE_THICKNESS_LIST); - lineThicknessBox.setSelectedIndex(DEFAULT_LINE_THICKNESS); - lineThicknessBox.addItemListener(this); - JLabel label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.circle.lineThickness")); - addGB(this, label, 0, 0, 1, 1); - addGB(this, lineThicknessBox, 1, 0, 1, 1); - - // Line style - lineStyleBox = new JComboBox(LINE_STYLE_LIST); - lineStyleBox.setSelectedIndex(DEFAULT_LINE_STYLE); - lineStyleBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.circle.lineStyle")); - addGB(this, label, 0, 1, 1, 1); - addGB(this, lineStyleBox, 1, 1, 1, 1); - - // border colour - colorBorderButton = new JButton(" "); - colorBorderButton.addActionListener(this); - colorBorderButton.setOpaque(true); - colorBorderButton.setBackground(DEFAULT_BORDER_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.circle.colorBorderLabel")); - addGB(this, label, 0, 2, 1, 1); - addGB(this, colorBorderButton, 1, 2, 1, 1); - - // fill type options - fillTypeBox = new JComboBox(VISIBLE_TYPE_LIST); - fillTypeBox.setSelectedIndex(DEFAULT_FILL_TYPE); - fillTypeBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.circle.fillTypeLabel")); - addGB(this, label, 0, 3, 1, 1); - addGB(this, fillTypeBox, 1, 3, 1, 1); - - // interior colour - colorFillButton = new JButton(" "); - colorFillButton.addActionListener(this); - colorFillButton.setOpaque(true); - colorFillButton.setBackground(DEFAULT_INTERIOR_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.circle.colorInteriorLabel")); - addGB(this, label, 0, 4, 1, 1); - addGB(this, colorFillButton, 1, 4, 1, 1); - - // transparency slider - transparencySlider = buildAlphaSlider(); - transparencySlider.setMajorTickSpacing(255); - transparencySlider.setPaintLabels(true); - transparencySlider.addChangeListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.circle.transparencyLabel")); - addGB(this, label, 0, 5, 1, 1); - addGB(this, transparencySlider, 1, 5, 1, 1); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - - safeEnable(lineThicknessBox, enabled); - safeEnable(lineStyleBox, enabled); - safeEnable(fillTypeBox, enabled); - safeEnable(colorBorderButton, enabled); - safeEnable(colorFillButton, enabled); - safeEnable(transparencySlider, enabled); - } - - /** - * Convenience method to ensure a component is safe to toggle the enabled state on - * - * @param comp to toggle - * @param enabled the status to use - * @return true on success - */ - protected boolean safeEnable(JComponent comp, boolean enabled) { - if (comp != null) { - comp.setEnabled(enabled); - return true; - } - return false; - } - - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/FlagsPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/FlagsPanel.java deleted file mode 100644 index 702c8269aa..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/FlagsPanel.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import java.awt.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * The flags panel allows a user to set common properties of an annotation like - * readonly, no roate, no zoom and printable. This panel can be removed from - * the viewer ri with the - * PropertiesManager.PROPERTY_SHOW_UTILITYPANE_ANNOTATION_FLAGS=false. - * - * @since 5.0.4 - */ -@SuppressWarnings("serial") -public class FlagsPanel extends AnnotationPanelAdapter implements ItemListener { - - private JComboBox readOnlyComboBox; - private JComboBox noRotateComboBox; - private JComboBox noZoomComboBox; - private JComboBox printableComboBox; - - public FlagsPanel(SwingController controller) { - super(controller); - setLayout(new GridLayout(4, 2, 5, 2)); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - public void setAnnotationComponent(AnnotationComponent annotationComponent) { - if (annotationComponent == null || annotationComponent.getAnnotation() == null) { - setEnabled(false); - return; - } - // assign the new action instance. - // assign the new action instance. - this.currentAnnotationComponent = annotationComponent; - - // For convenience grab the Annotation object wrapped by the component - Annotation annotation = currentAnnotationComponent.getAnnotation(); - - // apply flag state to swing components. - noRotateComboBox.setSelectedIndex(annotation.getFlagNoRotate() ? 0 : 1); - noZoomComboBox.setSelectedIndex(annotation.getFlagNoZoom() ? 0 : 1); - readOnlyComboBox.setSelectedIndex(annotation.getFlagReadOnly() ? 0 : 1); - printableComboBox.setSelectedIndex(annotation.getFlagPrint() ? 0 : 1); - - } - - public void itemStateChanged(ItemEvent e) { - Object source = e.getItemSelectable(); - if (source == noRotateComboBox) { - currentAnnotationComponent.getAnnotation().setFlag(Annotation.FLAG_NO_ROTATE, - noRotateComboBox.getSelectedIndex() == 0); - } else if (source == noZoomComboBox) { - currentAnnotationComponent.getAnnotation().setFlag(Annotation.FLAG_NO_ZOOM, - noZoomComboBox.getSelectedIndex() == 0); - } else if (source == readOnlyComboBox) { - currentAnnotationComponent.getAnnotation().setFlag(Annotation.FLAG_READ_ONLY, - readOnlyComboBox.getSelectedIndex() == 0); - } else if (source == printableComboBox) { - currentAnnotationComponent.getAnnotation().setFlag(Annotation.FLAG_PRINT, - printableComboBox.getSelectedIndex() == 0); - } - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - noRotateComboBox.setEnabled(enabled); - noZoomComboBox.setEnabled(enabled); - readOnlyComboBox.setEnabled(enabled); - printableComboBox.setEnabled(enabled); - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.flags.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - // build out the yes no list. - ValueLabelItem[] flagList = new ValueLabelItem[]{ - new ValueLabelItem(Boolean.TRUE, - messageBundle.getString("viewer.utilityPane.annotation.flags.enabled")), - new ValueLabelItem(Boolean.FALSE, - messageBundle.getString("viewer.utilityPane.annotation.flags.disabled"))}; - - // no rotate - noRotateComboBox = new JComboBox(flagList); - noRotateComboBox.addItemListener(this); - add(new JLabel(messageBundle.getString("viewer.utilityPane.annotation.flags.noRotate"))); - add(noRotateComboBox); - // no zoom - noZoomComboBox = new JComboBox(flagList); - noZoomComboBox.addItemListener(this); - add(new JLabel(messageBundle.getString("viewer.utilityPane.annotation.flags.noZoom"))); - add(noZoomComboBox); - // read only - readOnlyComboBox = new JComboBox(flagList); - readOnlyComboBox.addItemListener(this); - add(new JLabel(messageBundle.getString("viewer.utilityPane.annotation.flags.readOnly"))); - add(readOnlyComboBox); - // read only - printableComboBox = new JComboBox(flagList); - printableComboBox.addItemListener(this); - add(new JLabel(messageBundle.getString("viewer.utilityPane.annotation.flags.printable"))); - add(printableComboBox); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/FreeTextAnnotationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/FreeTextAnnotationPanel.java deleted file mode 100644 index b892141274..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/FreeTextAnnotationPanel.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.FreeTextAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; -import org.icepdf.ri.common.views.annotations.FreeTextAnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * FreeTextAnnotationPanel is a configuration panel for changing the properties - * of a FreeTextAnnotationComponent and the underlying annotation component. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class FreeTextAnnotationPanel extends AnnotationPanelAdapter implements ItemListener, - ActionListener, ChangeListener { - - // default list values. - private static final int DEFAULT_FONT_SIZE = 5; - private static final int DEFAULT_FONT_FAMILY = 0; - private static final Color DEFAULT_FONT_COLOR = Color.DARK_GRAY; - - public static final int DEFAULT_STROKE_THICKNESS_STYLE = 0; - public static final int DEFAULT_STROKE_STYLE = 0; - public static final int DEFAULT_FILL_STYLE = 0; - private static final Color DEFAULT_BORDER_COLOR = FreeTextAnnotation.defaultBorderColor; - private static final Color DEFAULT_STROKE_COLOR = FreeTextAnnotation.defaultFillColor; - - // font styles. - private static ValueLabelItem[] FONT_NAMES_LIST; - - // Font size. - private static ValueLabelItem[] FONT_SIZES_LIST; - - // action instance that is being edited - private FreeTextAnnotation freeTextAnnotation; - - // font configuration - private JComboBox fontNameBox; - private JComboBox fontSizeBox; - private JButton fontColorButton; - - // fill configuration - private JComboBox fillTypeBox; - private JButton fillColorButton; - - // border configuration - private JComboBox strokeTypeBox; - private JComboBox strokeThicknessBox; - private JComboBox strokeStyleBox; - private JButton strokeColorButton; - - // annotation transparency/opacity - private JSlider transparencySlider; - - public FreeTextAnnotationPanel(SwingController controller) { - super(controller); - - setLayout(new GridBagLayout()); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - /** - * Method that should be called when a new AnnotationComponent is selected by the user - * The associated object will be stored locally as currentAnnotation - * Then all of it's properties will be applied to the UI pane - * For example if the border was red, the color of the background button will - * be changed to red - * - * @param newAnnotation to set and apply to this UI - */ - public void setAnnotationComponent(AnnotationComponent newAnnotation) { - - if (newAnnotation == null || newAnnotation.getAnnotation() == null) { - setEnabled(false); - return; - } - // assign the new action instance. - this.currentAnnotationComponent = newAnnotation; - - // For convenience grab the Annotation object wrapped by the component - FreeTextAnnotationComponent freeTextAnnotationComponent = (FreeTextAnnotationComponent) - currentAnnotationComponent; - - freeTextAnnotation = (FreeTextAnnotation) freeTextAnnotationComponent.getAnnotation(); - - - // font comps - applySelectedValue(fontNameBox, freeTextAnnotation.getFontName()); - applySelectedValue(fontSizeBox, freeTextAnnotation.getFontSize()); - setButtonBackgroundColor(fontColorButton, freeTextAnnotation.getFontColor()); - - // border comps. - applySelectedValue(strokeTypeBox, freeTextAnnotation.isStrokeType()); - applySelectedValue(strokeStyleBox, freeTextAnnotation.getBorderStyle().getBorderStyle()); - applySelectedValue(strokeThicknessBox, freeTextAnnotation.getBorderStyle().getStrokeWidth()); - setButtonBackgroundColor(strokeColorButton, freeTextAnnotation.getColor()); - transparencySlider.setValue(Math.round(freeTextAnnotation.getOpacity() * 255)); - - // fill comps. - applySelectedValue(fillTypeBox, freeTextAnnotation.isFillType()); - setButtonBackgroundColor(fillColorButton, freeTextAnnotation.getFillColor()); - - safeEnable(fontNameBox, true); - safeEnable(fontSizeBox, true); - safeEnable(fontColorButton, true); - - safeEnable(strokeTypeBox, true); - safeEnable(strokeThicknessBox, true); - safeEnable(strokeStyleBox, true); - safeEnable(strokeColorButton, true); - - safeEnable(fillTypeBox, true); - safeEnable(fillColorButton, true); - safeEnable(transparencySlider, true); - - // set visibility based on fill and stroke type. - disableInvisibleFields(); - } - - private void disableInvisibleFields() { - - boolean fillType = freeTextAnnotation.isFillType(); - boolean strokeType = freeTextAnnotation.isStrokeType(); - - safeEnable(fillColorButton, fillType); - safeEnable(strokeThicknessBox, strokeType); - safeEnable(strokeStyleBox, strokeType); - safeEnable(strokeColorButton, strokeType); - - } - - public void itemStateChanged(ItemEvent e) { - ValueLabelItem item = (ValueLabelItem) e.getItem(); - if (e.getStateChange() == ItemEvent.SELECTED) { - if (e.getSource() == fontNameBox) { - freeTextAnnotation.setFontName((String) item.getValue()); - } else if (e.getSource() == fontSizeBox) { - freeTextAnnotation.setFontSize((Integer) item.getValue()); - } else if (e.getSource() == strokeTypeBox) { - Boolean visible = (Boolean) item.getValue(); - freeTextAnnotation.setStrokeType(visible); - if (visible) { - // set the line thickness - freeTextAnnotation.getBorderStyle().setStrokeWidth( - (Float) ((ValueLabelItem) strokeThicknessBox.getSelectedItem()).getValue()); - // set teh default stroke. - freeTextAnnotation.getBorderStyle().setBorderStyle( - (Name) ((ValueLabelItem) strokeStyleBox.getSelectedItem()).getValue()); - // apply the default colour - freeTextAnnotation.setColor(strokeColorButton.getBackground()); - } else { - freeTextAnnotation.getBorderStyle().setStrokeWidth(0); - } - disableInvisibleFields(); - } else if (e.getSource() == strokeStyleBox) { - freeTextAnnotation.getBorderStyle().setBorderStyle((Name) item.getValue()); - } else if (e.getSource() == strokeThicknessBox) { - freeTextAnnotation.getBorderStyle().setStrokeWidth((Float) item.getValue()); - } else if (e.getSource() == fillTypeBox) { - freeTextAnnotation.setFillType((Boolean) item.getValue()); - if (freeTextAnnotation.isFillType()) { - freeTextAnnotation.setFillColor(fillColorButton.getBackground()); - } - disableInvisibleFields(); - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == strokeColorButton) { - Color chosenColor = - JColorChooser.showDialog(strokeColorButton, - messageBundle.getString( - "viewer.utilityPane.annotation.freeText.border.color.ChooserTitle"), - strokeColorButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - setButtonBackgroundColor(strokeColorButton, chosenColor); - freeTextAnnotation.setColor(chosenColor); - } - } else if (e.getSource() == fillColorButton) { - Color chosenColor = - JColorChooser.showDialog(fillColorButton, - messageBundle.getString( - "viewer.utilityPane.annotation.freeText.fill.color.ChooserTitle"), - fillColorButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - setButtonBackgroundColor(fillColorButton, chosenColor); - freeTextAnnotation.setFillColor(chosenColor); - } - } else if (e.getSource() == fontColorButton) { - Color chosenColor = - JColorChooser.showDialog(fillColorButton, - messageBundle.getString( - "viewer.utilityPane.annotation.freeText.font.color.ChooserTitle"), - fontColorButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - setButtonBackgroundColor(fontColorButton, chosenColor); - freeTextAnnotation.setFontColor(chosenColor); - } - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - - public void stateChanged(ChangeEvent e) { - alphaSliderChange(e, freeTextAnnotation); - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - - // font styles - core java font names and respective labels. All Java JRE should have these fonts, these - // fonts also have huge number of glyphs support many different languages. - if (FONT_NAMES_LIST == null) { - FONT_NAMES_LIST = new ValueLabelItem[]{ - new ValueLabelItem("Helvetica", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.helvetica")), - new ValueLabelItem("Helvetica-Oblique", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.helveticaOblique")), - new ValueLabelItem("Helvetica-Bold", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.helveticaBold")), - new ValueLabelItem("Helvetica-BoldOblique", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.HelveticaBoldOblique")), - new ValueLabelItem("Times-Italic", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.timesItalic")), - new ValueLabelItem("Times-Bold", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.timesBold")), - new ValueLabelItem("Times-BoldItalic", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.timesBoldItalic")), - new ValueLabelItem("Times-Roman", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.timesRoman")), - new ValueLabelItem("Courier", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.courier")), - new ValueLabelItem("Courier-Oblique", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.courierOblique")), - new ValueLabelItem("Courier-BoldOblique", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.courierBoldOblique")), - new ValueLabelItem("Courier-Bold", - messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name.courierBold"))}; - } - - // Font size. - if (FONT_SIZES_LIST == null) { - FONT_SIZES_LIST = new ValueLabelItem[]{ - new ValueLabelItem(6, messageBundle.getString("viewer.common.number.six")), - new ValueLabelItem(8, messageBundle.getString("viewer.common.number.eight")), - new ValueLabelItem(9, messageBundle.getString("viewer.common.number.nine")), - new ValueLabelItem(10, messageBundle.getString("viewer.common.number.ten")), - new ValueLabelItem(12, messageBundle.getString("viewer.common.number.twelve")), - new ValueLabelItem(14, messageBundle.getString("viewer.common.number.fourteen")), - new ValueLabelItem(16, messageBundle.getString("viewer.common.number.sixteen")), - new ValueLabelItem(18, messageBundle.getString("viewer.common.number.eighteen")), - new ValueLabelItem(20, messageBundle.getString("viewer.common.number.twenty")), - new ValueLabelItem(24, messageBundle.getString("viewer.common.number.twentyFour")), - new ValueLabelItem(36, messageBundle.getString("viewer.common.number.thirtySix")), - new ValueLabelItem(48, messageBundle.getString("viewer.common.number.fortyEight"))}; - } - - // Create and setup an Appearance panel - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.freeText.appearance.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(1, 2, 1, 2); - - // Font name - fontNameBox = new JComboBox(FONT_NAMES_LIST); - fontNameBox.setSelectedIndex(DEFAULT_FONT_FAMILY); - fontNameBox.addItemListener(this); - JLabel label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.font.name")); - addGB(this, label, 0, 0, 1, 1); - addGB(this, fontNameBox, 1, 0, 1, 1); - - // border style - fontSizeBox = new JComboBox(FONT_SIZES_LIST); - fontSizeBox.setSelectedIndex(DEFAULT_FONT_SIZE); - fontSizeBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.font.size")); - addGB(this, label, 0, 1, 1, 1); - addGB(this, fontSizeBox, 1, 1, 1, 1); - - // border colour - fontColorButton = new JButton(" "); - fontColorButton.addActionListener(this); - fontColorButton.setOpaque(true); - fontColorButton.setBackground(DEFAULT_FONT_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.font.color")); - addGB(this, label, 0, 2, 1, 1); - addGB(this, fontColorButton, 1, 2, 1, 1); - - // stroke type - strokeTypeBox = new JComboBox(VISIBLE_TYPE_LIST); - strokeTypeBox.setSelectedIndex(DEFAULT_STROKE_STYLE); - strokeTypeBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.border.type")); - addGB(this, label, 0, 3, 1, 1); - addGB(this, strokeTypeBox, 1, 3, 1, 1); - - // border thickness - strokeThicknessBox = new JComboBox(LINE_THICKNESS_LIST); - strokeThicknessBox.setSelectedIndex(DEFAULT_STROKE_THICKNESS_STYLE); - strokeThicknessBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.border.thickness")); - addGB(this, label, 0, 4, 1, 1); - addGB(this, strokeThicknessBox, 1, 4, 1, 1); - - // border style - strokeStyleBox = new JComboBox(LINE_STYLE_LIST); - strokeStyleBox.setSelectedIndex(DEFAULT_STROKE_STYLE); - strokeStyleBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.border.style")); - addGB(this, label, 0, 5, 1, 1); - addGB(this, strokeStyleBox, 1, 5, 1, 1); - - // border colour - strokeColorButton = new JButton(" "); - strokeColorButton.addActionListener(this); - strokeColorButton.setOpaque(true); - setButtonBackgroundColor(strokeColorButton, DEFAULT_BORDER_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.border.color")); - addGB(this, label, 0, 6, 1, 1); - addGB(this, strokeColorButton, 1, 6, 1, 1); - - // fill type - fillTypeBox = new JComboBox(VISIBLE_TYPE_LIST); - fillTypeBox.setSelectedIndex(DEFAULT_FILL_STYLE); - fillTypeBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.fill.type")); - addGB(this, label, 0, 7, 1, 1); - addGB(this, fillTypeBox, 1, 7, 1, 1); - - // fill colour - fillColorButton = new JButton(" "); - fillColorButton.addActionListener(this); - fillColorButton.setOpaque(true); - setButtonBackgroundColor(fillColorButton, DEFAULT_STROKE_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.fill.color")); - addGB(this, label, 0, 8, 1, 1); - addGB(this, fillColorButton, 1, 8, 1, 1); - - // transparency slider - transparencySlider = buildAlphaSlider(); - transparencySlider.setMajorTickSpacing(255); - transparencySlider.setPaintLabels(true); - transparencySlider.addChangeListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.freeText.transparencyLabel")); - addGB(this, label, 0, 9, 1, 1); - addGB(this, transparencySlider, 1, 9, 1, 1); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - - safeEnable(fontNameBox, enabled); - safeEnable(fontSizeBox, enabled); - safeEnable(fontColorButton, enabled); - - safeEnable(strokeTypeBox, enabled); - safeEnable(strokeThicknessBox, enabled); - safeEnable(strokeStyleBox, enabled); - safeEnable(strokeColorButton, enabled); - - safeEnable(fillTypeBox, enabled); - safeEnable(fillColorButton, enabled); - safeEnable(transparencySlider, enabled); - } - - /** - * Convenience method to ensure a component is safe to toggle the enabled state on - * - * @param comp to toggle - * @param enabled the status to use - * @return true on success - */ - protected boolean safeEnable(JComponent comp, boolean enabled) { - if (comp != null) { - comp.setEnabled(enabled); - return true; - } - return false; - } - - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/GoToActionDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/GoToActionDialog.java deleted file mode 100644 index ebadc4fadd..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/GoToActionDialog.java +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Destination; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.NameTree; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.actions.ActionFactory; -import org.icepdf.core.pobjects.actions.GoToAction; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.LinkAnnotation; -import org.icepdf.ri.common.*; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EmptyBorder; -import java.awt.*; -import java.awt.event.*; -import java.util.List; -import java.util.ResourceBundle; - -/** - * GoTo Action panel used for setting an GoTo Action type properties. GoTo - * actions store a PDF Destination data structure which can either be a named - * destination or a vector of properties that specifies a page location. - * - * @since 4.0 - */ -@SuppressWarnings("serial") -public class GoToActionDialog extends AnnotationDialogAdapter - implements ActionListener, ItemListener { - - public static final String EMPTY_DESTINATION = " "; - - private SwingController controller; - private ResourceBundle messageBundle; - private AnnotationComponent currentAnnotation; - private ActionsPanel actionsPanel; - - // state full ui elements. - private GridBagConstraints constraints; - private JButton okButton; - private JButton cancelButton; - private JRadioButton implicitDestination; - private JRadioButton namedDestination; - - // controls for explicit destinations - private JComboBox implicitDestTypeComboBox; - private JTextField pageNumberTextField; - private JTextField topTextField; - private JTextField bottomTextField; - private JTextField leftTextField; - private JTextField rightTextField; - private JTextField zoomTextField; - private JButton viewPositionButton; - - // named destination fields. - private JLabel destinationName; - private JButton viewNamedDesButton; - private NameTreeDialog nameTreeDialog; - - public GoToActionDialog(SwingController controller, - ActionsPanel actionsPanel) { - super(controller.getViewerFrame(), true); - this.controller = controller; - this.messageBundle = this.controller.getMessageBundle(); - this.actionsPanel = actionsPanel; - - setTitle(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.title")); - // setup gui components. - setGui(); - } - - /** - * Copies state information from the annotation so it can pre respresented - * in the UI. This method does not modify the annotaiton object in any way. - * State saving should handled with save state call. - * - * @param annotation annotation to be updated by dialog. - */ - public void setAnnotationComponent(AnnotationComponent annotation) { - - // get a reference so we can setup a save on dialog close - currentAnnotation = annotation; - - org.icepdf.core.pobjects.actions.Action action = - currentAnnotation.getAnnotation().getAction(); - - // get the destination object, doesn't matter where it comes from. - Destination dest = null; - if (action != null && action instanceof GoToAction) { - dest = ((GoToAction) action).getDestination(); - } - // alternatively we can have a dest field on Link annotations - else if (action == null && - currentAnnotation.getAnnotation() instanceof LinkAnnotation) { - LinkAnnotation linkAnnotation = - (LinkAnnotation) currentAnnotation.getAnnotation(); - dest = linkAnnotation.getDestination(); - } - // check to see of we have a name tree in the document, if not we - // disable the controls for named destinations - if (controller.getDocument().getCatalog().getNames() == null || - controller.getDocument().getCatalog().getNames().getDestsNameTree() == null) { - implicitDestinationFieldsEnabled(true); - clearImplicitDestinations(true); - namedDestination.setEnabled(false); - } else { - namedDestination.setEnabled(true); - } - - // start gui value assignments. - if (dest != null) { - // first clear all previous values. - clearImplicitDestinations(false); - clearImplicitDestinations(true); - // implicit assignment - if (dest.getNamedDestination() == null) { - implicitDestinationFieldsEnabled(true); - Name type = dest.getType(); - applySelectedValue(implicitDestTypeComboBox, type); - // set field visibility for type - enableFitTypeFields(type); - // type assignment. - applyTypeValues(dest, type); - // finally assign the page number - pageNumberTextField.setText(String.valueOf(controller.getDocument() - .getPageTree().getPageNumber(dest.getPageReference()) + 1)); - } - // named assignment - else { - // enable GUI elements. - implicitDestinationFieldsEnabled(false); - // assign name to name label - destinationName.setText(dest.getNamedDestination().toString()); - } - } else { - // apply default fit type for new annotations. - applySelectedValue(implicitDestTypeComboBox, Destination.TYPE_FIT); - enableFitTypeFields(Destination.TYPE_FIT); - } - } - - /** - * Utility or saving the complicated state of a GoTo action. - */ - private void saveActionState() { - - Annotation annotation = currentAnnotation.getAnnotation(); - Destination destination; - - // create a new implicit destination - if (implicitDestination.isSelected()) { - Name fitType = (Name) ((ValueLabelItem) implicitDestTypeComboBox - .getSelectedItem()).getValue(); - int pageNumber = Integer.parseInt(pageNumberTextField.getText()); - Reference pageReference = controller.getDocument().getPageTree() - .getPageReference(pageNumber - 1); - List destArray = null; - if (fitType.equals(Destination.TYPE_FIT) || - fitType.equals(Destination.TYPE_FITB)) { - destArray = Destination.destinationSyntax(pageReference, fitType); - } - // just top enabled - else if (fitType.equals(Destination.TYPE_FITH) || - fitType.equals(Destination.TYPE_FITBH) || - fitType.equals(Destination.TYPE_FITV) || - fitType.equals(Destination.TYPE_FITBV)) { - Object top = parseDestCoordinate(topTextField.getText()); - destArray = Destination.destinationSyntax( - pageReference, fitType, top); - } - // special xyz case - else if (fitType.equals(Destination.TYPE_XYZ)) { - Object left = parseDestCoordinate(leftTextField.getText()); - Object top = parseDestCoordinate(topTextField.getText()); - Object zoom = parseDestCoordinate(zoomTextField.getText()); - destArray = Destination.destinationSyntax( - pageReference, fitType, left, top, zoom); - } - // special FitR - else if (fitType.equals(Destination.TYPE_FITR)) { - Object left = parseDestCoordinate(leftTextField.getText()); - Object bottom = parseDestCoordinate(leftTextField.getText()); - Object right = parseDestCoordinate(leftTextField.getText()); - Object top = parseDestCoordinate(leftTextField.getText()); - destArray = Destination.destinationSyntax( - pageReference, fitType, left, bottom, right, top); - } - destination = new Destination(annotation.getLibrary(), destArray); - } - // otherwise a simple named destination - else { - destination = new Destination(annotation.getLibrary(), - new Name(destinationName.getText())); - } - GoToAction action = (GoToAction) annotation.getAction(); - - // if no previous action then we have a 'new' or old 'dest' that - // that is getting updated. VERY IMPORTANT, dest are replaced with - // similar GoToActions under the current implementation. - if (action == null) { - action = (GoToAction) - ActionFactory.buildAction(annotation.getLibrary(), - ActionFactory.GOTO_ACTION); - action.setDestination(destination); - annotation.addAction(action); - actionsPanel.clearActionList(); - actionsPanel.addActionToList(action); - } else { - // set new destination value and merge the change back into the - // annotation. - action.setDestination(destination); - annotation.updateAction(action); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == okButton) { - // todo validate action State before save proceeds. - if (true) { - // if all is - saveActionState(); - dispose(); - } - } else if (e.getSource() == cancelButton) { - // disposes this dialog - dispose(); - } else if (e.getSource() == viewNamedDesButton) { - // test implementation of a NameJTree for destinations. - NameTree nameTree = controller.getDocument().getCatalog().getNames().getDestsNameTree(); - if (nameTree != null) { - // create new dialog instance. - nameTreeDialog = new NameTreeDialog( - controller, - true, nameTree); - nameTreeDialog.setDestinationName(destinationName); - // add the nameTree instance. - nameTreeDialog.setVisible(true); - nameTreeDialog.dispose(); - } - } - // very special button that gets the current view position coords. - else if (e.getSource() == viewPositionButton) { - - } - } - - @Override - public void dispose() { - setVisible(false); - super.dispose(); - // dispose the name tree if someone opened - if (nameTreeDialog != null) { - nameTreeDialog.dispose(); - } - } - - public void itemStateChanged(ItemEvent e) { - if (e.getStateChange() == ItemEvent.SELECTED || - e.getStateChange() == ItemEvent.DESELECTED) { - // enable/disable field sets for the two destinations types. - if (e.getSource() == implicitDestination) { - implicitDestinationFieldsEnabled(e.getStateChange() == ItemEvent.SELECTED); - // check for an empty type and if so assign fit - if (implicitDestination.isSelected()) { - if (implicitDestTypeComboBox.getSelectedItem() == null) { - applySelectedValue(implicitDestTypeComboBox, - Destination.TYPE_FIT); - enableFitTypeFields(Destination.TYPE_FIT); - } - } - } - // handle enabled state of top,bottom,left right and zoom. - else if (e.getSource() == implicitDestTypeComboBox) { - ValueLabelItem valueItem = (ValueLabelItem) e.getItem(); - Name fitType = (Name) valueItem.getValue(); - enableFitTypeFields(fitType); - } - } - } - - /** - * Method to create and customize the actions section of the panel - */ - protected void setGui() { - - /** - * Place GUI elements on dialog - */ - - JPanel goToActionPanel = new JPanel(); - - goToActionPanel.setAlignmentY(JPanel.TOP_ALIGNMENT); - GridBagLayout layout = new GridBagLayout(); - goToActionPanel.setLayout(layout); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.EAST; - constraints.insets = new Insets(5, 5, 5, 5); - - /** - * Create explicit layout - */ - // main panel for implicit fields, more work need for other fit types. - JPanel explicitDestinationSubpane = new JPanel(new GridLayout(4, 4, 10, 5)); - explicitDestinationSubpane.setBorder(new EmptyBorder(0, 40, 0, 0)); - // use current view location -// explicitDestinationSubpane.add(new JLabel(messageBundle.getString( -// "viewer.utilityPane.action.dialog.goto.current.label"))); -// viewPositionButton = new JButton(messageBundle.getString( -// "viewer.utilityPane.action.dialog.goto.current")); -// viewPositionButton.addActionListener(this); -// explicitDestinationSubpane.add(viewPositionButton); - // filler -// explicitDestinationSubpane.add(new JLabel()); -// explicitDestinationSubpane.add(new JLabel()); - // fit type - currently only xyz - explicitDestinationSubpane.add(new JLabel(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.type.label"))); - implicitDestTypeComboBox = buildImplicitDestTypes(); - implicitDestTypeComboBox.addItemListener(this); - explicitDestinationSubpane.add(implicitDestTypeComboBox); - // page assignment - explicitDestinationSubpane.add(new JLabel(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.page.label"))); - pageNumberTextField = buildDocumentPageNumbers(); - explicitDestinationSubpane.add(pageNumberTextField); - // top position - explicitDestinationSubpane.add(new JLabel(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.top.label"))); - topTextField = buildFloatTextField(); - explicitDestinationSubpane.add(topTextField); - // bottom position - explicitDestinationSubpane.add(new JLabel(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.bottom.label"))); - bottomTextField = buildFloatTextField(); - explicitDestinationSubpane.add(bottomTextField); - // left position - explicitDestinationSubpane.add(new JLabel(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.left.label"))); - leftTextField = buildFloatTextField(); - explicitDestinationSubpane.add(leftTextField); - // right position - explicitDestinationSubpane.add(new JLabel(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.right.label"))); - rightTextField = buildFloatTextField(); - explicitDestinationSubpane.add(rightTextField); - // zoom level - explicitDestinationSubpane.add(new JLabel(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.zoom.label"))); - zoomTextField = buildFloatTextField(); - explicitDestinationSubpane.add(zoomTextField); - // filler - explicitDestinationSubpane.add(new JLabel()); - explicitDestinationSubpane.add(new JLabel()); - // put the explicit destinations fields into one container. - JPanel pageNumberPane = new JPanel(new BorderLayout(5, 5)); - implicitDestination = new JRadioButton(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.explicitDestination.title"), true); - implicitDestination.addItemListener(this); - pageNumberPane.add(implicitDestination, BorderLayout.NORTH); - pageNumberPane.add(explicitDestinationSubpane, BorderLayout.CENTER); - - /** - * Setup Named destinations - */ - JPanel namedDestSubpane = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5)); - namedDestSubpane.setBorder(new EmptyBorder(0, 40, 0, 0)); - // name of named dest.. - namedDestSubpane.add(new JLabel(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.name.label"))); - destinationName = new JLabel(EMPTY_DESTINATION); - namedDestSubpane.add(destinationName); - // browse button to show named destination tree. - viewNamedDesButton = new JButton(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.browse")); - viewNamedDesButton.addActionListener(this); - namedDestSubpane.add(viewNamedDesButton); - // put the named destination into one container. - JPanel namedDestPane = new JPanel(new BorderLayout(5, 5)); - namedDestination = - new JRadioButton(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.nameDestination.title"), false); - namedDestPane.add(namedDestination, BorderLayout.NORTH); - namedDestPane.add(namedDestSubpane, BorderLayout.CENTER); - - // Button group to link the two panels toggled functionality. - ButtonGroup actionButtonGroup = new ButtonGroup(); - actionButtonGroup.add(implicitDestination); - actionButtonGroup.add(namedDestination); - - // ok button to save changes and close the dialog. - okButton = new JButton(messageBundle.getString("viewer.button.ok.label")); - okButton.setMnemonic(messageBundle.getString("viewer.button.ok.mnemonic").charAt(0)); - okButton.addActionListener(this); - cancelButton = new JButton(messageBundle.getString("viewer.button.cancel.label")); - cancelButton.setMnemonic(messageBundle.getString("viewer.button.cancel.mnemonic").charAt(0)); - cancelButton.addActionListener(this); - // panel for OK and cancel - JPanel okCancelPanel = new JPanel(new FlowLayout()); - okCancelPanel.add(okButton); - okCancelPanel.add(cancelButton); - - // add values - constraints.insets = new Insets(5, 5, 5, 5); - constraints.anchor = GridBagConstraints.WEST; - - addGB(goToActionPanel, pageNumberPane, 0, 0, 1, 1); - addGB(goToActionPanel, namedDestPane, 0, 1, 1, 1); - - constraints.insets = new Insets(15, 5, 5, 5); - constraints.anchor = GridBagConstraints.CENTER; - addGB(goToActionPanel, okCancelPanel, 0, 2, 1, 1); - - this.getContentPane().add(goToActionPanel); - - setSize(new Dimension(500, 325)); - setLocationRelativeTo(controller.getViewerFrame()); - - } - - /** - * Utility for parsing input text coordinates into valide numbers used - * for destinations. If an empty string or Na, we return a null value - * which is valid in post script. - * - * @param fieldValue value to convert to either a number or null. - * @return Float if valid fieldValue, Null otherwise. - */ - private Object parseDestCoordinate(String fieldValue) { - try { - return Float.parseFloat(fieldValue); - } catch (NumberFormatException e) { - // empty on purpose - } - return null; - } - - /** - * Utility to return the - * - * @param coord float value to convert to UI usuable string - * @return string value of coord or an empty string if coord is null - */ - private String getDestCoordinate(Float coord) { - if (coord != null) { - return String.valueOf(coord); - } else { - return ""; - } - } - - private void applyTypeValues(Destination dest, Name type) { - if (Destination.TYPE_XYZ.equals(type)) { - leftTextField.setText(getDestCoordinate(dest.getLeft())); - topTextField.setText(getDestCoordinate(dest.getTop())); - zoomTextField.setText(getDestCoordinate(dest.getZoom())); - } else if (Destination.TYPE_FIT.equals(type)) { - // nothing to do - } else if (Destination.TYPE_FITH.equals(type)) { - // get top value - topTextField.setText(getDestCoordinate(dest.getTop())); - } else if (Destination.TYPE_FITV.equals(type)) { - // get left value - leftTextField.setText(getDestCoordinate(dest.getLeft())); - } else if (Destination.TYPE_FITR.equals(type)) { - // left, bottom right and top. - leftTextField.setText(getDestCoordinate(dest.getLeft())); - rightTextField.setText(getDestCoordinate(dest.getRight())); - topTextField.setText(getDestCoordinate(dest.getTop())); - bottomTextField.setText(getDestCoordinate(dest.getBottom())); - } else if (Destination.TYPE_FITB.equals(type)) { - // nothing to do. - } else if (Destination.TYPE_FITH.equals(type)) { - // get the top - topTextField.setText(getDestCoordinate(dest.getTop())); - } else if (Destination.TYPE_FITBV.equals(type)) { - // get the left - leftTextField.setText(getDestCoordinate(dest.getLeft())); - } - } - - /** - * Utility for building input field that handles page number limits for the - * current document. - * - * @return pageNumber text field with listeners for validation. - */ - private JTextField buildDocumentPageNumbers() { - final JTextField textField = new JTextField(); - textField.setInputVerifier(new PageNumberTextFieldInputVerifier()); - textField.addKeyListener(new PageNumberTextFieldKeyListener()); - textField.addFocusListener(new FocusAdapter() { - public void focusLost(FocusEvent e) { - Object src = e.getSource(); - if (src == null) - return; - if (src == textField) { - String fieldValue = textField.getText(); - int currentValue = Integer.parseInt(fieldValue); - int maxValue = controller.getDocument().getNumberOfPages(); - if (currentValue > maxValue) - textField.setText(String.valueOf(maxValue)); - } - } - }); - // start off with page 1. - textField.setText("1"); - return textField; - } - - /** - * Utility for building input field that handles page number limits for the - * current document. - * - * @return pageNumber text field with listeners for validation. - */ - private JTextField buildFloatTextField() { - final JTextField textField = new JTextField(); - textField.setInputVerifier(new FloatTextFieldInputVerifier()); - textField.addKeyListener(new FloatTextFieldKeyListener()); - textField.addFocusListener(new FocusAdapter() { - public void focusLost(FocusEvent e) { - Object src = e.getSource(); - if (src == null) - return; - if (src == textField) { - String fieldValue = textField.getText(); - // empty string, no problem we can allow that. - if ("".equals(fieldValue)) { - return; - } - float currentValue = Float.parseFloat(fieldValue); - textField.setText(String.valueOf(currentValue)); - } - } - }); - - return textField; - } - - /** - * Builds destination types combo box. - * - * @return combo box of possilbe implict destination types. - */ - private JComboBox buildImplicitDestTypes() { - ValueLabelItem[] destTypes = new ValueLabelItem[]{ - new ValueLabelItem(Destination.TYPE_XYZ, - messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.type.xyz.label")), - new ValueLabelItem(Destination.TYPE_FITH, - messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.type.fith.label")), - new ValueLabelItem(Destination.TYPE_FITR, - messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.type.fitr.label")), - new ValueLabelItem(Destination.TYPE_FIT, - messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.type.fit.label")), - new ValueLabelItem(Destination.TYPE_FITB, - messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.type.fitb.label")), - new ValueLabelItem(Destination.TYPE_FITBH, - messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.type.fitbh.label")), - new ValueLabelItem(Destination.TYPE_FITBV, - messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.type.fitbv.label")), - new ValueLabelItem(Destination.TYPE_FITBV, - messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.type.fitbv.label")), - }; - return new JComboBox(destTypes); - } - - /** - * Gridbag constructor helper - * - * @param layout panel to invoke layout on - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan rowspan value - * @param colSpan colspan value - */ - private void addGB(JPanel layout, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - layout.add(component, constraints); - } - - /** - * Enables fields for destinations - * - * @param isImplictDestSelected true enables all implicit destination fields, - * false enables all named destinations - */ - private void implicitDestinationFieldsEnabled(boolean isImplictDestSelected) { - - // radio selection - implicitDestination.setSelected(isImplictDestSelected); - namedDestination.setSelected(!isImplictDestSelected); - - // implicit dest fields - pageNumberTextField.setEnabled(isImplictDestSelected); - implicitDestTypeComboBox.setEnabled(isImplictDestSelected); - leftTextField.setEnabled(isImplictDestSelected); - topTextField.setEnabled(isImplictDestSelected); - zoomTextField.setEnabled(isImplictDestSelected); -// viewPositionButton.setEnabled(isImplictDestSelected); - // named fields - destinationName.setEnabled(!isImplictDestSelected); - viewNamedDesButton.setEnabled(!isImplictDestSelected); - } - - /** - * Clears fields for destinations - * - * @param isImplictDestSelected true clears all implicit destination fields, - * false clears all named destinations - */ - private void clearImplicitDestinations(boolean isImplictDestSelected) { - // implicit - if (!isImplictDestSelected) { - pageNumberTextField.setText(""); - implicitDestTypeComboBox.setSelectedIndex(-1); - leftTextField.setText(""); - topTextField.setText(""); - zoomTextField.setText(""); - } - // named - else { - destinationName.setText(EMPTY_DESTINATION); - } - } - - /** - * Assigns the fit type and applies the field enabled state logic for the - * respective view type. - * - * @param fitType destination fit type to apply - */ - private void enableFitTypeFields(Name fitType) { - if (fitType.equals(Destination.TYPE_FIT) || - fitType.equals(Destination.TYPE_FITB)) { - // disable all fields - setFitTypesEnabled(false, false, false, false, false); - } - // just top enabled - else if (fitType.equals(Destination.TYPE_FITH) || - fitType.equals(Destination.TYPE_FITBH)) { - setFitTypesEnabled(true, false, false, false, false); - } - // Just left enabled - else if (fitType.equals(Destination.TYPE_FITV) || - fitType.equals(Destination.TYPE_FITBV)) { - setFitTypesEnabled(false, false, true, false, false); - } - // special xyz case - else if (fitType.equals(Destination.TYPE_XYZ)) { - setFitTypesEnabled(true, false, true, false, true); - } - // special FitR - else if (fitType.equals(Destination.TYPE_FITR)) { - setFitTypesEnabled(true, true, true, true, false); - } - } - - /** - * Sets the enabled state of the input fields associated with implicit - * destination fit types. - * - * @param top top coordinat input field. - * @param bottom bottom coordinat input field. - * @param left left coordinat input field. - * @param right right coordinat input field. - * @param zoom view port zoom value field. - */ - private void setFitTypesEnabled(boolean top, boolean bottom, - boolean left, boolean right, boolean zoom) { - topTextField.setEnabled(top); - bottomTextField.setEnabled(bottom); - leftTextField.setEnabled(left); - rightTextField.setEnabled(right); - zoomTextField.setEnabled(zoom); - } - - /** - * Apply selected values to combo box. If a match can not be found - * no values is applied. - * - * @param comboBox combo box to update - * @param value value to assing. - */ - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/InkAnnotationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/InkAnnotationPanel.java deleted file mode 100644 index 1717813054..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/InkAnnotationPanel.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.InkAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * InkAnnotationPanel is a configuration panel for changing the properties - * of a InkAnnotationComponent and the underlying annotation component. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class InkAnnotationPanel extends AnnotationPanelAdapter implements ItemListener, - ActionListener, ChangeListener { - - // default list values. - private static final int DEFAULT_LINE_THICKNESS = 0; - private static final int DEFAULT_LINE_STYLE = 0; - private static final Color DEFAULT_BORDER_COLOR = Color.RED; - - // link action appearance properties. - private JComboBox lineThicknessBox; - private JComboBox lineStyleBox; - private JButton colorBorderButton; - private JSlider transparencySlider; - - private InkAnnotation annotation; - - public InkAnnotationPanel(SwingController controller) { - super(controller); - setLayout(new GridBagLayout()); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - - /** - * Method that should be called when a new AnnotationComponent is selected by the user - * The associated object will be stored locally as currentAnnotation - * Then all of it's properties will be applied to the UI pane - * For example if the border was red, the color of the background button will - * be changed to red - * - * @param newAnnotation to set and apply to this UI - */ - public void setAnnotationComponent(AnnotationComponent newAnnotation) { - - if (newAnnotation == null || newAnnotation.getAnnotation() == null) { - setEnabled(false); - return; - } - // assign the new action instance. - this.currentAnnotationComponent = newAnnotation; - - // For convenience grab the Annotation object wrapped by the component - annotation = (InkAnnotation) - currentAnnotationComponent.getAnnotation(); - - applySelectedValue(lineThicknessBox, annotation.getLineThickness()); - applySelectedValue(lineStyleBox, annotation.getLineStyle()); - setButtonBackgroundColor(colorBorderButton, annotation.getColor()); - transparencySlider.setValue(Math.round(annotation.getOpacity() * 255)); - - // disable appearance input if we have a invisible rectangle - safeEnable(lineThicknessBox, true); - safeEnable(lineStyleBox, true); - safeEnable(colorBorderButton, true); - safeEnable(transparencySlider, true); - } - - public void itemStateChanged(ItemEvent e) { - ValueLabelItem item = (ValueLabelItem) e.getItem(); - if (e.getStateChange() == ItemEvent.SELECTED) { - if (e.getSource() == lineThicknessBox) { - annotation.getBorderStyle().setStrokeWidth((Float) item.getValue()); - } else if (e.getSource() == lineStyleBox) { - annotation.getBorderStyle().setBorderStyle((Name) item.getValue()); - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == colorBorderButton) { - Color chosenColor = - JColorChooser.showDialog(colorBorderButton, - messageBundle.getString( - "viewer.utilityPane.annotation.ink.colorBorderChooserTitle"), - colorBorderButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - colorBorderButton.setBackground(chosenColor); - annotation.setColor(chosenColor); - - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - } - - public void stateChanged(ChangeEvent e) { - alphaSliderChange(e, annotation); - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - - // Create and setup an Appearance panel - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.ink.appearance.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(1, 2, 1, 2); - - // Line thickness - lineThicknessBox = new JComboBox(LINE_THICKNESS_LIST); - lineThicknessBox.setSelectedIndex(DEFAULT_LINE_THICKNESS); - lineThicknessBox.addItemListener(this); - JLabel label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.ink.lineThickness")); - addGB(this, label, 0, 0, 1, 1); - addGB(this, lineThicknessBox, 1, 0, 1, 1); - // Line style - lineStyleBox = new JComboBox(LINE_STYLE_LIST); - lineStyleBox.setSelectedIndex(DEFAULT_LINE_STYLE); - lineStyleBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.ink.lineStyle")); - addGB(this, label, 0, 1, 1, 1); - addGB(this, lineStyleBox, 1, 1, 1, 1); - // border colour - colorBorderButton = new JButton(" "); - colorBorderButton.addActionListener(this); - colorBorderButton.setOpaque(true); - colorBorderButton.setBackground(DEFAULT_BORDER_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.ink.colorBorderLabel")); - addGB(this, label, 0, 2, 1, 1); - addGB(this, colorBorderButton, 1, 2, 1, 1); - - // transparency slider - transparencySlider = buildAlphaSlider(); - transparencySlider.setMajorTickSpacing(255); - transparencySlider.setPaintLabels(true); - transparencySlider.addChangeListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.ink.transparencyLabel")); - addGB(this, label, 0, 3, 1, 1); - addGB(this, transparencySlider, 1, 3, 1, 1); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - - safeEnable(lineThicknessBox, enabled); - safeEnable(lineStyleBox, enabled); - safeEnable(colorBorderButton, enabled); - safeEnable(transparencySlider, enabled); - } - - /** - * Convenience method to ensure a component is safe to toggle the enabled state on - * - * @param comp to toggle - * @param enabled the status to use - * @return true on success - */ - protected boolean safeEnable(JComponent comp, boolean enabled) { - if (comp != null) { - comp.setEnabled(enabled); - return true; - } - return false; - } - - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/LineAnnotationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/LineAnnotationPanel.java deleted file mode 100644 index a63dc3f709..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/LineAnnotationPanel.java +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.LineAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * LineAnnotationPanel is a configuration panel for changing the properties - * of a LineAnnotationComponent and the underlying annotation component. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class LineAnnotationPanel extends AnnotationPanelAdapter implements ItemListener, - ActionListener, ChangeListener { - - // default list values. - private static final int DEFAULT_START_END_TYPE = 0; - private static final int DEFAULT_END_END_TYPE = 0; - private static final int DEFAULT_LINE_THICKNESS = 0; - private static final int DEFAULT_LINE_STYLE = 0; - private static final Color DEFAULT_BORDER_COLOR = Color.DARK_GRAY; - private static final Color DEFAULT_FILL_COLOR = Color.DARK_GRAY; - - // line end types. - private static ValueLabelItem[] END_TYPE_LIST; - - // link action appearance properties. - private JComboBox startEndTypeBox; - private JComboBox endEndTypeBox; - private JComboBox lineThicknessBox; - private JComboBox lineStyleBox; - private JButton colorButton; - private JButton internalColorButton; - private JSlider transparencySlider; - - private LineAnnotation annotation; - - public LineAnnotationPanel(SwingController controller) { - super(controller); - - setLayout(new GridBagLayout()); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - - /** - * Method that should be called when a new AnnotationComponent is selected by the user - * The associated object will be stored locally as currentAnnotation - * Then all of it's properties will be applied to the UI pane - * For example if the border was red, the color of the background button will - * be changed to red - * - * @param newAnnotation to set and apply to this UI - */ - public void setAnnotationComponent(AnnotationComponent newAnnotation) { - - if (newAnnotation == null || newAnnotation.getAnnotation() == null) { - setEnabled(false); - return; - } - // assign the new action instance. - this.currentAnnotationComponent = newAnnotation; - - // For convenience grab the Annotation object wrapped by the component - annotation = (LineAnnotation) - currentAnnotationComponent.getAnnotation(); - - applySelectedValue(startEndTypeBox, annotation.getStartArrow()); - applySelectedValue(endEndTypeBox, annotation.getEndArrow()); - applySelectedValue(lineThicknessBox, annotation.getLineThickness()); - applySelectedValue(lineStyleBox, annotation.getLineStyle()); - setButtonBackgroundColor(colorButton, annotation.getColor()); - setButtonBackgroundColor(internalColorButton, annotation.getInteriorColor()); - transparencySlider.setValue(Math.round(annotation.getOpacity() * 255)); - - // disable appearance input if we have a invisible rectangle - safeEnable(startEndTypeBox, true); - safeEnable(endEndTypeBox, true); - safeEnable(lineThicknessBox, true); - safeEnable(lineStyleBox, true); - safeEnable(colorButton, true); - safeEnable(internalColorButton, true); - safeEnable(transparencySlider, true); - } - - public void itemStateChanged(ItemEvent e) { - ValueLabelItem item = (ValueLabelItem) e.getItem(); - if (e.getStateChange() == ItemEvent.SELECTED) { - if (e.getSource() == startEndTypeBox) { - annotation.setStartArrow((Name) item.getValue()); - } else if (e.getSource() == endEndTypeBox) { - annotation.setEndArrow((Name) item.getValue()); - } else if (e.getSource() == lineThicknessBox) { - annotation.getBorderStyle().setStrokeWidth((Float) item.getValue()); - } else if (e.getSource() == lineStyleBox) { - annotation.getBorderStyle().setBorderStyle((Name) item.getValue()); - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == colorButton) { - Color chosenColor = - JColorChooser.showDialog(colorButton, - messageBundle.getString( - "viewer.utilityPane.annotation.line.colorChooserTitle"), - colorButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - colorButton.setBackground(chosenColor); - annotation.setColor(chosenColor); - - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } else if (e.getSource() == internalColorButton) { - Color chosenColor = - JColorChooser.showDialog(internalColorButton, - messageBundle.getString( - "viewer.utilityPane.annotation.line.colorInternalChooserTitle"), - internalColorButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - internalColorButton.setBackground(chosenColor); - annotation.setInteriorColor(chosenColor); - - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - - } - - public void stateChanged(ChangeEvent e) { - alphaSliderChange(e, annotation); - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - // line end types - if (END_TYPE_LIST == null) { - END_TYPE_LIST = new ValueLabelItem[]{ - new ValueLabelItem(LineAnnotation.LINE_END_NONE, - messageBundle.getString("viewer.utilityPane.annotation.line.end.none")), - new ValueLabelItem(LineAnnotation.LINE_END_OPEN_ARROW, - messageBundle.getString("viewer.utilityPane.annotation.line.end.openArrow")), - new ValueLabelItem(LineAnnotation.LINE_END_CLOSED_ARROW, - messageBundle.getString("viewer.utilityPane.annotation.line.end.closedArrow")), - new ValueLabelItem(LineAnnotation.LINE_END_DIAMOND, - messageBundle.getString("viewer.utilityPane.annotation.line.end.diamond")), - new ValueLabelItem(LineAnnotation.LINE_END_SQUARE, - messageBundle.getString("viewer.utilityPane.annotation.line.end.square")), - new ValueLabelItem(LineAnnotation.LINE_END_CIRCLE, - messageBundle.getString("viewer.utilityPane.annotation.line.end.circle"))}; - } - - // Create and setup an Appearance panel - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.line.appearance.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(1, 2, 1, 2); - - // Line start type - startEndTypeBox = new JComboBox(END_TYPE_LIST); - startEndTypeBox.setSelectedIndex(DEFAULT_START_END_TYPE); - startEndTypeBox.addItemListener(this); - JLabel label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.line.startStyle")); - addGB(this, label, 0, 0, 1, 1); - addGB(this, startEndTypeBox, 1, 0, 1, 1); - // Line end type - endEndTypeBox = new JComboBox(END_TYPE_LIST); - endEndTypeBox.setSelectedIndex(DEFAULT_END_END_TYPE); - endEndTypeBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.line.endStyle")); - addGB(this, label, 0, 1, 1, 1); - addGB(this, endEndTypeBox, 1, 1, 1, 1); - // Line thickness - lineThicknessBox = new JComboBox(LINE_THICKNESS_LIST); - lineThicknessBox.setSelectedIndex(DEFAULT_LINE_THICKNESS); - lineThicknessBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.line.lineThickness")); - addGB(this, label, 0, 2, 1, 1); - addGB(this, lineThicknessBox, 1, 2, 1, 1); - // Line style - lineStyleBox = new JComboBox(LINE_STYLE_LIST); - lineStyleBox.setSelectedIndex(DEFAULT_LINE_STYLE); - lineStyleBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.line.lineStyle")); - addGB(this, label, 0, 3, 1, 1); - addGB(this, lineStyleBox, 1, 3, 1, 1); - - // border colour - colorButton = new JButton(" "); - colorButton.addActionListener(this); - colorButton.setOpaque(true); - colorButton.setBackground(DEFAULT_BORDER_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.line.colorLabel")); - addGB(this, label, 0, 4, 1, 1); - addGB(this, colorButton, 1, 4, 1, 1); - // line colour - internalColorButton = new JButton(" "); - internalColorButton.addActionListener(this); - internalColorButton.setOpaque(true); - internalColorButton.setBackground(DEFAULT_FILL_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.line.colorInternalLabel")); - addGB(this, label, 0, 5, 1, 1); - addGB(this, internalColorButton, 1, 5, 1, 1); - - // transparency slider - transparencySlider = buildAlphaSlider(); - transparencySlider.setMajorTickSpacing(255); - transparencySlider.setPaintLabels(true); - transparencySlider.addChangeListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.line.transparencyLabel")); - addGB(this, label, 0, 6, 1, 1); - addGB(this, transparencySlider, 1, 6, 1, 1); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - - safeEnable(startEndTypeBox, enabled); - safeEnable(endEndTypeBox, enabled); - safeEnable(lineThicknessBox, enabled); - safeEnable(lineStyleBox, enabled); - safeEnable(colorButton, enabled); - safeEnable(internalColorButton, enabled); - safeEnable(transparencySlider, enabled); - } - - /** - * Convenience method to ensure a component is safe to toggle the enabled state on - * - * @param comp to toggle - * @param enabled the status to use - * @return true on success - */ - protected boolean safeEnable(JComponent comp, boolean enabled) { - if (comp != null) { - comp.setEnabled(enabled); - return true; - } - return false; - } - - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/LinkAnnotationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/LinkAnnotationPanel.java deleted file mode 100644 index ee2da48944..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/LinkAnnotationPanel.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.LinkAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import java.awt.*; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * Link Annotation panel intended use is for the manipulation of LinkAnnotation - * appearance properties. This could be used with other annotation types but - * it's not suggested. - * - * @since 4.0 - */ -@SuppressWarnings("serial") -public class LinkAnnotationPanel extends AnnotationPanelAdapter implements ItemListener { - - // default list values. - private static final int DEFAULT_HIGHLIGHT_STYLE = 1; - - // link action appearance properties. - private JComboBox highlightStyleBox; - - // appearance properties to take care of. - private Name highlightStyle; - - public LinkAnnotationPanel(SwingController controller) { - super(controller); - setLayout(new GridLayout(1, 2, 5, 2)); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - /** - * Method that should be called when a new AnnotationComponent is selected by the user - * The associated object will be stored locally as currentAnnotation - * Then all of it's properties will be applied to the UI pane - * For example if the border was red, the color of the background button will - * be changed to red - * - * @param newAnnotation to set and apply to this UI - */ - public void setAnnotationComponent(AnnotationComponent newAnnotation) { - - if (newAnnotation == null || newAnnotation.getAnnotation() == null || - !(newAnnotation.getAnnotation() instanceof LinkAnnotation)) { - setEnabled(false); - return; - } - // assign the new action instance. - this.currentAnnotationComponent = newAnnotation; - - // For convenience grab the Annotation object wrapped by the component - LinkAnnotation linkAnnotation = - (LinkAnnotation) currentAnnotationComponent.getAnnotation(); - - // apply values to appears - highlightStyle = linkAnnotation.getHighlightMode(); - applySelectedValue(highlightStyleBox, highlightStyle); - - // disable appearance input if we have a invisible rectangle - enableAppearanceInputComponents(linkAnnotation.getBorderType()); - } - - public void itemStateChanged(ItemEvent e) { - ValueLabelItem item = (ValueLabelItem) e.getItem(); - if (e.getStateChange() == ItemEvent.SELECTED) { - if (e.getSource() == highlightStyleBox) { - highlightStyle = (Name) item.getValue(); - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.repaint(); - } - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - - // highlight styles. - ValueLabelItem[] highlightStyleList = new ValueLabelItem[]{ - new ValueLabelItem(LinkAnnotation.HIGHLIGHT_NONE, - messageBundle.getString("viewer.utilityPane.annotation.link.none")), - new ValueLabelItem(LinkAnnotation.HIGHLIGHT_INVERT, - messageBundle.getString("viewer.utilityPane.annotation.link.invert")), - new ValueLabelItem(LinkAnnotation.HIGHLIGHT_OUTLINE, - messageBundle.getString("viewer.utilityPane.annotation.link.outline")), - new ValueLabelItem(LinkAnnotation.HIGHLIGHT_PUSH, - messageBundle.getString("viewer.utilityPane.annotation.link.push"))}; - - // Create and setup an Appearance panel - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.link.appearance.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - // highlight style box. - highlightStyleBox = new JComboBox(highlightStyleList); - highlightStyleBox.setSelectedIndex(DEFAULT_HIGHLIGHT_STYLE); - highlightStyleBox.addItemListener(this); - add(new JLabel( - messageBundle.getString("viewer.utilityPane.annotation.link.highlightType"))); - add(highlightStyleBox); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - safeEnable(highlightStyleBox, enabled); - } - - /** - * Method to enable appearance input fields for an invisible rectangle - * - * @param linkType invisible rectangle or visible, your pick. - */ - private void enableAppearanceInputComponents(int linkType) { - if (linkType == Annotation.INVISIBLE_RECTANGLE) { - // everything but highlight style and link type - safeEnable(highlightStyleBox, true); - } else { - // enable all fields. - safeEnable(highlightStyleBox, true); - } - } - - /** - * Convenience method to ensure a component is safe to toggle the enabled state on - * - * @param comp to toggle - * @param enabled the status to use - * @return true on success - */ - protected boolean safeEnable(JComponent comp, boolean enabled) { - if (comp != null) { - comp.setEnabled(enabled); - return true; - } - return false; - } - - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/NameJTree.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/NameJTree.java deleted file mode 100644 index ffefe91f37..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/NameJTree.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.ri.images.Images; - -import javax.swing.*; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.TreeSelectionModel; - -/** - * Name tree component to represent a PDF documents name tree data structure. - * - * @since 4.0 - */ -@SuppressWarnings("serial") -public class NameJTree extends JTree { - public NameJTree() { - getSelectionModel().setSelectionMode( - TreeSelectionModel.SINGLE_TREE_SELECTION); - // change the look & feel of the jtree - DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); - renderer.setOpenIcon(new ImageIcon(Images.get("page.gif"))); - renderer.setClosedIcon(new ImageIcon(Images.get("page.gif"))); - renderer.setLeafIcon(new ImageIcon(Images.get("page.gif"))); - setCellRenderer(renderer); - - setModel(null); - setRootVisible(true); - setScrollsOnExpand(true); - // old font was Arial with is no go for linux. - setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 13)); - setRowHeight(18); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/NameTreeDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/NameTreeDialog.java deleted file mode 100644 index 6ecc0c36c8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/NameTreeDialog.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.NameTree; -import org.icepdf.ri.common.EscapeJDialog; -import org.icepdf.ri.common.SwingController; - -import javax.swing.*; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultTreeModel; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ResourceBundle; - -/** - * Create a dialog containg a name tree for the open document. If no name - * tree exists then no tree is shown. - * - * @since 4.0 - */ -@SuppressWarnings("serial") -public class NameTreeDialog extends EscapeJDialog - implements ActionListener, TreeSelectionListener { - - private SwingController controller; - private ResourceBundle messageBundle; - - private JTree nameJTree; - private NameTreeNode selectedName; - private JLabel destinationName; - private JButton okButton; - private JButton cancelButton; - - private GridBagConstraints constraints; - - public NameTreeDialog(SwingController controller, boolean modal, NameTree nameTree) - throws HeadlessException { - super(controller.getViewerFrame(), modal); - this.controller = controller; - this.messageBundle = this.controller.getMessageBundle(); - - setGui(nameTree); - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == okButton) { - // assign the selected name. - if (selectedName != null) { - destinationName.setText(selectedName.getName().toString()); - } - setVisible(false); - dispose(); - } else if (e.getSource() == cancelButton) { - setVisible(false); - dispose(); - } - } - - // Listen for selected tree items - public void valueChanged(TreeSelectionEvent e) { - // jump to the page stored in the JTree - if (nameJTree.getLastSelectedPathComponent() != null) { - NameTreeNode selectedNode = ((NameTreeNode) - nameJTree.getLastSelectedPathComponent()); - // make sure we have name leaf and not a intermediate node. - if (selectedNode.getReference() != null) { - selectedName = selectedNode; - } else { - // null the selection. - nameJTree.setSelectionPath(null); - selectedName = null; - } - } - } - - private void setGui(NameTree nameTree) { - - // dialog title - setTitle(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.nameTree.title")); - - // build the name tree. - nameJTree = new NameJTree(); - nameJTree.setModel(new DefaultTreeModel( - new NameTreeNode(nameTree.getRoot(), messageBundle))); - nameJTree.setRootVisible(!nameTree.getRoot().isEmpty()); - nameJTree.addTreeSelectionListener(this); - JScrollPane nameTreeScroller = new JScrollPane(nameJTree); - nameTreeScroller.setPreferredSize(new Dimension(325, 225)); - - // ok / cancel layout. - okButton = new JButton(messageBundle.getString("viewer.button.ok.label")); - okButton.setMnemonic(messageBundle.getString("viewer.button.ok.mnemonic").charAt(0)); - okButton.addActionListener(this); - cancelButton = new JButton(messageBundle.getString("viewer.button.cancel.label")); - cancelButton.setMnemonic(messageBundle.getString("viewer.button.cancel.mnemonic").charAt(0)); - cancelButton.addActionListener(this); - // panel for OK and cancel - JPanel okCancelPanel = new JPanel(new FlowLayout()); - okCancelPanel.add(okButton); - okCancelPanel.add(cancelButton); - - JPanel nameTreePanel = new JPanel(); - nameTreePanel.setAlignmentY(JPanel.TOP_ALIGNMENT); - GridBagLayout layout = new GridBagLayout(); - nameTreePanel.setLayout(layout); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.EAST; - constraints.insets = new Insets(5, 5, 5, 5); - - constraints.anchor = GridBagConstraints.CENTER; - addGB(nameTreePanel, nameTreeScroller, 0, 0, 1, 1); - addGB(nameTreePanel, okCancelPanel, 0, 1, 1, 1); - - this.getContentPane().add(nameTreePanel); - -// pack(); - setSize(new Dimension(375, 350)); - validate(); - setLocationRelativeTo(controller.getViewerFrame()); - - } - - public void setDestinationName(JLabel destinationName) { - this.destinationName = destinationName; - } - - private void addGB(JPanel layout, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - layout.add(component, constraints); - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/NameTreeNode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/NameTreeNode.java deleted file mode 100644 index 80b8d4a694..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/NameTreeNode.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.NameNode; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.StringObject; - -import javax.swing.tree.DefaultMutableTreeNode; -import java.text.MessageFormat; -import java.util.List; -import java.util.ResourceBundle; - -/** - * Name tree node. - */ -@SuppressWarnings("serial") -public class NameTreeNode extends DefaultMutableTreeNode { - - // we can either be a intermediate node - private NameNode item; - // or a leaf node but not both. - private StringObject name; - private Reference reference; - - private ResourceBundle messageBundle; - private MessageFormat formatter; - - private boolean rootNode; - private boolean intermidiatNode; - private boolean leaf; - - private boolean loadedChildren; - - /** - * Creates a new instance of an OutlineItemTreeNode - * - * @param item Contains PDF Outline item data - * @param messageBundle ri root message bundle, localized node text. - */ - public NameTreeNode(NameNode item, ResourceBundle messageBundle) { - super(); - this.item = item; - this.messageBundle = messageBundle; - if (!item.hasLimits()) { - rootNode = true; - setUserObject(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.nameTree.root.label")); - } else { - intermidiatNode = true; - // setup a patterned message - Object[] messageArguments = { - item.getLowerLimit(), - item.getUpperLimit() - }; - if (formatter == null) { - formatter = new MessageFormat(messageBundle.getString( - "viewer.utilityPane.action.dialog.goto.nameTree.branch.label")); - } - setUserObject(formatter.format(messageArguments)); - } - } - - public NameTreeNode(StringObject name, Reference ref) { - super(); - leaf = true; - this.name = name; - this.reference = ref; - setUserObject(name); - } - - - public void recursivelyClearOutlineItems() { - item = null; - if (loadedChildren) { - int count = getChildCount(); - for (int i = 0; i < count; i++) { - NameTreeNode node = (NameTreeNode) getChildAt(i); - node.recursivelyClearOutlineItems(); - } - } - } - - public StringObject getName() { - return name; - } - - public Reference getReference() { - return reference; - } - - public boolean isRootNode() { - return rootNode; - } - - public boolean isIntermidiatNode() { - return intermidiatNode; - } - - public boolean isLeaf() { - return leaf; - } - - public void setRootNode(boolean rootNode) { - this.rootNode = rootNode; - } - - public int getChildCount() { - ensureChildrenLoaded(); - return super.getChildCount(); - } - - /** - * Only load children as needed, so don't have to load - * OutlineItems that the user has not even browsed to - */ - private void ensureChildrenLoaded() { - if (!loadedChildren && (intermidiatNode || rootNode)) { - loadedChildren = true; - - // look for any kids. - if (item.getKidsReferences() != null) { - int count = item.getKidsReferences().size(); - for (int i = 0; i < count; i++) { - NameNode child = item.getNode(i); - NameTreeNode childTreeNode = - new NameTreeNode(child, messageBundle); - add(childTreeNode); - } - } - // other wise we might have some leaf to add - if (item.getNamesAndValues() != null) { - List namesAndValues = item.getNamesAndValues(); - StringObject name; - Reference ref; - for (int i = 0, max = namesAndValues.size(); i < max; i += 2) { - name = (StringObject) namesAndValues.get(i); - ref = (Reference) namesAndValues.get(i + 1); - add(new NameTreeNode(name, ref)); - } - } - } - } -} - - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/SquareAnnotationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/SquareAnnotationPanel.java deleted file mode 100644 index b2f67e6fa1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/SquareAnnotationPanel.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.SquareAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * SquareAnnotationPanel is a configuration panel for changing the properties - * of a SquareAnnotationComponent and the underlying annotation component. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class SquareAnnotationPanel extends AnnotationPanelAdapter implements ItemListener, - ActionListener, ChangeListener { - - // default list values. - private static final int DEFAULT_LINE_THICKNESS = 0; - private static final int DEFAULT_LINE_STYLE = 0; - private static final int DEFAULT_STROKE_TYPE = 0; - private static final Color DEFAULT_BORDER_COLOR = Color.RED; - private static final int DEFAULT_FILL_TYPE = 1; - private static final Color DEFAULT_INTERIOR_COLOR = new Color(1, 1, 1); - - // Fill styles types. - private final ValueLabelItem[] PAINT_TYPE_LIST = new ValueLabelItem[]{ - new ValueLabelItem(Boolean.TRUE, "Visible"), - new ValueLabelItem(Boolean.FALSE, "Invisible")}; - - // link action appearance properties. - private JComboBox lineThicknessBox; - private JComboBox lineStyleBox; - private JComboBox fillTypeBox; - private JButton colorFillButton; - private JButton colorBorderButton; - private JSlider transparencySlider; - - private SquareAnnotation annotation; - - public SquareAnnotationPanel(SwingController controller) { - super(controller); - - setLayout(new GridBagLayout()); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - - /** - * Method that should be called when a new AnnotationComponent is selected by the user - * The associated object will be stored locally as currentAnnotation - * Then all of it's properties will be applied to the UI pane - * For example if the border was red, the color of the background button will - * be changed to red - * - * @param newAnnotation to set and apply to this UI - */ - public void setAnnotationComponent(AnnotationComponent newAnnotation) { - - if (newAnnotation == null || newAnnotation.getAnnotation() == null) { - setEnabled(false); - return; - } - // assign the new action instance. - this.currentAnnotationComponent = newAnnotation; - - // For convenience grab the Annotation object wrapped by the component - annotation = (SquareAnnotation) - currentAnnotationComponent.getAnnotation(); - - applySelectedValue(lineThicknessBox, annotation.getLineThickness()); - applySelectedValue(lineStyleBox, annotation.getLineStyle()); - applySelectedValue(fillTypeBox, annotation.isFillColor()); - setButtonBackgroundColor(colorBorderButton, annotation.getColor()); - setButtonBackgroundColor(colorFillButton, annotation.getFillColor()); - transparencySlider.setValue(Math.round(annotation.getOpacity() * 255)); - - // disable appearance input if we have a invisible rectangle - safeEnable(lineThicknessBox, true); - safeEnable(lineStyleBox, true); - safeEnable(colorFillButton, true); - safeEnable(fillTypeBox, true); - safeEnable(colorBorderButton, true); - safeEnable(transparencySlider, true); - - setStrokeFillColorButtons(); - } - - private void setStrokeFillColorButtons() { - SquareAnnotation squareAnnotation = (SquareAnnotation) - currentAnnotationComponent.getAnnotation(); - if (annotation.isFillColor()) { - setButtonBackgroundColor(colorFillButton, squareAnnotation.getFillColor()); - safeEnable(colorFillButton, true); - } else { - safeEnable(colorFillButton, false); - } - } - - public void itemStateChanged(ItemEvent e) { - ValueLabelItem item = (ValueLabelItem) e.getItem(); - if (e.getStateChange() == ItemEvent.SELECTED) { - if (e.getSource() == lineThicknessBox) { - annotation.getBorderStyle().setStrokeWidth((Float) item.getValue()); - } else if (e.getSource() == lineStyleBox) { - annotation.getBorderStyle().setBorderStyle((Name) item.getValue()); - } else if (e.getSource() == fillTypeBox) { - annotation.setFillColor((Boolean) item.getValue()); - setStrokeFillColorButtons(); - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == colorBorderButton) { - Color chosenColor = - JColorChooser.showDialog(colorBorderButton, - messageBundle.getString( - "viewer.utilityPane.annotation.square.colorBorderChooserTitle"), - colorBorderButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - setButtonBackgroundColor(colorBorderButton, chosenColor); - annotation.setColor(chosenColor); - } - } else if (e.getSource() == colorFillButton) { - Color chosenColor = - JColorChooser.showDialog(colorFillButton, - messageBundle.getString( - "viewer.utilityPane.annotation.square.colorInteriorChooserTitle"), - colorFillButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - setButtonBackgroundColor(colorFillButton, chosenColor); - annotation.setFillColor(chosenColor); - } - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - - public void stateChanged(ChangeEvent e) { - alphaSliderChange(e, annotation); - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - - // Create and setup an Appearance panel - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.square.appearance.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(1, 2, 1, 2); - - // Line thickness - lineThicknessBox = new JComboBox(LINE_THICKNESS_LIST); - lineThicknessBox.setSelectedIndex(DEFAULT_LINE_THICKNESS); - lineThicknessBox.addItemListener(this); - JLabel label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.square.lineThickness")); - addGB(this, label, 0, 0, 1, 1); - addGB(this, lineThicknessBox, 1, 0, 1, 1); - // Line style - lineStyleBox = new JComboBox(LINE_STYLE_LIST); - lineStyleBox.setSelectedIndex(DEFAULT_LINE_STYLE); - lineStyleBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.square.lineStyle")); - addGB(this, label, 0, 1, 1, 1); - addGB(this, lineStyleBox, 1, 1, 1, 1); - - // border colour - colorBorderButton = new JButton(" "); - colorBorderButton.addActionListener(this); - colorBorderButton.setOpaque(true); - colorBorderButton.setBackground(DEFAULT_BORDER_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.square.colorBorderLabel")); - addGB(this, label, 0, 2, 1, 1); - addGB(this, colorBorderButton, 1, 2, 1, 1); - - // fill type options - fillTypeBox = new JComboBox(VISIBLE_TYPE_LIST); - fillTypeBox.setSelectedIndex(DEFAULT_FILL_TYPE); - fillTypeBox.addItemListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.square.fillTypeLabel")); - addGB(this, label, 0, 3, 1, 1); - addGB(this, fillTypeBox, 1, 3, 1, 1); - - // interior colour - colorFillButton = new JButton(" "); - colorFillButton.addActionListener(this); - colorFillButton.setOpaque(true); - colorFillButton.setBackground(DEFAULT_INTERIOR_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.square.colorInteriorLabel")); - addGB(this, label, 0, 4, 1, 1); - addGB(this, colorFillButton, 1, 4, 1, 1); - - // transparency slider - transparencySlider = buildAlphaSlider(); - transparencySlider.setMajorTickSpacing(255); - transparencySlider.setPaintLabels(true); - transparencySlider.addChangeListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.square.transparencyLabel")); - addGB(this, label, 0, 5, 1, 1); - addGB(this, transparencySlider, 1, 5, 1, 1); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - - safeEnable(lineThicknessBox, enabled); - safeEnable(lineStyleBox, enabled); - safeEnable(fillTypeBox, enabled); - safeEnable(colorBorderButton, enabled); - safeEnable(colorFillButton, enabled); - safeEnable(transparencySlider, enabled); - } - - /** - * Convenience method to ensure a component is safe to toggle the enabled state on - * - * @param comp to toggle - * @param enabled the status to use - * @return true on success - */ - protected boolean safeEnable(JComponent comp, boolean enabled) { - if (comp != null) { - comp.setEnabled(enabled); - return true; - } - return false; - } - - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/TextAnnotationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/TextAnnotationPanel.java deleted file mode 100644 index 708123d6cf..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/TextAnnotationPanel.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.TextAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * TextAnnotationPanel is a configuration panel for changing the properties - * of a TextAnnotationComponent and the underlying annotation component. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class TextAnnotationPanel extends AnnotationPanelAdapter implements ItemListener, - ActionListener, ChangeListener { - - // default list values. - private static final int DEFAULT_ICON_NAME = 0; - private static final Color DEFAULT_COLOR = new Color(1f, 1f, 0f); - - // line thicknesses. - private static ValueLabelItem[] TEXT_ICON_LIST; - - // link action appearance properties. - private JComboBox iconNameBox; - private JButton colorButton; - private JSlider transparencySlider; - - private TextAnnotation annotation; - - public TextAnnotationPanel(SwingController controller) { - super(controller); - setLayout(new GridBagLayout()); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - /** - * Method that should be called when a new AnnotationComponent is selected by the user - * The associated object will be stored locally as currentAnnotation - * Then all of it's properties will be applied to the UI pane - * For example if the border was red, the color of the background button will - * be changed to red - * - * @param newAnnotation to set and apply to this UI - */ - public void setAnnotationComponent(AnnotationComponent newAnnotation) { - - if (newAnnotation == null || newAnnotation.getAnnotation() == null) { - setEnabled(false); - return; - } - // assign the new action instance. - this.currentAnnotationComponent = newAnnotation; - - // For convenience grab the Annotation object wrapped by the component - annotation = (TextAnnotation) - currentAnnotationComponent.getAnnotation(); - - applySelectedValue(iconNameBox, annotation.getIconName()); - setButtonBackgroundColor(colorButton, annotation.getColor()); - transparencySlider.setValue(Math.round(annotation.getOpacity() * 255)); - - // disable appearance input if we have a invisible rectangle - safeEnable(iconNameBox, true); - safeEnable(colorButton, true); - safeEnable(transparencySlider, true); - } - - public void itemStateChanged(ItemEvent e) { - ValueLabelItem item = (ValueLabelItem) e.getItem(); - if (e.getStateChange() == ItemEvent.SELECTED) { - if (e.getSource() == iconNameBox) { - annotation.setIconName((Name) item.getValue()); - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == colorButton) { - Color chosenColor = - JColorChooser.showDialog(colorButton, - messageBundle.getString("viewer.utilityPane.annotation.textMarkup.colorChooserTitle"), - colorButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - colorButton.setBackground(chosenColor); - annotation.setColor(chosenColor); - - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - } - - public void stateChanged(ChangeEvent e) { - alphaSliderChange(e, annotation); - } - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - if (TEXT_ICON_LIST == null) { - TEXT_ICON_LIST = new ValueLabelItem[]{ - new ValueLabelItem(TextAnnotation.COMMENT_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.comment")), - new ValueLabelItem(TextAnnotation.CHECK_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.check")), - new ValueLabelItem(TextAnnotation.CHECK_MARK_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.checkMark")), - new ValueLabelItem(TextAnnotation.CIRCLE_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.circle")), - new ValueLabelItem(TextAnnotation.CROSS_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.cross")), - new ValueLabelItem(TextAnnotation.CROSS_HAIRS_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.crossHairs")), - new ValueLabelItem(TextAnnotation.HELP_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.help")), - new ValueLabelItem(TextAnnotation.INSERT_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.insert")), - new ValueLabelItem(TextAnnotation.KEY_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.key")), - new ValueLabelItem(TextAnnotation.NEW_PARAGRAPH_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.newParagraph")), - new ValueLabelItem(TextAnnotation.PARAGRAPH_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.paragraph")), - new ValueLabelItem(TextAnnotation.RIGHT_ARROW_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.rightArrow")), - new ValueLabelItem(TextAnnotation.RIGHT_POINTER_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.rightPointer")), - new ValueLabelItem(TextAnnotation.STAR_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.star")), - new ValueLabelItem(TextAnnotation.UP_LEFT_ARROW_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.upLeftArrow")), - new ValueLabelItem(TextAnnotation.UP_ARROW_ICON, - messageBundle.getString("viewer.utilityPane.annotation.text.iconName.upArrow"))}; - } - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(1, 2, 1, 2); - - // Create and setup an Appearance panel - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.text.appearance.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - // Line thickness - iconNameBox = new JComboBox(TEXT_ICON_LIST); - iconNameBox.setSelectedIndex(DEFAULT_ICON_NAME); - iconNameBox.addItemListener(this); - JLabel label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.text.iconName")); - addGB(this, label, 0, 0, 1, 1); - addGB(this, iconNameBox, 1, 0, 1, 1); - // fill colour - colorButton = new JButton(" "); - colorButton.addActionListener(this); - colorButton.setOpaque(true); - colorButton.setBackground(DEFAULT_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.textMarkup.colorLabel")); - addGB(this, label, 0, 1, 1, 1); - addGB(this, colorButton, 1, 1, 1, 1); - // transparency slider - transparencySlider = buildAlphaSlider(); - transparencySlider.setMajorTickSpacing(255); - transparencySlider.setPaintLabels(true); - transparencySlider.addChangeListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.textMarkup.transparencyLabel")); - addGB(this, label, 0, 5, 1, 1); - addGB(this, transparencySlider, 1, 5, 1, 1); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - safeEnable(iconNameBox, enabled); - safeEnable(colorButton, enabled); - safeEnable(transparencySlider, enabled); - } - - /** - * Convenience method to ensure a component is safe to toggle the enabled state on - * - * @param comp to toggle - * @param enabled the status to use - * @return true on success - */ - protected boolean safeEnable(JComponent comp, boolean enabled) { - if (comp != null) { - comp.setEnabled(enabled); - return true; - } - return false; - } - - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/TextMarkupAnnotationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/TextMarkupAnnotationPanel.java deleted file mode 100644 index d152075600..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/TextMarkupAnnotationPanel.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.TextMarkupAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AnnotationComponent; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.ItemEvent; -import java.awt.event.ItemListener; - -/** - * TextAnnotationPanel is a configuration panel for changing the properties - * of a TextAnnotationComponent and the underlying annotation component. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class TextMarkupAnnotationPanel extends AnnotationPanelAdapter implements ItemListener, - ActionListener, ChangeListener { - - // default list values. - private static final int DEFAULT_TEXT_MARKUP_TYPE = 0; - private static final Color DEFAULT_BORDER_COLOR = Color.BLACK; - - // text markup sub types. - private static ValueLabelItem[] TEXT_MARKUP_TYPE_LIST; - - // text markup appearance properties. - private JComboBox textMarkupTypes; - private JButton colorButton; - private JSlider transparencySlider; - - private TextMarkupAnnotation annotation; - - public TextMarkupAnnotationPanel(SwingController controller) { - super(controller); - setLayout(new GridBagLayout()); - - // Setup the basics of the panel - setFocusable(true); - - // Add the tabbed pane to the overall panel - createGUI(); - - // Start the panel disabled until an action is clicked - setEnabled(false); - - revalidate(); - } - - /** - * Method that should be called when a new AnnotationComponent is selected by the user - * The associated object will be stored locally as currentAnnotation - * Then all of it's properties will be applied to the UI pane - * For example if the border was red, the color of the background button will - * be changed to red - * - * @param newAnnotation to set and apply to this UI - */ - public void setAnnotationComponent(AnnotationComponent newAnnotation) { - - if (newAnnotation == null || newAnnotation.getAnnotation() == null) { - setEnabled(false); - return; - } - // assign the new action instance. - this.currentAnnotationComponent = newAnnotation; - - // For convenience grab the Annotation object wrapped by the component - annotation = (TextMarkupAnnotation) - currentAnnotationComponent.getAnnotation(); - - applySelectedValue(textMarkupTypes, annotation.getSubType()); - setButtonBackgroundColor(colorButton, annotation.getTextMarkupColor()); - transparencySlider.setValue(Math.round(annotation.getOpacity() * 255)); - - // disable appearance input if we have a invisible rectangle - safeEnable(textMarkupTypes, true); - safeEnable(colorButton, true); - safeEnable(transparencySlider, true); - } - - public void itemStateChanged(ItemEvent e) { - ValueLabelItem item = (ValueLabelItem) e.getItem(); - if (e.getStateChange() == ItemEvent.SELECTED) { - if (e.getSource() == textMarkupTypes) { - annotation.setSubtype((Name) item.getValue()); - } - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == colorButton) { - Color chosenColor = - JColorChooser.showDialog(colorButton, - messageBundle.getString( - "viewer.utilityPane.annotation.textMarkup.colorChooserTitle"), - colorButton.getBackground()); - if (chosenColor != null) { - // change the colour of the button background - colorButton.setBackground(chosenColor); - annotation.setTextMarkupColor(chosenColor); - - // save the action state back to the document structure. - updateCurrentAnnotation(); - currentAnnotationComponent.resetAppearanceShapes(); - currentAnnotationComponent.repaint(); - } - } - } - - public void stateChanged(ChangeEvent e) { - alphaSliderChange(e, annotation); - } - - - /** - * Method to create link annotation GUI. - */ - private void createGUI() { - - // text markup types. - if (TEXT_MARKUP_TYPE_LIST == null) { - TEXT_MARKUP_TYPE_LIST = new ValueLabelItem[]{ - new ValueLabelItem(TextMarkupAnnotation.SUBTYPE_HIGHLIGHT, - "Highlight"), - new ValueLabelItem(TextMarkupAnnotation.SUBTYPE_STRIKE_OUT, - "Strikeout"), - new ValueLabelItem(TextMarkupAnnotation.SUBTYPE_UNDERLINE, - "Underline")}; - } - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(1, 2, 1, 2); - - // Create and setup an Appearance panel - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.utilityPane.annotation.textMarkup.appearance.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - // Text markup type - textMarkupTypes = new JComboBox(TEXT_MARKUP_TYPE_LIST); - textMarkupTypes.setSelectedIndex(DEFAULT_TEXT_MARKUP_TYPE); - textMarkupTypes.addItemListener(this); - JLabel label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.textMarkup.highlightType")); - addGB(this, label, 0, 0, 1, 1); - addGB(this, textMarkupTypes, 1, 0, 1, 1); - - // border colour - colorButton = new JButton(" "); - colorButton.addActionListener(this); - colorButton.setOpaque(true); - colorButton.setBackground(DEFAULT_BORDER_COLOR); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.textMarkup.colorLabel")); - addGB(this, label, 0, 2, 1, 1); - addGB(this, colorButton, 1, 2, 1, 1); - - // transparency slider - transparencySlider = buildAlphaSlider(); - transparencySlider.setMajorTickSpacing(255); - transparencySlider.setPaintLabels(true); - transparencySlider.addChangeListener(this); - label = new JLabel(messageBundle.getString("viewer.utilityPane.annotation.textMarkup.transparencyLabel")); - addGB(this, label, 0, 3, 1, 1); - addGB(this, transparencySlider, 1, 3, 1, 1); - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - - safeEnable(textMarkupTypes, enabled); - safeEnable(colorButton, enabled); - safeEnable(transparencySlider, enabled); - } - - /** - * Convenience method to ensure a component is safe to toggle the enabled state on - * - * @param comp to toggle - * @param enabled the status to use - * @return true on success - */ - protected boolean safeEnable(JComponent comp, boolean enabled) { - if (comp != null) { - comp.setEnabled(enabled); - return true; - } - return false; - } - - private void applySelectedValue(JComboBox comboBox, Object value) { - comboBox.removeItemListener(this); - ValueLabelItem currentItem; - for (int i = 0; i < comboBox.getItemCount(); i++) { - currentItem = (ValueLabelItem) comboBox.getItemAt(i); - if (currentItem.getValue().equals(value)) { - comboBox.setSelectedIndex(i); - break; - } - } - comboBox.addItemListener(this); - } - -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/ValueLabelItem.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/ValueLabelItem.java deleted file mode 100644 index 290cd6b04f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/annotation/ValueLabelItem.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.annotation; - -/** - * Class to associate with a JComboBox - * Used to allow us to display different text to the user than we set in the backend - * - * @since 5.0 - */ -public class ValueLabelItem { - private Object value; - private String label; - - public ValueLabelItem(Object value, String label) { - this.value = value; - this.label = label; - } - - public Object getValue() { - return value; - } - - public void setValue(Object value) { - this.value = value; - } - - public String getLabel() { - return label; - } - - public void setLabel(String label) { - this.label = label; - } - - public String toString() { - return label; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/attachment/AttachmentPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/attachment/AttachmentPanel.java deleted file mode 100644 index 41a2824b51..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/attachment/AttachmentPanel.java +++ /dev/null @@ -1,287 +0,0 @@ -package org.icepdf.ri.common.utility.attachment; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.ViewModel; -import org.icepdf.ri.images.Images; -import org.icepdf.ri.viewer.WindowManager; - -import javax.swing.*; -import javax.swing.table.TableModel; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.io.*; -import java.net.MalformedURLException; -import java.util.HashMap; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; - -import static org.icepdf.ri.common.utility.attachment.FileTableModel.*; - -/** - * AttachmentPanel displays a PDF attachments as defined by the Catalogs names tree's EmbeddedFiles entry. - * The view is pretty straight forward showing properties on all attached files but only allows the opening - * of .pdf files via a double click of a row. However it is possible to save any file by selecting a table - * row and right clicking to expose the context menu for 'Save as..." - * - * @since 6.2 - */ -@SuppressWarnings("serial") -public class AttachmentPanel extends JPanel implements MouseListener, ActionListener { - - private static final Logger logger = - Logger.getLogger(AttachmentPanel.class.toString()); - - public static final String PDF_EXTENSION = ".pdf"; - - private SwingController controller; - private Document currentDocument; - - private JTable fileTable; - private FileTableModel fileTableModel; - private JPopupMenu contextMenu; - private JMenuItem saveAsMenuItem; - private HashMap files; - - // message bundle for internationalization - private ResourceBundle messageBundle; - - public AttachmentPanel(SwingController controller) { - this.controller = controller; - this.setFocusable(true); - this.messageBundle = this.controller.getMessageBundle(); - } - - private void buildUI() { - fileTableModel = new FileTableModel(messageBundle, files); - fileTable = new JTable(fileTableModel) { - // Implement table cell tool tips. - public String getToolTipText(MouseEvent e) { - String tip = null; - java.awt.Point p = e.getPoint(); - int rowIndex = rowAtPoint(p); - int colIndex = columnAtPoint(p); - int realColumnIndex = convertColumnIndexToModel(colIndex); - if (realColumnIndex == NAME_COLUMN) { - TableModel model = getModel(); - tip = (String) model.getValueAt(rowIndex, NAME_COLUMN); - } else if (realColumnIndex == DESCRIPTION_COLUMN) { - TableModel model = getModel(); - tip = (String) model.getValueAt(rowIndex, DESCRIPTION_COLUMN); - } else if (realColumnIndex == MODIFIED_COLUMN) { - TableModel model = getModel(); - tip = model.getValueAt(rowIndex, MODIFIED_COLUMN).toString(); - } else if (realColumnIndex == SIZE_COLUMN) { - TableModel model = getModel(); - tip = model.getValueAt(rowIndex, SIZE_COLUMN).toString(); - } else if (realColumnIndex == COMPRESSION_COLUMN) { - TableModel model = getModel(); - tip = model.getValueAt(rowIndex, COMPRESSION_COLUMN).toString(); - } else { - tip = super.getToolTipText(e); - } - return tip; - } - }; - fileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - // try and show all the file name label. - fileTable.getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(225); - fileTable.getColumnModel().getColumn(DESCRIPTION_COLUMN).setPreferredWidth(50); - fileTable.getColumnModel().getColumn(MODIFIED_COLUMN).setPreferredWidth(75); - fileTable.getColumnModel().getColumn(SIZE_COLUMN).setPreferredWidth(75); - fileTable.getColumnModel().getColumn(COMPRESSION_COLUMN).setPreferredWidth(75); - // add double click support for row, so we can load the file if it's pdf. - fileTable.addMouseListener(this); - // right click context menu for save as. - contextMenu = new JPopupMenu(); - saveAsMenuItem = new JMenuItem(messageBundle.getString( - "viewer.utilityPane.attachments.menu.saveAs.label"), - new ImageIcon(Images.get("save_a_24.png"))); - saveAsMenuItem.addActionListener(this); - contextMenu.add(saveAsMenuItem); - - // remove any previous UI components. - this.setLayout(new BorderLayout()); - JScrollPane scrollPane = new JScrollPane(fileTable, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - scrollPane.getVerticalScrollBar().setUnitIncrement(20); - scrollPane.getHorizontalScrollBar().setUnitIncrement(20); - this.add(scrollPane, BorderLayout.CENTER); - } - - public void dispose() { - this.removeAll(); - } - - /** - * Sets the given document as the current and builds the embedded file table is possible. - * - * @param document document to look for attached files and build table based UI from. - */ - public void setDocument(Document document) { - this.currentDocument = document; - this.removeAll(); - files = null; - fileTableModel = null; - if (this.currentDocument != null) { - Catalog catalog = document.getCatalog(); - // grab each file pair and build out the FileSpecification objects. - if (catalog.getEmbeddedFilesNameTree() != null) { - NameTree embeddedFilesNameTree = catalog.getEmbeddedFilesNameTree(); - java.util.List filePairs = embeddedFilesNameTree.getNamesAndValues(); - if (filePairs != null) { - Library library = catalog.getLibrary(); - // check to see if at least one file is a PDF. - int max = filePairs.size(); - files = new HashMap(max / 2); - for (int i = 0; i < max; i += 2) { - // get the name and document for - // file name and file specification pairs. - Object rawFileName = library.getObject(filePairs.get(i)); - Object rawFileProperties = library.getObject(filePairs.get(i + 1)); - if (rawFileName != null && rawFileName instanceof LiteralStringObject && - rawFileProperties != null && rawFileProperties instanceof HashMap) { - String fileName = Utils.convertStringObject(library, (LiteralStringObject) rawFileName); - files.put(fileName, new FileSpecification(library, (HashMap) rawFileProperties)); - } - } - buildUI(); - } - } - } - } - - public void actionPerformed(ActionEvent e) { - // show save as dialog and try to save the file stream. - if (e.getSource().equals(saveAsMenuItem)) { - int selectedRow = fileTable.getSelectedRow(); - Object value = fileTableModel.getValueAt(selectedRow, DATA_COLUMN); - if (value != null && value instanceof FileSpecification) { - FileSpecification fileSpecification = (FileSpecification) value; - final EmbeddedFileStream embeddedFileStream = fileSpecification.getEmbeddedFileStream(); - final String fileName = (String) fileTableModel.getValueAt(selectedRow, NAME_COLUMN); - // already on awt thread but still nice to play by the rules. - Runnable doSwingWork = new Runnable() { - public void run() { - saveFile(fileName, embeddedFileStream); - } - }; - SwingUtilities.invokeLater(doSwingWork); - } - } - } - - public void mouseClicked(MouseEvent e) { - // try and do double click file opening of PDF documents. - if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { - int selectedRow = fileTable.getSelectedRow(); - Object value = fileTableModel.getValueAt(selectedRow, DATA_COLUMN); - if (value != null && value instanceof FileSpecification) { - FileSpecification fileSpecification = (FileSpecification) value; - EmbeddedFileStream embeddedFileStream = fileSpecification.getEmbeddedFileStream(); - String fileName = (String) fileTableModel.getValueAt(selectedRow, NAME_COLUMN); - // load the file stream if it's PDF. - if (fileName.toLowerCase().endsWith(PDF_EXTENSION)) { - try { - InputStream fileInputStream = embeddedFileStream.getDecodedStreamData(); - Document embeddedDocument = new Document(); - embeddedDocument.setInputStream(fileInputStream, fileName); - WindowManager.getInstance().newWindow(embeddedDocument, fileName); - } catch (Throwable e1) { - logger.log(Level.WARNING, "Error opening PDF " + fileName, e); - } - } - } - } - if (e.getButton() == MouseEvent.BUTTON3 || e.getButton() == MouseEvent.BUTTON2) { - int row = fileTable.rowAtPoint(e.getPoint()); - // if pointer is over a selected row, show popup - if (fileTable.isRowSelected(row)) { - contextMenu.show(e.getComponent(), e.getX(), e.getY()); - } - } - } - - public void mousePressed(MouseEvent e) { - - } - - public void mouseReleased(MouseEvent e) { - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - /** - * Utility method to save the embedded file stream as a separate file. Any file can be saved not just - * limited to PDF. - * - * @param fileName filename associated with he embedded file stream. - * @param embeddedFileStream embedded file stream data to save. . - */ - private void saveFile(String fileName, EmbeddedFileStream embeddedFileStream) { - - // Create and display a file saving dialog - final JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle(messageBundle.getString("viewer.dialog.saveAs.title")); - fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); - // set the directory to our currently set default. - if (ViewModel.getDefaultFile() != null) { - fileChooser.setCurrentDirectory(ViewModel.getDefaultFile()); - } - // set the file name. - fileChooser.setSelectedFile(new File(fileName)); - // show the dialog - int returnVal = fileChooser.showSaveDialog(controller.getViewerFrame()); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fileChooser.getSelectedFile(); - if (file.exists()) { - boolean overWrite = org.icepdf.ri.util.Resources.showConfirmDialog( - controller.getViewerFrame(), - messageBundle, - "viewer.utilityPane.attachments.saveAs.replace.title", - "viewer.utilityPane.attachments.saveAs.replace.msg", - fileName); - if (!overWrite) { - // ask again. - saveFile(fileName, embeddedFileStream); - } - } - // save file stream - try { - InputStream inputStream = embeddedFileStream.getDecodedStreamData(); - FileOutputStream fileOutputStream = new FileOutputStream(file); - BufferedOutputStream buf = new BufferedOutputStream(fileOutputStream, 8192); - byte[] buffer = new byte[8192]; - int length; - while ((length = inputStream.read(buffer)) > 0) { - buf.write(buffer, 0, length); - } - buf.flush(); - fileOutputStream.flush(); - buf.close(); - fileOutputStream.close(); - inputStream.close(); - } catch (MalformedURLException e) { - logger.log(Level.FINE, "Malformed URL Exception ", e); - } catch (IOException e) { - logger.log(Level.FINE, "IO Exception ", e); - } - // save the default directory - ViewModel.setDefaultFile(file); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/attachment/FileTableModel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/attachment/FileTableModel.java deleted file mode 100644 index 2ea479b171..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/attachment/FileTableModel.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.icepdf.ri.common.utility.attachment; - -import org.icepdf.core.pobjects.EmbeddedFileStream; -import org.icepdf.core.pobjects.FileSpecification; -import org.icepdf.core.util.Utils; - -import javax.swing.table.AbstractTableModel; -import java.util.HashMap; -import java.util.ResourceBundle; -import java.util.Set; - -/** - * Table model for displaying file data using the following columns: name, description, modified, size and - * compressed size. - * - * @since 6.2 - */ -@SuppressWarnings("serial") -public class FileTableModel extends AbstractTableModel { - - public static final int NAME_COLUMN = 0; - public static final int DESCRIPTION_COLUMN = 1; - public static final int MODIFIED_COLUMN = 2; - public static final int SIZE_COLUMN = 3; - public static final int COMPRESSION_COLUMN = 4; - public static final int DATA_COLUMN = 5; - - private String[] columnNames; - private Object[][] data; - - public FileTableModel(ResourceBundle messageBundle, HashMap files) { - - // build the headers. - columnNames = new String[]{ - messageBundle.getString("viewer.utilityPane.attachments.column.fileName.title"), - messageBundle.getString("viewer.utilityPane.attachments.column.description.title"), - messageBundle.getString("viewer.utilityPane.attachments.column.modified.title"), - messageBundle.getString("viewer.utilityPane.attachments.column.size.title"), - messageBundle.getString("viewer.utilityPane.attachments.column.compressedSize.title"), - }; - - // build the column data. - if (files != null) { - Set keys = files.keySet(); - int rows = keys.size(); - int columns = 6; - data = new Object[rows][columns]; - int i = 0; - for (String key : keys) { - FileSpecification fileSpecification = files.get(key); - EmbeddedFileStream embeddedFileStream = fileSpecification.getEmbeddedFileStream(); - data[i][NAME_COLUMN] = fileSpecification.getUnicodeFileSpecification() != null ? - fileSpecification.getUnicodeFileSpecification() : fileSpecification.getFileSpecification() != null ? - fileSpecification.getFileSpecification() : ""; - data[i][DESCRIPTION_COLUMN] = fileSpecification.getDescription() != null ? - fileSpecification.getDescription() : ""; - data[i][MODIFIED_COLUMN] = embeddedFileStream.getParamLastModifiedData() != null ? - embeddedFileStream.getParamLastModifiedData() : ""; - data[i][SIZE_COLUMN] = Utils.byteFormatter(embeddedFileStream.getParamUncompressedSize(), true); - data[i][COMPRESSION_COLUMN] = Utils.byteFormatter(embeddedFileStream.getCompressedSize(), true); - data[i][DATA_COLUMN] = fileSpecification; - i++; - } - } - } - - public int getColumnCount() { - return columnNames.length; - } - - public int getRowCount() { - return data.length; - } - - public String getColumnName(int col) { - return columnNames[col]; - } - - public Object getValueAt(int row, int col) { - return data[row][col]; - } - - public Class getColumnClass(int c) { - return getValueAt(0, c).getClass(); - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/layers/LayersPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/layers/LayersPanel.java deleted file mode 100644 index 575164fa9e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/layers/LayersPanel.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.layers; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.OptionalContent; -import org.icepdf.core.pobjects.OptionalContentGroup; -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AbstractDocumentView; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import javax.swing.*; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; -import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.List; -import java.util.ResourceBundle; - -/** - * LayersPanel contains a LayersTree for manipulation of the PDF's optional - * content if present. The panel should only be enabled if the the Document's - * catalog contains a OCProperties entry. - */ -@SuppressWarnings("serial") -public class LayersPanel extends JPanel { - - protected DocumentViewController documentViewController; - - protected Document currentDocument; - - private SwingController controller; - - protected LayersTreeNode nodes; - protected DocumentViewModel documentViewModel; - // message bundle for internationalization - ResourceBundle messageBundle; - - public LayersPanel(SwingController controller) { - super(true); - setFocusable(true); - this.controller = controller; - this.messageBundle = this.controller.getMessageBundle(); - } - - private void buildUI() { - - JTree tree = new LayersTree(nodes); - tree.setShowsRootHandles(true); - tree.setRootVisible(false); - tree.addMouseListener(new NodeSelectionListener(tree)); - - this.setLayout(new BorderLayout()); - JScrollPane scrollPane = new JScrollPane(tree, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - scrollPane.getVerticalScrollBar().setUnitIncrement(20); - scrollPane.getHorizontalScrollBar().setUnitIncrement(20); - this.add(scrollPane, - BorderLayout.CENTER); - } - - public void setDocument(Document document) { - this.currentDocument = document; - documentViewController = controller.getDocumentViewController(); - documentViewModel = documentViewController.getDocumentViewModel(); - - if (this.currentDocument != null) { - OptionalContent optionalContent = currentDocument.getCatalog().getOptionalContent(); - List layersOrder = optionalContent.getOrder(); - if (layersOrder != null) { - // check for radio buttons - boolean hasRadioButtons = optionalContent.getRbGroups() != null - && optionalContent.getRbGroups().size() > 0; - - nodes = new LayersTreeNode("Layers"); - nodes.setAllowsChildren(true); - buildTree(layersOrder, nodes, hasRadioButtons); - buildUI(); - } - } else { - // tear down the old container. - this.removeAll(); - } - } - - @SuppressWarnings("unchecked") - public void buildTree(List layersOrder, LayersTreeNode parent, boolean radioGroup) { - - LayersTreeNode tmp = null; - boolean selected = true; - // tod recursive build with parent checking. - for (Object obj : layersOrder) { - if (obj instanceof List) { - LayersTreeNode newParent; - if (parent.getChildCount() > 0) { - newParent = (LayersTreeNode) parent.getLastChild(); - } else { - newParent = parent; - } - buildTree((List) obj, newParent, radioGroup); - } else if (obj instanceof String) { - // sets the node as selected if children are all selected. - if (tmp != null && selected) { - tmp.setSelected(true); - } - tmp = new LayersTreeNode(obj); - tmp.setAllowsChildren(true); - nodes.add(tmp); - selected = true; - } else if (obj instanceof OptionalContentGroup) { - LayersTreeNode node = new LayersTreeNode(obj); - node.setAllowsChildren(true); - if (radioGroup) { - node.setSelectionMode(LayersTreeNode.RADIO_SELECTION); - } - parent.add(node); - // check for an unselected state, goal is to select the parent - // if all children are selected. - if (!node.isSelected()) { - selected = false; - } - } - } - } - - - public void dispose() { - this.removeAll(); - } - - - class NodeSelectionListener extends MouseAdapter { - JTree tree; - - NodeSelectionListener(JTree tree) { - this.tree = tree; - } - - public void mouseClicked(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - int row = tree.getRowForLocation(x, y); - TreePath path = tree.getPathForRow(row); - if (path != null) { - LayersTreeNode node = (LayersTreeNode) path.getLastPathComponent(); - boolean isSelected = !(node.isSelected()); - node.setSelected(isSelected); - // the current page and repaint - List pages = documentViewModel.getPageComponents(); - AbstractPageViewComponent page = pages.get(documentViewModel.getViewCurrentPageIndex()); - // resort page text as layer visibility will have changed. - try { - page.getPage().getText().sortAndFormatText(); - } catch (InterruptedException e1) { - // silent running for now. - } - // fire change event. - ((AbstractDocumentView)documentViewController.getDocumentView()).firePropertyChange( - PropertyConstants.DOCUMENT_VIEW_REFRESH_CHANGE, false, true); - // repaint the page. - page.repaint(); - // repaint the tree so the checkbox states are show correctly. - tree.repaint(); - ((DefaultTreeModel) tree.getModel()).nodeChanged(node); - if (row == 0) { - tree.revalidate(); - tree.repaint(); - } - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/layers/LayersTree.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/layers/LayersTree.java deleted file mode 100644 index 4dc16f3d2d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/layers/LayersTree.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.layers; - -import javax.swing.*; -import javax.swing.plaf.ColorUIResource; -import javax.swing.tree.TreeCellRenderer; -import javax.swing.tree.TreeNode; -import javax.swing.tree.TreeSelectionModel; -import java.awt.*; - -/** - * LayersTree provides a UI interface for manipulating optional content - * that maybe specified in a document. The LayersTree stores LayersTreeNodes - * which when selected directly affect the visibility of the named layer. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class LayersTree extends JTree { - - public LayersTree(TreeNode root) { - super(root); - setCellRenderer(new CheckBoxRenderer()); - getSelectionModel().setSelectionMode( - TreeSelectionModel.SINGLE_TREE_SELECTION); - setRootVisible(true); - setScrollsOnExpand(true); - // old font was Arial with is no go for linux. - setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 13)); - setRowHeight(18); - } -} - -@SuppressWarnings("serial") -class CheckBoxRenderer extends JPanel implements TreeCellRenderer { - - protected JCheckBox checkBox; - protected TreeLabel treeLabel; - - public CheckBoxRenderer() { - setLayout(null); - add(checkBox = new JCheckBox()); - add(treeLabel = new TreeLabel()); - checkBox.setBackground(UIManager.getColor("Tree.textBackground")); - treeLabel.setForeground(UIManager.getColor("Tree.textForeground")); - } - - public Component getTreeCellRendererComponent(JTree tree, Object value, - boolean isSelected, boolean expanded, - boolean leaf, int row, boolean hasFocus) { - String stringValue = tree.convertValueToText(value, isSelected, - expanded, leaf, row, hasFocus); - setEnabled(tree.isEnabled()); - if (value instanceof LayersTreeNode) { - checkBox.setSelected(((LayersTreeNode) value).isSelected()); - } - treeLabel.setFont(tree.getFont()); - treeLabel.setText(stringValue); - treeLabel.setSelected(isSelected); - treeLabel.setFocus(hasFocus); - return this; - } - - public Dimension getPreferredSize() { - Dimension d_check = checkBox.getPreferredSize(); - Dimension d_label = treeLabel.getPreferredSize(); - return new Dimension(d_check.width + d_label.width, - (d_check.height < d_label.height ? - d_label.height : d_check.height)); - } - - public void doLayout() { - Dimension dCheck = checkBox.getPreferredSize(); - Dimension dLabel = treeLabel.getPreferredSize(); - int yCheck = 0; - int yLabel = 0; - if (dCheck.height < dLabel.height) { - yCheck = (dLabel.height - dCheck.height) / 2; - } else { - yLabel = (dCheck.height - dLabel.height) / 2; - } - checkBox.setLocation(0, yCheck); - checkBox.setBounds(0, yCheck, dCheck.width, dCheck.height); - treeLabel.setLocation(dCheck.width, yLabel); - treeLabel.setBounds(dCheck.width, yLabel, dLabel.width, dLabel.height); - } - - - public void setBackground(Color color) { - if (color instanceof ColorUIResource) - color = null; - super.setBackground(color); - } - - - public class TreeLabel extends JLabel { - boolean isSelected; - boolean hasFocus; - - public TreeLabel() { - } - - public void setBackground(Color color) { - if (color instanceof ColorUIResource) - color = null; - super.setBackground(color); - } - - public void paint(Graphics g) { - String str; - if ((str = getText()) != null) { - if (0 < str.length()) { - if (isSelected) { - g.setColor(UIManager.getColor("Tree.selectionBackground")); - } else { - g.setColor(UIManager.getColor("Tree.textBackground")); - } - Dimension d = getPreferredSize(); - int imageOffset = 0; - Icon currentI = getIcon(); - if (currentI != null) { - imageOffset = currentI.getIconWidth() + Math.max(0, getIconTextGap() - 1); - } - g.fillRect(imageOffset, 0, d.width - 1 - imageOffset, d.height); - if (hasFocus) { - g.setColor(UIManager.getColor("Tree.selectionBorderColor")); - g.drawRect(imageOffset, 0, d.width - 1 - imageOffset, d.height - 1); - } - } - } - super.paint(g); - } - - public Dimension getPreferredSize() { - Dimension retDimension = super.getPreferredSize(); - if (retDimension != null) { - retDimension = new Dimension(retDimension.width + 3, - retDimension.height); - } - return retDimension; - } - - public void setSelected(boolean isSelected) { - this.isSelected = isSelected; - } - - public void setFocus(boolean hasFocus) { - this.hasFocus = hasFocus; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/layers/LayersTreeNode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/layers/LayersTreeNode.java deleted file mode 100644 index 07b26bef8b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/layers/LayersTreeNode.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.layers; - -import org.icepdf.core.pobjects.OptionalContentGroup; - -import javax.swing.tree.DefaultMutableTreeNode; -import java.util.Enumeration; - -/** - * The LayersTreeNode represent a group of optional content members or just - * one optional content group. The user object for this DefaultMutableTreeNode - * must always be of type OptionalContentGroup. The OptionalContentGroup object - * is a reference to the OptionalContentGroup in the document's dictionary - * and any visibility changes will be reflected in the next Page paint. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class LayersTreeNode extends DefaultMutableTreeNode { - - /** - * Node selection is independent of other nodes. - */ - public final static int SINGLE_SELECTION = 1; - - /** - * Nodes behave like radio check boxes where only one can be selected - * at a time. - */ - public final static int RADIO_SELECTION = 2; - - protected int selectionMode = SINGLE_SELECTION; - - public LayersTreeNode(Object object) { - OptionalContentGroup optionalContentGroup = null; - if (object instanceof String) { - optionalContentGroup = new OptionalContentGroup((String) object, false); - } else if (object instanceof OptionalContentGroup) { - optionalContentGroup = (OptionalContentGroup) object; - } - setUserObject(optionalContentGroup); - } - - public LayersTreeNode(OptionalContentGroup optionalContentGroup) { - this(optionalContentGroup, true); - setUserObject(optionalContentGroup); - } - - public LayersTreeNode(Object userObject, boolean allowsChildren) { - super(userObject, allowsChildren); - } - - public void setSelectionMode(int mode) { - selectionMode = mode; - } - - public int getSelectionMode() { - return selectionMode; - } - - public OptionalContentGroup getOptionalContentGroup() { - return (OptionalContentGroup) getUserObject(); - } - - public void setSelected(boolean isSelected) { - ((OptionalContentGroup) getUserObject()).setVisible(isSelected); - - // if the node is a branch (has children), propagate the selection - // in to the child notes. - if ((selectionMode == SINGLE_SELECTION) - && (children != null)) { - LayersTreeNode layerNode; - for (Object child : children) { - layerNode = (LayersTreeNode) child; - layerNode.setSelected(isSelected); - } - } - // only one node cn be selected at one. - else if (selectionMode == RADIO_SELECTION) { - // deselect other nodes. - Enumeration children = parent.children(); - if (children != null) { - LayersTreeNode layerNode; - while (children.hasMoreElements()) { - layerNode = (LayersTreeNode) children.nextElement(); - if (!layerNode.equals(this)) { - layerNode.getOptionalContentGroup().setVisible(false); - } - } - } - - } - - } - - public boolean isSelected() { - return ((OptionalContentGroup) getUserObject()).isVisible(); - } - - @Override - public String toString() { - return ((OptionalContentGroup) getUserObject()).getName(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/outline/OutlineItemTreeNode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/outline/OutlineItemTreeNode.java deleted file mode 100644 index 490d157c94..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/outline/OutlineItemTreeNode.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.outline; - -import org.icepdf.core.pobjects.OutlineItem; - -import javax.swing.tree.DefaultMutableTreeNode; - -/** - * A PDF document may optionally display a document outline on the screen, - * allowing the user to navigate interactively from one part of the document to - * another. The outline consists of a tree-structured hierarchy of outline - * items (sometimes called bookmarks), which serve as a "visual table of - * contents" to display the document's structure to the user. The user can - * interactively open and close individual items by clicking them with the - * mouse. When an item is open, its immediate children in the hierarchy become - * visible on the screen; each child may in turn be open or closed, selectively - * revealing or hiding further parts of the hierarchy. When an item is closed, - * all of its descendants in the hierarchy are hidden. Clicking the text of any - * visible item with the mouse activates the item, causing the viewer - * application to jump to a destination or trigger an action associated with - * the item. - * An OutlineItemTreeNode object represents the bookmarks or leaves which makes up - * the actual Outline JTree. - */ -@SuppressWarnings("serial") -public class OutlineItemTreeNode extends DefaultMutableTreeNode { - private OutlineItem item; - private boolean loadedChildren; - - /** - * Creates a new instance of an OutlineItemTreeNode - * - * @param item Contains PDF Outline item data - */ - public OutlineItemTreeNode(OutlineItem item) { - super(); - this.item = item; - loadedChildren = false; - - // build the tree - setUserObject(item.getTitle()); - } - - public OutlineItem getOutlineItem() { - return item; - } - - public void recursivelyClearOutlineItems() { - item = null; - if (loadedChildren) { - int count = getChildCount(); - for (int i = 0; i < count; i++) { - OutlineItemTreeNode node = (OutlineItemTreeNode) getChildAt(i); - node.recursivelyClearOutlineItems(); - } - } - } - - public int getChildCount() { - ensureChildrenLoaded(); - return super.getChildCount(); - } - - /** - * Only load children as needed, so don't have to load - * OutlineItems that the user has not even browsed to - */ - private void ensureChildrenLoaded() { - if (!loadedChildren) { - loadedChildren = true; - - int count = item.getSubItemCount(); - for (int i = 0; i < count; i++) { - OutlineItem child = item.getSubItem(i); - OutlineItemTreeNode childTreeNode = new OutlineItemTreeNode(child); - add(childTreeNode); - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/outline/OutlinesTree.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/outline/OutlinesTree.java deleted file mode 100644 index 2d3a175b71..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/outline/OutlinesTree.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.outline; - -import org.icepdf.ri.images.Images; - -import javax.swing.*; -import javax.swing.text.Position; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.TreePath; -import javax.swing.tree.TreeSelectionModel; - -/** - * OutlinesTree is a JTree derivative whose nodes are OutlineItemTreeNode objects, - * each of which refers to an OutlineItem - * - * @author Mark Collette - * @see OutlineItemTreeNode - * @see org.icepdf.core.pobjects.OutlineItem - * @since 2.0 - */ -@SuppressWarnings("serial") -public class OutlinesTree extends JTree { - public OutlinesTree() { - getSelectionModel().setSelectionMode( - TreeSelectionModel.SINGLE_TREE_SELECTION); - // change the look & feel of the jtree - DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); - renderer.setOpenIcon(new ImageIcon(Images.get("page.gif"))); - renderer.setClosedIcon(new ImageIcon(Images.get("page.gif"))); - renderer.setLeafIcon(new ImageIcon(Images.get("page.gif"))); - setCellRenderer(renderer); - - setModel(null); - setRootVisible(true); - setScrollsOnExpand(true); - // old font was Arial with is no go for linux. - setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 13)); - setRowHeight(18); - } - - public TreePath getNextMatch(String prefix, int startingRow, Position.Bias bias) { - // this method body is the same as JTree's implementation but has a check - // for null text object, which causes a null pointer error in JDK 1.4 - int max = getRowCount(); - if (prefix == null) { - throw new IllegalArgumentException(); - } - if (startingRow < 0 || startingRow >= max) { - throw new IllegalArgumentException(); - } - prefix = prefix.toUpperCase(); - - // start search from the next/previous element from the - // selected element - int increment = (bias == Position.Bias.Forward) ? 1 : -1; - int row = startingRow; - do { - TreePath path = getPathForRow(row); - String text = convertValueToText( - path.getLastPathComponent(), isRowSelected(row), - isExpanded(row), true, row, false); - - // Added check for null text to avoid nasty output - if (text != null && text.toUpperCase().startsWith(prefix)) { - return path; - } - row = (row + increment + max) % max; - } while (row != startingRow); - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/search/SearchPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/search/SearchPanel.java deleted file mode 100644 index 1a52a965fe..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/search/SearchPanel.java +++ /dev/null @@ -1,823 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.search; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.graphics.text.LineText; -import org.icepdf.core.pobjects.graphics.text.WordText; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.DocumentViewModelImpl; -import org.icepdf.ri.images.Images; -import org.icepdf.ri.util.SearchTextTask; - -import javax.swing.*; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.text.ChoiceFormat; -import java.text.Format; -import java.text.MessageFormat; -import java.util.List; -import java.util.ResourceBundle; - -/** - * This class is the GUI component for the SearchTextTask. This panel can be - * added to a utility panel. The GUI allows users to - * type in a search string and displays a JList of all the pages that have results. - * Each list item can be selected, and when selected, the viewer will show the - * corresponding page. - * - * @since 1.1 - */ -@SuppressWarnings("serial") -public class SearchPanel extends JPanel implements ActionListener, - TreeSelectionListener { - - // markup for search context. - private static final String HTML_TAG_START = ""; - private static final String HTML_TAG_END = ""; - private static final String BOLD_TAG_START = ""; - private static final String BOLD_TAG_END = ""; - - // layouts constraint - private GridBagConstraints constraints; - // input for a search pattern - private JTextField searchTextField; - // pointer to document which will be searched - private Document document; - private SwingController controller; - - // tree view of the groups and panels - //private ResultsTree resultsTree; - - // list box to hold search results - private JTree tree; - private DefaultMutableTreeNode rootTreeNode; - private DefaultTreeModel treeModel; - // search start button - private JButton searchButton; - // clear search - private JButton clearSearchButton; - // search option check boxes. - private JCheckBox caseSensitiveCheckbox; - private JCheckBox wholeWordCheckbox; - private JCheckBox cumulativeCheckbox; - private JCheckBox showPagesCheckbox; - // page index of the last added node. - private int lastNodePageIndex; - - // show progress of search - protected JProgressBar progressBar; - - // task to complete in separate thread - protected SearchTextTask searchTextTask; - - // status label for search - protected JLabel findMessage; - - // time class to manage gui updates - protected Timer timer; - - // refresh rate of gui elements - private static final int ONE_SECOND = 1000; - - // flag indicating if search is under way. - private boolean isSearching; - - // message bundle for internationalization - ResourceBundle messageBundle; - MessageFormat searchResultMessageForm; - - /** - * Create a new instance of SearchPanel. - * - * @param controller root SwingController - */ - public SearchPanel(SwingController controller) { - super(true); - setFocusable(true); - this.controller = controller; - this.messageBundle = this.controller.getMessageBundle(); - searchResultMessageForm = setupSearchResultMessageForm(); - setGui(); - setDocument(controller.getDocument()); - } - - public void setDocument(Document doc) { - // First have to stop any existing search - if (timer != null) - timer.stop(); - if (searchTextTask != null) { - searchTextTask.stop(); - while (searchTextTask.isCurrentlySearching()) { - try { - Thread.sleep(50L); - } catch (Exception e) { - // intentional - } - } - } - - document = doc; - if (document != null && progressBar != null) { - progressBar.setMaximum(document.getNumberOfPages()); - } - if (searchTextField != null) { - searchTextField.setText(""); - } - if (searchButton != null) { - searchButton.setText(messageBundle.getString( - "viewer.utilityPane.search.tab.title")); - } - if (rootTreeNode != null) { - resetTree(); - // set title - String docTitle = getDocumentTitle(); - rootTreeNode.setUserObject(docTitle); - rootTreeNode.setAllowsChildren(true); - tree.setRootVisible((docTitle != null)); - } - if (findMessage != null) { - findMessage.setText(""); - findMessage.setVisible(false); - } - if (progressBar != null) { - progressBar.setVisible(false); - } - isSearching = false; - } - - /** - * Construct the GUI layout. - */ - private void setGui() { - - /** - * Setup GUI objects - */ - - // build the supporting tree objects - rootTreeNode = new DefaultMutableTreeNode(); - treeModel = new DefaultTreeModel(rootTreeNode); - - // build and customize the JTree - tree = new JTree(treeModel); - tree.setRootVisible(true); - tree.setExpandsSelectedPaths(true); - tree.setShowsRootHandles(true); - tree.setScrollsOnExpand(true); - tree.getSelectionModel().setSelectionMode( - TreeSelectionModel.SINGLE_TREE_SELECTION); - tree.addTreeSelectionListener(this); - - // set look and feel to match outline style - DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); - renderer.setOpenIcon(new ImageIcon(Images.get("page.gif"))); - renderer.setClosedIcon(new ImageIcon(Images.get("page.gif"))); - renderer.setLeafIcon(new ImageIcon(Images.get("page.gif"))); - tree.setCellRenderer(renderer); - - JScrollPane scrollPane = new JScrollPane(tree); - scrollPane.setPreferredSize(new Dimension(150, 75)); - - // search Label - JLabel searchLabel = new JLabel(messageBundle.getString( - "viewer.utilityPane.search.searchText.label")); - - // search input field - searchTextField = new JTextField("", 15); - searchTextField.addActionListener(this); - - // setup search progress bar - progressBar = new JProgressBar(0, 1); - progressBar.setValue(0); - progressBar.setVisible(false); - findMessage = new JLabel(messageBundle.getString("viewer.utilityPane.search.searching.msg")); - findMessage.setVisible(false); - timer = new Timer(ONE_SECOND, new TimerListener()); - - // setup search button - searchButton = new JButton(messageBundle.getString( - "viewer.utilityPane.search.searchButton.label")); - searchButton.addActionListener(this); - - // clear search button - clearSearchButton = new JButton(messageBundle.getString( - "viewer.utilityPane.search.clearSearchButton.label")); - clearSearchButton.addActionListener(this); - - // search options check boxes. - wholeWordCheckbox = new JCheckBox(messageBundle.getString( - "viewer.utilityPane.search.wholeWordCheckbox.label")); - caseSensitiveCheckbox = new JCheckBox(messageBundle.getString( - "viewer.utilityPane.search.caseSenstiveCheckbox.label")); - cumulativeCheckbox = new JCheckBox(messageBundle.getString( - "viewer.utilityPane.search.cumlitiveCheckbox.label")); - showPagesCheckbox = new JCheckBox(messageBundle.getString( - "viewer.utilityPane.search.showPagesCheckbox.label"), true); - showPagesCheckbox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent event) { - if (event.getSource() != null) { - // Determine if the user just selected or deselected the Show Pages checkbox - // If selected we'll want to combine all the leaf results into page nodes containing a series of results - // Otherwise we'll want to explode the parent/node page folders into basic leafs showing the results - if (((JCheckBox) event.getSource()).isSelected()) { - if ((rootTreeNode != null) && (rootTreeNode.getChildCount() > 0)) { - DefaultMutableTreeNode currentChild; // the current node we're handling - DefaultMutableTreeNode storedChildParent = null; // the newest page node we're adding to - int newPageNumber; // page number of the current result node - int storedPageNumber = -1; // the page number of the node we're adding to - int storedResultCount = 0; // the count of results that are on the storedPageNumber - Object[] messageArguments; // arguments used for formatting the labels - - // Loop through the results tree - for (int i = 0; i < rootTreeNode.getChildCount(); i++) { - currentChild = (DefaultMutableTreeNode) rootTreeNode.getChildAt(i); - - // Ensure we have a FindEntry object - if (currentChild.getUserObject() instanceof FindEntry) { - newPageNumber = ((FindEntry) currentChild.getUserObject()).getPageNumber(); - - // Check if the page number for the current node matches the stored number - // If it does we will want to add the node to the existing page node, - // otherwise we'll want to create a new page node and start adding to that - if (storedPageNumber == newPageNumber) { - storedResultCount++; - - if (storedChildParent != null) { - // Remove the old parentless child from the tree - treeModel.removeNodeFromParent(currentChild); - - // Add the child back to the new page node - storedChildParent.add(currentChild); - currentChild.setParent(storedChildParent); - - // Reduce the loop count by one since we moved a node from the root to a page node - i--; - } - } else { - // Update the label of the page node, so that the result count is correct - if (storedChildParent != null) { - messageArguments = new Object[]{ - String.valueOf(storedPageNumber + 1), - storedResultCount, storedResultCount}; - storedChildParent.setUserObject( - new FindEntry(searchResultMessageForm.format(messageArguments), - storedPageNumber)); - } - - // Reset the stored variables - storedPageNumber = newPageNumber; - storedResultCount = 1; - - treeModel.removeNodeFromParent(currentChild); - - // Create a new page node and move the current leaf to it - messageArguments = new Object[]{ - String.valueOf(storedPageNumber + 1), - storedResultCount, storedResultCount}; - storedChildParent = new DefaultMutableTreeNode( - new FindEntry(searchResultMessageForm.format(messageArguments), - storedPageNumber), - true); - storedChildParent.add(currentChild); - currentChild.setParent(storedChildParent); - - // Put the new page node into the overall tree - treeModel.insertNodeInto(storedChildParent, rootTreeNode, i); - } - } - } - } - } else { - if ((rootTreeNode != null) && (rootTreeNode.getChildCount() > 0)) { - // Now add the children back into the tree, this time without parent nodes - DefaultMutableTreeNode currentChild; - int rootChildCount = rootTreeNode.getChildCount(); - - // Loop through all children page nodes and explode the children out into leafs under the root node - // Then we'll remove the parent nodes so we're just left with leafs under the root - for (int i = 0; i < rootChildCount; i++) { - currentChild = (DefaultMutableTreeNode) rootTreeNode.getChildAt(0); - - if (currentChild.getChildCount() > 0) { - // Get any subchildren and reinsert them as plain leafs on the root - // We need to wrap the user object in a new mutable tree node to stop any conflicts with parent indexes - for (int j = 0; j < currentChild.getChildCount(); j++) { - treeModel.insertNodeInto( - new DefaultMutableTreeNode( - ((DefaultMutableTreeNode) currentChild.getChildAt(j)).getUserObject(), - false), - rootTreeNode, rootTreeNode.getChildCount()); - } - } - treeModel.removeNodeFromParent(currentChild); - } - } - } - } - } - }); - - /** - * Build search GUI - */ - - GridBagLayout layout = new GridBagLayout(); - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.weighty = 0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(10, 5, 1, 5); - - // content Panel - JPanel searchPanel = new JPanel(layout); - this.setLayout(new BorderLayout()); - this.add(new JScrollPane(searchPanel, - JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), BorderLayout.CENTER); - - // add the search label - addGB(searchPanel, searchLabel, 0, 0, 2, 1); - - // add the search input field - constraints.insets = new Insets(1, 1, 1, 5); - constraints.weightx = 1.0; - constraints.fill = GridBagConstraints.HORIZONTAL; - addGB(searchPanel, searchTextField, 0, 1, 2, 1); - - // add start/stop search button - constraints.insets = new Insets(1, 1, 1, 5); - constraints.weightx = 1.0; - constraints.fill = GridBagConstraints.EAST; - addGB(searchPanel, searchButton, 0, 2, 1, 1); - - // add clear search button - constraints.insets = new Insets(1, 1, 1, 5); - constraints.weightx = 0; - constraints.fill = GridBagConstraints.REMAINDER; - addGB(searchPanel, clearSearchButton, 1, 2, 1, 1); - - // add case sensitive button - constraints.insets = new Insets(5, 1, 1, 5); - constraints.weightx = 1.0; - constraints.fill = GridBagConstraints.HORIZONTAL; - addGB(searchPanel, caseSensitiveCheckbox, 0, 3, 2, 1); - - // add whole word checkbox - constraints.insets = new Insets(1, 1, 1, 5); - constraints.fill = GridBagConstraints.HORIZONTAL; - addGB(searchPanel, wholeWordCheckbox, 0, 4, 2, 1); - - // add cumulative checkbox - constraints.insets = new Insets(1, 1, 1, 5); - constraints.fill = GridBagConstraints.HORIZONTAL; - addGB(searchPanel, cumulativeCheckbox, 0, 5, 2, 1); - - // add show pages checkbox - constraints.insets = new Insets(1, 1, 1, 5); - constraints.fill = GridBagConstraints.HORIZONTAL; - addGB(searchPanel, showPagesCheckbox, 0, 6, 2, 1); - - // Add Results label - constraints.insets = new Insets(10, 5, 1, 5); - constraints.fill = GridBagConstraints.NONE; - addGB(searchPanel, new JLabel(messageBundle.getString( - "viewer.utilityPane.search.results.label")), - 0, 7, 2, 1); - - // add the lit to scroll pane - constraints.fill = GridBagConstraints.BOTH; - constraints.insets = new Insets(1, 5, 1, 5); - constraints.weightx = 1.0; - constraints.weighty = 1.0; - addGB(searchPanel, scrollPane, 0, 8, 2, 1); - - // add find message - constraints.insets = new Insets(1, 5, 1, 5); - constraints.weighty = 0; - constraints.fill = GridBagConstraints.NONE; - constraints.anchor = GridBagConstraints.EAST; - findMessage.setAlignmentX(JLabel.RIGHT_ALIGNMENT); - addGB(searchPanel, findMessage, 0, 9, 2, 1); - - // add progress - constraints.insets = new Insets(5, 5, 1, 5); - constraints.fill = GridBagConstraints.HORIZONTAL; - addGB(searchPanel, progressBar, 0, 10, 2, 1); - } - - public void setVisible(boolean flag) { - // try and get searchText focus - super.setVisible(flag); - if (this.isShowing()) { - searchTextField.requestFocus(true); - } - } - - public void requestFocus() { - super.requestFocus(); - // try and get searchText focus - searchTextField.requestFocus(); - } - - public void dispose() { - document = null; - controller = null; - searchTextTask = null; - timer = null; - } - - // Listen for selected tree items - public void valueChanged(TreeSelectionEvent e) { - // jump to the page stored in the JTree - if (tree.getLastSelectedPathComponent() != null) { - DefaultMutableTreeNode selectedNode = ((DefaultMutableTreeNode) - tree.getLastSelectedPathComponent()); - if (selectedNode.getUserObject() instanceof FindEntry) { - // get the find entry and navigate to the page. - FindEntry tmp = (FindEntry) selectedNode.getUserObject(); - if (controller != null) { - int oldTool = controller.getDocumentViewToolMode(); - try { - controller.setDisplayTool(DocumentViewModelImpl.DISPLAY_TOOL_WAIT); - controller.showPage(tmp.getPageNumber()); - } finally { - controller.setDisplayTool(oldTool); - } - } - } - } - } - - /** - * Adds a new node item to the treeModel. - * - * @param title display title of tree item - * @param pageNumber page number where the hit(s) occured - * @param textResults list of LineText items that match - * @param showPages boolean to display or hide the page node - */ - public void addFoundEntry(String title, int pageNumber, - List textResults, - boolean showPages) { - // add the new results entry. - if ((textResults != null) && (textResults.size() > 0)) { - DefaultMutableTreeNode parentNode; - // insert parent page number note. - if ((showPages) && - (lastNodePageIndex != pageNumber)) { - parentNode = new DefaultMutableTreeNode( - new FindEntry(title, pageNumber), true); - treeModel.insertNodeInto(parentNode, rootTreeNode, - rootTreeNode.getChildCount()); - } else { - parentNode = rootTreeNode; - } - // add the hit entries. - for (LineText currentText : textResults) { - addObject(parentNode, - new DefaultMutableTreeNode( - new FindEntry(generateResultPreview( - currentText.getWords()), pageNumber), - false), false); - } - - // expand the root node, we only do this once. - if (lastNodePageIndex == -1) { - tree.expandPath(new TreePath(rootTreeNode)); - } - - lastNodePageIndex = pageNumber; - - } - } - - /** - * Utility for adding a tree node. - * - * @param parent parent to add the node too. - * @param childNode node to add. - * @param shouldBeVisible true indicates an auto scroll to bottom of page - */ - private void addObject(DefaultMutableTreeNode parent, - DefaultMutableTreeNode childNode, - boolean shouldBeVisible) { - if (parent == null) { - parent = rootTreeNode; - } - //It is key to invoke this on the TreeModel, and NOT DefaultMutableTreeNode - treeModel.insertNodeInto(childNode, parent, - parent.getChildCount()); - //Make sure the user can see the lovely new node. - if (shouldBeVisible) { - tree.scrollPathToVisible(new TreePath(childNode.getPath())); - } - } - - /** - * Generate the results preview label where the hit word is bolded using - * html markup. - * - * @param allText text to unravel into a string. - * @return styled html text. - */ - private static String generateResultPreview(List allText) { - StringBuilder toReturn = new StringBuilder(HTML_TAG_START); - for (WordText currentText : allText) { - if (currentText.isHighlighted()) { - toReturn.append(BOLD_TAG_START); - toReturn.append(currentText.getText()); - toReturn.append(BOLD_TAG_END); - } else { - toReturn.append(currentText.getText()); - } - } - toReturn.append(HTML_TAG_END); - return toReturn.toString(); - } - - /** - * Reset the tree for a new document or a new search. - */ - protected void resetTree() { - tree.setSelectionPath(null); - rootTreeNode.removeAllChildren(); - treeModel.nodeStructureChanged(rootTreeNode); - // rest node count - lastNodePageIndex = -1; - } - - /** - * Utility for getting the doucment title. - * - * @return document title, if non title then a simple search results - * label is returned; - */ - private String getDocumentTitle() { - String documentTitle = null; - if (document != null && document.getInfo() != null) { - documentTitle = document.getInfo().getTitle(); - } - - if ((documentTitle == null) || (documentTitle.trim().length() == 0)) { - return null; - } - - return documentTitle; - } - - /** - * Two main actions are handle here, search and clear search. - * - * @param event awt action event. - */ - public void actionPerformed(ActionEvent event) { - - Object source = event.getSource(); - // Start/ stop a search - if (searchTextField.getText().length() > 0 && - (source == searchTextField || source == searchButton)) { - - if (!timer.isRunning()) { - // update gui components - findMessage.setVisible(true); - progressBar.setVisible(true); - - // clean the previous results and repaint the tree - resetTree(); - - // start a new search text task - searchTextTask = new SearchTextTask(this, - controller, - searchTextField.getText(), - wholeWordCheckbox.isSelected(), - caseSensitiveCheckbox.isSelected(), - cumulativeCheckbox.isSelected(), - showPagesCheckbox.isSelected(), - false, - messageBundle); - isSearching = true; - - // set state of search button - searchButton.setText(messageBundle.getString( - "viewer.utilityPane.search.stopButton.label")); - clearSearchButton.setEnabled(false); - caseSensitiveCheckbox.setEnabled(false); - wholeWordCheckbox.setEnabled(false); - cumulativeCheckbox.setEnabled(false); - showPagesCheckbox.setEnabled(false); - - // start the task and the timer - searchTextTask.go(); - timer.start(); - } else { - isSearching = false; - clearSearchButton.setEnabled(true); - caseSensitiveCheckbox.setEnabled(true); - wholeWordCheckbox.setEnabled(true); - cumulativeCheckbox.setEnabled(true); - showPagesCheckbox.setEnabled(true); - } - } else if (source == clearSearchButton) { - // clear input - searchTextField.setText(""); - - // clear the tree. - resetTree(); - - // reset high light states. - controller.getDocumentSearchController().clearAllSearchHighlight(); - controller.getDocumentViewController().getViewContainer().repaint(); - } - } - - /** - * Gridbag constructor helper - * - * @param panel parent adding component too. - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan rowspane of field - * @param colSpan colspane of field. - */ - private void addGB(JPanel panel, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - panel.add(component, constraints); - } - - /** - * Uitility for createing the searchable dialog message format. - * - * @return reuseable message format. - */ - public MessageFormat setupSearchResultMessageForm() { - MessageFormat messageForm = - new MessageFormat(messageBundle.getString( - "viewer.utilityPane.search.result.msg")); - double[] pageLimits = {0, 1, 2}; - String[] resultsStrings = { - messageBundle.getString( - "viewer.utilityPane.search.result.moreFile.msg"), - messageBundle.getString( - "viewer.utilityPane.search.result.oneFile.msg"), - messageBundle.getString( - "viewer.utilityPane.search.result.moreFile.msg") - }; - ChoiceFormat resultsChoiceForm = new ChoiceFormat(pageLimits, - resultsStrings); - - Format[] formats = {null, resultsChoiceForm}; - messageForm.setFormats(formats); - return messageForm; - } - - /** - * Uitility for createing the searching message format. - * - * @return reuseable message format. - */ - public MessageFormat setupSearchingMessageForm() { - // Build Internationalized plural phrase. - MessageFormat messageForm = - new MessageFormat(messageBundle.getString( - "viewer.utilityPane.search.searching1.msg")); - double[] fileLimits = {0, 1, 2}; - String[] fileStrings = { - messageBundle.getString( - "viewer.utilityPane.search.searching1.moreFile.msg"), - messageBundle.getString( - "viewer.utilityPane.search.searching1.oneFile.msg"), - messageBundle.getString( - "viewer.utilityPane.search.searching1.moreFile.msg"), - }; - ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, - fileStrings); - Format[] formats = {null, choiceForm, null}; - messageForm.setFormats(formats); - - return messageForm; - } - - public MessageFormat setupSearchCompletionMessageForm() { - MessageFormat messageForm = - new MessageFormat(messageBundle.getString( - "viewer.utilityPane.search.progress.msg")); - double[] pageLimits = {0, 1, 2}; - String[] pageStrings = { - messageBundle.getString( - "viewer.utilityPane.search.progress.morePage.msg"), - messageBundle.getString( - "viewer.utilityPane.search.progress.onePage.msg"), - messageBundle.getString( - "viewer.utilityPane.search.progress.morePage.msg"), - }; - ChoiceFormat pageChoiceForm = new ChoiceFormat(pageLimits, - pageStrings); - String[] resultsStrings = { - messageBundle.getString( - "viewer.utilityPane.search.progress.moreMatch.msg"), - messageBundle.getString( - "viewer.utilityPane.search.progress.oneMatch.msg"), - messageBundle.getString( - "viewer.utilityPane.search.progress.moreMatch.msg"), - }; - ChoiceFormat resultsChoiceForm = new ChoiceFormat(pageLimits, - resultsStrings); - - Format[] formats = {null, pageChoiceForm, resultsChoiceForm}; - messageForm.setFormats(formats); - return messageForm; - } - - /** - * The actionPerformed method in this class - * is called each time the Timer "goes off". - */ - class TimerListener implements ActionListener { - public void actionPerformed(ActionEvent evt) { - progressBar.setValue(searchTextTask.getCurrent()); - String s = searchTextTask.getMessage(); - if (s != null) { - findMessage.setText(s); - } - // update the text when the search is completed - if (searchTextTask.isDone() || !isSearching) { - // update search status - findMessage.setText(searchTextTask.getFinalMessage()); - timer.stop(); - searchTextTask.stop(); - // update buttons states. - searchButton.setText(messageBundle.getString("viewer.utilityPane.search.searchButton.label")); - clearSearchButton.setEnabled(true); - caseSensitiveCheckbox.setEnabled(true); - wholeWordCheckbox.setEnabled(true); - cumulativeCheckbox.setEnabled(true); - showPagesCheckbox.setEnabled(true); - - // update progress bar then hide it. - progressBar.setValue(progressBar.getMinimum()); - progressBar.setVisible(false); - } - } - } - - /** - * An Entry objects represents the found pages - */ - @SuppressWarnings("serial") - class FindEntry extends DefaultMutableTreeNode { - - // The text to be displayed on the screen for this item. - String title; - - // The destination to be displayed when this item is activated - int pageNumber; - - /** - * Creates a new instance of a FindEntry. - * - * @param title display title - * @param pageNumber page number where the hit(s) occured - */ - FindEntry(String title, int pageNumber) { - super(); - this.pageNumber = pageNumber; - this.title = title; - setUserObject(title); - } - - /** - * Get the page number. - * - * @return page number - */ - public int getPageNumber() { - return pageNumber; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SigPropertyTreeNode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SigPropertyTreeNode.java deleted file mode 100644 index ba78133f9d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SigPropertyTreeNode.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.signatures; - -import javax.swing.tree.DefaultMutableTreeNode; -import java.util.logging.Logger; - -/** - * Represent a signature property tree node. This object is used by the SignatureCellRender to make sure - * properties aren't painted with an icon. - */ -public class SigPropertyTreeNode extends DefaultMutableTreeNode { - - private static final Logger logger = - Logger.getLogger(SignatureTreeNode.class.toString()); - - public SigPropertyTreeNode(Object userObject) { - super(userObject); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SigVerificationTask.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SigVerificationTask.java deleted file mode 100644 index 8d58072cd7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SigVerificationTask.java +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.signatures; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.acroform.InteractiveForm; -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.SwingWorker; - -import javax.swing.*; -import java.awt.*; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * This class is a utility for verifying signature annotations off the AWT thread. The are two main sub classes - * VerifyAllSignatures and VerifySignature. The RI uses both of these methods for validating all signatures and - * refreshing an individual signature annotation state. - */ -public class SigVerificationTask { - - private static final Logger logger = - Logger.getLogger(SigVerificationTask.class.toString()); - - // total number of signatures to process. - private int lengthOfTask; - // current progress, used for the progress bar - private int current = 0; - // message displayed on progress bar - private String dialogMessage; - // flags for threading - private boolean done = false; - private boolean canceled = false; - - // parent swing controller - SwingController controller; - - // append nodes for found text. - private SignaturesPanel signaturesPanel; - - // message bundle for internationalization - private ResourceBundle messageBundle; - - private boolean currentlyVerifying; - - private Container viewContainer; - - /** - * Creates a new instance of the SigVerificationTask. - * - * @param signaturesPanel parent signature panel that start this task via an action - * @param controller root controller object - * @param messageBundle message bundle used for dialog text. - */ - public SigVerificationTask(SignaturesPanel signaturesPanel, - SwingController controller, - ResourceBundle messageBundle) { - this.controller = controller; - this.signaturesPanel = signaturesPanel; - lengthOfTask = controller.getDocument().getCatalog().getInteractiveForm().getSignatureFields().size(); - this.messageBundle = messageBundle; - this.viewContainer = controller.getDocumentViewController().getViewContainer(); - } - - /** - * Start the task, start verifying all the signatures annotations. - */ - public void verifyAllSignatures() { - final SwingWorker worker = new SwingWorker() { - public Object construct() { - current = 0; - done = false; - canceled = false; - dialogMessage = null; - return new VerifyAllSignatures(); - } - }; - worker.setThreadPriority(Thread.NORM_PRIORITY); - worker.start(); - } - - /** - * Start the task, verify the specified signature annotation. - */ - public void verifySignature(final SignatureWidgetAnnotation signatureWidgetAnnotation, - final SignatureTreeNode signatureTreeNode) { - final SwingWorker worker = new SwingWorker() { - public Object construct() { - current = 0; - done = false; - canceled = false; - dialogMessage = null; - return new VerifySignature(signatureWidgetAnnotation, signatureTreeNode); - } - }; - worker.setThreadPriority(Thread.NORM_PRIORITY); - worker.start(); - } - - /** - * Number of signatures that has tobe validated. - * - * @return returns max number of signatures that need validation. - */ - public int getLengthOfTask() { - return lengthOfTask; - } - - /** - * Gets the signature number that is currently being validated by this task. - * - * @return current page being processed. - */ - public int getCurrent() { - return current; - } - - /** - * Stop the task. - */ - public void stop() { - canceled = true; - dialogMessage = null; - } - - /** - * Find out if the task has completed. - * - * @return true if task is done, false otherwise. - */ - public boolean isDone() { - return done; - } - - public boolean isCurrentlyVerifying() { - return currentlyVerifying; - } - - /** - * Returns the most recent dialog message, or null - * if there is no current dialog message. - * - * @return current message dialog text. - */ - public String getMessage() { - return dialogMessage; - } - - /** - * Verify all signatures defined by the parent task. - */ - class VerifyAllSignatures { - VerifyAllSignatures() { - currentlyVerifying = true; - MessageFormat messageFormat = new MessageFormat( - messageBundle.getString("viewer.utilityPane.signatures.verify.initializingMessage.label")); - try { - current = 0; - try { - Document document = controller.getDocument(); - InteractiveForm interactiveForm = document.getCatalog().getInteractiveForm(); - // checks and flags each annotation to indicate if the signatures cover the whole document - interactiveForm.isSignaturesCoverDocumentLength(); - final ArrayList signatures = interactiveForm.getSignatureFields(); - boolean unsignedFields = false; - // build out the tree - if (signatures.size() > 0) { - // iterate over the signature in the document. - for (int i = 0, max = signatures.size(); i < max; i++) { - // break if needed - if (canceled || done) { - break; - } - // Update task information - current = i; - - dialogMessage = messageFormat.format(new Object[]{i + 1, signatures.size()}); - - final SignatureWidgetAnnotation signatureWidgetAnnotation = signatures.get(i); - SignatureDictionary signatureDictionary = signatureWidgetAnnotation.getSignatureDictionary(); - if (signatureDictionary.getEntries().size() > 0) { - try { - signatureWidgetAnnotation.getSignatureValidator().validate(); - signatureWidgetAnnotation.getSignatureValidator().isSignaturesCoverDocumentLength(); - // add a new node to the tree. - } catch (SignatureIntegrityException e) { - logger.log(Level.WARNING, "Error verifying signature.", e); - } - // add the node to the signature panel tree but on the - // awt thread. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - // add the node - signaturesPanel.addSignature(signatureWidgetAnnotation); - // try repainting the container - viewContainer.repaint(); - } - }); - } else { - // found some unsigned fields. - unsignedFields = true; - } - Thread.yield(); - } - // build out unsigned fields - if (unsignedFields) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - signaturesPanel.addUnsignedSignatures(signatures); - viewContainer.repaint(); - } - }); - } - } - // update the dialog and end the task - dialogMessage = messageBundle.getString("viewer.utilityPane.signatures.verify.completeMessage.label"); - done = true; - } catch (Exception e) { - logger.log(Level.FINER, "Error verifying signatures.", e); - } - } finally { - currentlyVerifying = false; - } - // repaint the view container - SwingUtilities.invokeLater(new Runnable() { - public void run() { - viewContainer.validate(); - } - }); - } - } - - /** - * Verify the signature specified in the constructor. - */ - class VerifySignature { - /** - * Verifies the given signature and update the respective tree node. - * - * @param signatureWidgetAnnotation annotation to verify - * @param signatureTreeNode node to update for display of new validation info. - */ - VerifySignature(final SignatureWidgetAnnotation signatureWidgetAnnotation, - final SignatureTreeNode signatureTreeNode) { - try { - currentlyVerifying = true; - current = 0; - try { - dialogMessage = messageBundle.getString("viewer.utilityPane.signatures.verify.validating.label"); - signaturesPanel.updateSignature(signatureWidgetAnnotation, signatureTreeNode); - // add the node to the signature panel tree but on the - // awt thread. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - // add the node - signaturesPanel.showSignatureValidationDialog(signatureWidgetAnnotation); - // try repainting the container - viewContainer.repaint(); - } - }); - // update the dialog and end the task - dialogMessage = messageBundle.getString("viewer.utilityPane.signatures.verify.completeMessage.label"); - done = true; - } catch (Exception e) { - logger.log(Level.FINER, "Error verifying signature.", e); - } - } finally { - currentlyVerifying = false; - } - // repaint the view container - SwingUtilities.invokeLater(new Runnable() { - public void run() { - viewContainer.validate(); - } - }); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureCellRender.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureCellRender.java deleted file mode 100644 index 3d58a11bbc..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureCellRender.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.signatures; - -import javax.swing.*; -import javax.swing.tree.DefaultTreeCellRenderer; -import java.awt.*; - -/** - * Renders the appropriate root icon for a SignatureTreeNode. Child elements of SigPropertyTreeNode will - * have their icon set to null. - */ -public class SignatureCellRender extends DefaultTreeCellRenderer { - - public Component getTreeCellRendererComponent( - JTree tree, - Object value, - boolean sel, - boolean expanded, - boolean leaf, - int row, - boolean hasFocus) { - - super.getTreeCellRendererComponent( - tree, value, sel, - expanded, leaf, row, - hasFocus); - // dynamic as the validator status changes, so will the icon. - if (value instanceof SignatureTreeNode) { - SignatureTreeNode signatureTreeNode = (SignatureTreeNode) value; - if (signatureTreeNode.getRootNodeValidityIcon() != null) { - setIcon(signatureTreeNode.getRootNodeValidityIcon()); - } - } else { - setIcon(null); - } - return this; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureCertTreeNode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureCertTreeNode.java deleted file mode 100644 index 557a53095a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureCertTreeNode.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.signatures; - -import javax.swing.tree.DefaultMutableTreeNode; -import java.awt.*; -import java.security.cert.Certificate; -import java.util.Collection; -import java.util.logging.Logger; - -/** - * SignatureCertTreeNode object type is used to enable/show the - */ -public class SignatureCertTreeNode extends DefaultMutableTreeNode { - - private static final Logger logger = - Logger.getLogger(SignatureTreeNode.class.toString()); - - private Collection certificateChain; - private Image image; - - public SignatureCertTreeNode(Object userObject, Collection certificateChain, Image image) { - super(userObject); - this.certificateChain = certificateChain; - this.image = image; - } - - public Collection getCertificateChain() { - return certificateChain; - } - - public Image getImage() { - return image; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureTreeNode.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureTreeNode.java deleted file mode 100644 index 0b4641d80f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureTreeNode.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.signatures; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x500.style.BCStyle; -import org.icepdf.core.pobjects.PDate; -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; -import org.icepdf.ri.images.Images; - -import javax.security.auth.x500.X500Principal; -import javax.swing.*; -import javax.swing.tree.DefaultMutableTreeNode; -import java.security.cert.X509Certificate; -import java.text.MessageFormat; -import java.util.ResourceBundle; -import java.util.logging.Logger; - -/** - * Represents a signatures in the signature tree. The node can be expanded to show more details about the - * signer, validity and certificate details. - */ -@SuppressWarnings("serial") -public class SignatureTreeNode extends DefaultMutableTreeNode { - - private static final Logger logger = - Logger.getLogger(SignatureTreeNode.class.toString()); - - private ResourceBundle messageBundle; - private SignatureWidgetAnnotation signatureWidgetAnnotation; - private SignatureValidator signatureValidator; - // flag that validation process is taking place. - private boolean verifyingSignature; - - - private String location = null; - private String reason = null; - private String contact = null; - private String name = null; - private String commonName = null; - private String organization = null; - private String emailAddress = null; - private String date = null; - - /** - * Creates a new instance of an OutlineItemTreeNode - * - * @param signatureWidgetAnnotation Contains PDF Outline signatureWidgetAnnotation data - */ - public SignatureTreeNode(SignatureWidgetAnnotation signatureWidgetAnnotation, ResourceBundle messageBundle) { - super(); - this.signatureWidgetAnnotation = signatureWidgetAnnotation; - this.messageBundle = messageBundle; - - try { - validateSignatureNode(); - } catch (SignatureIntegrityException e) { - logger.warning("There was an issue creating a node for the signature: " + - signatureWidgetAnnotation.toString()); - // build a user node object to report the error. - MessageFormat formatter = new MessageFormat(messageBundle.getString( - "viewer.utilityPane.signatures.tab.certTree.error.label")); - setUserObject(formatter.format(new Object[]{(commonName != null ? commonName + " " : " "), - (emailAddress != null ? "<" + emailAddress + ">" : "")})); - } - } - - /** - * Validates the signatures represented by this tree node. This method is called by a worker thread - * and once validation is complete the notes states is updated with a call to {@link #refreshSignerNode()} - * - * @throws SignatureIntegrityException - */ - public void validateSignatureNode() throws SignatureIntegrityException { - - SignatureFieldDictionary fieldDictionary = signatureWidgetAnnotation.getFieldDictionary(); - SignatureDictionary signatureDictionary = signatureWidgetAnnotation.getSignatureDictionary(); - if (fieldDictionary != null) { - // grab some signer properties right from the annotations dictionary. - name = signatureDictionary.getName(); - location = signatureDictionary.getLocation(); - reason = signatureDictionary.getReason(); - contact = signatureDictionary.getContactInfo(); - date = signatureDictionary.getDate(); - - // getting a signatureValidator should give us a pointer the to the signer cert if all goes well. - signatureValidator = signatureWidgetAnnotation.getSignatureValidator(); - // try and parse out the signer info. - X509Certificate certificate = signatureValidator.getSignerCertificate(); - X500Principal principal = certificate.getIssuerX500Principal(); - X500Name x500name = new X500Name(principal.getName()); - if (x500name.getRDNs() != null) { - commonName = SignatureUtilities.parseRelativeDistinguishedName(x500name, BCStyle.CN); - organization = SignatureUtilities.parseRelativeDistinguishedName(x500name, BCStyle.O); - emailAddress = SignatureUtilities.parseRelativeDistinguishedName(x500name, BCStyle.EmailAddress); - } - // Start validation process. - setVerifyingSignature(true); - signatureValidator.validate(); - setVerifyingSignature(true); - } - - } - - /** - * Builds a rather complicated tree node and child nodes to show various properties of a a signer and the - * corresponding certificate. The main purpose is to display to the end user if the certificate is valid and - * can be trusted as well as showing document permissions and if the document has been modified since it was - * singed. - *

      - * - Singed by "signer name" - * | - * - Signature is - * | - * - This version of the document has been altered - * - SignatureSigner's identity is - * - Signature includes an embedded timestamp | Signing is from the clock of the signer's computer. - * - Permissions - * | - * - No changes allowed - * - Field values can be changed - * - needs more research - * - Signature Details - * | - * - Reason: - * - Location: - * - Certificate Details (clickable, loads certificate dialog) - * - Last Checked: - * - Field Name: on page X (clickable, takes to page and applies focus). - * - */ - public synchronized void refreshSignerNode() { - if (isVerifyingSignature()) { - // should have enough data to build a out a full signature node. - MessageFormat formatter = new MessageFormat(messageBundle.getString( - "viewer.utilityPane.signatures.tab.certTree.rootSigned.label")); - setUserObject(formatter.format(new Object[]{(commonName != null ? commonName + " " : " "), - (emailAddress != null ? "<" + emailAddress + ">" : "")})); - removeAllChildren(); - // signature validity - buildSignatureValidity(this); - // add signature details - buildSignatureDetails(this); - // tack on last verified date and link to annotation if present - buildVerifiedDateAndFieldLink(this); - } else { - // build out a simple validating message - MessageFormat formatter = new MessageFormat(messageBundle.getString( - "viewer.utilityPane.signatures.tab.certTree.rootValidating.label")); - setUserObject(formatter.format(new Object[]{(commonName != null ? commonName + " " : " "), - (emailAddress != null ? "<" + emailAddress + ">" : "")})); - } - } - - // set one of the three icon's to represent the validity status of the signature node. - protected ImageIcon getRootNodeValidityIcon() { - if (!signatureValidator.isSignedDataModified() && signatureValidator.isCertificateChainTrusted() - && signatureValidator.isSignaturesCoverDocumentLength()) { - return new ImageIcon(Images.get("signature_valid.png")); - } else if (!signatureValidator.isSignedDataModified() && signatureValidator.isSignaturesCoverDocumentLength()) { - return new ImageIcon(Images.get("signature_caution.png")); - } else { - return new ImageIcon(Images.get("signature_invalid.png")); - } - } - - // builds otu the validity tree node. - private void buildSignatureValidity(DefaultMutableTreeNode root) { - // figure out the opening messages. - String validity = "viewer.utilityPane.signatures.tab.certTree.cert.invalid.label"; - if (!signatureValidator.isSignedDataModified() && signatureValidator.isCertificateChainTrusted()) { - validity = "viewer.utilityPane.signatures.tab.certTree.cert.unknown.label"; - } else if (!signatureValidator.isSignedDataModified() && !signatureValidator.isCertificateChainTrusted()) { - validity = "viewer.utilityPane.signatures.tab.certTree.cert.valid.label"; - } - SigPropertyTreeNode rootValidityDetails = new SigPropertyTreeNode( - messageBundle.getString(validity)); - - // document modification - String documentModified = "viewer.utilityPane.signatures.tab.certTree.doc.modified.label"; - if (!signatureValidator.isSignedDataModified() && !signatureValidator.isDocumentDataModified()) { - documentModified = "viewer.utilityPane.signatures.tab.certTree.doc.unmodified.label"; - } else if (!signatureValidator.isSignedDataModified() && signatureValidator.isDocumentDataModified() && signatureValidator.isSignaturesCoverDocumentLength()) { - documentModified = "viewer.utilityPane.signatures.tab.certTree.doc.modified.label"; - } else if (!signatureValidator.isSignaturesCoverDocumentLength()) { - documentModified = "viewer.utilityPane.signatures.tab.certTree.doc.major.label"; - } - rootValidityDetails.add(new SigPropertyTreeNode(messageBundle.getString(documentModified))); - // trusted certification - String certificateTrusted = "viewer.utilityPane.signatures.tab.certTree.signature.identity.unknown.label"; - if (signatureValidator.isCertificateChainTrusted()) { - if (signatureValidator.isRevocation()) { - certificateTrusted = "viewer.utilityPane.signatures.tab.certTree.signature.identity.unchecked.label"; - } else { - certificateTrusted = "viewer.utilityPane.signatures.tab.certTree.signature.identity.valid.label"; - } - } - rootValidityDetails.add(new SigPropertyTreeNode(messageBundle.getString(certificateTrusted))); - // signature time. - String signatureTime = "viewer.utilityPane.signatures.tab.certTree.signature.time.local.label"; - if (signatureValidator.isEmbeddedTimeStamp()) { - signatureTime = "viewer.utilityPane.signatures.tab.certTree.signature.time.embedded.label"; - } - rootValidityDetails.add(new SigPropertyTreeNode(messageBundle.getString(signatureTime))); - root.add(rootValidityDetails); - } - - // builds out the signature details - private void buildSignatureDetails(DefaultMutableTreeNode root) { - SigPropertyTreeNode rootSignatureDetails = new SigPropertyTreeNode( - messageBundle.getString("viewer.utilityPane.signatures.tab.certTree.signature.details.label")); - // try and add the reason - if (reason != null && reason.length() > 0) { - MessageFormat messageFormat = new MessageFormat(messageBundle.getString( - "viewer.utilityPane.signatures.tab.certTree.signature.details.reason.label")); - rootSignatureDetails.add(new SigPropertyTreeNode(messageFormat.format(new Object[]{reason}))); - } - // add the location - if (location != null && location.length() > 0) { - MessageFormat messageFormat = new MessageFormat(messageBundle.getString( - "viewer.utilityPane.signatures.tab.certTree.signature.details.location.label")); - rootSignatureDetails.add(new SigPropertyTreeNode(messageFormat.format(new Object[]{location}))); - } - // add link for bringing up the certificate details. - rootSignatureDetails.add(new SignatureCertTreeNode( - messageBundle.getString("viewer.utilityPane.signatures.tab.certTree.signature.details.full.label"), - signatureValidator.getCertificateChain(), - getRootNodeValidityIcon().getImage())); - root.add(rootSignatureDetails); - } - - private void buildVerifiedDateAndFieldLink(DefaultMutableTreeNode root) { - if (signatureValidator != null && signatureValidator.getLastValidated() != null) { - MessageFormat messageFormat = new MessageFormat(messageBundle.getString( - "viewer.utilityPane.signatures.tab.certTree.signature.lastChecked.label")); - SigPropertyTreeNode lastChecked = - new SigPropertyTreeNode(messageFormat.format(new Object[]{ - new PDate(signatureWidgetAnnotation.getLibrary().getSecurityManager(), - PDate.formatDateTime(signatureValidator.getLastValidated())).toString()})); - lastChecked.setAllowsChildren(false); - root.add(lastChecked); - } - } - - public synchronized boolean isVerifyingSignature() { - return verifyingSignature; - } - - /** - * Flat to indicated that the validation process has completed and the state variables are in a completed - * state. This doesn't mean that the signature is valid just the validation process is complete. - * - * @param verifyingSignature true to indicate the validation process is complete, otherwise falls. - */ - public void setVerifyingSignature(boolean verifyingSignature) { - this.verifyingSignature = verifyingSignature; - } - - public SignatureWidgetAnnotation getOutlineItem() { - return signatureWidgetAnnotation; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureUtilities.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureUtilities.java deleted file mode 100644 index a2b30d069b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignatureUtilities.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.signatures; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x500.RDN; -import org.bouncycastle.asn1.x500.X500Name; - -/** - * Utility of commonly used signature related algorithms. - */ -public class SignatureUtilities { - - /** - * Parse out a known data element from an X500Name. - * - * @param rdName name to parse value from. - * @param commonCode BCStyle name . - * @return BCStyle name value, null if the BCStyle name was not found. - */ - public static String parseRelativeDistinguishedName(X500Name rdName, ASN1ObjectIdentifier commonCode) { - RDN[] rdns = rdName.getRDNs(commonCode); - if (rdns != null && rdns.length > 0 && rdns[0].getFirst() != null) { - return rdns[0].getFirst().getValue().toString(); - } - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignaturesPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignaturesPanel.java deleted file mode 100644 index 7e7252a3ad..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignaturesPanel.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.signatures; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.acroform.InteractiveForm; -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.signatures.CertificatePropertiesDialog; -import org.icepdf.ri.common.views.annotations.signatures.SignaturePropertiesDialog; -import org.icepdf.ri.common.views.annotations.signatures.SignatureValidationDialog; - -import javax.swing.*; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreePath; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.ArrayList; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * The SignaturesPanel lists all the digital signatures in a document as well as the signature fields components - * that are just placeholders. SwingWorkers are used to - */ -public class SignaturesPanel extends JPanel { - - private static final Logger logger = - Logger.getLogger(SignaturesPanel.class.toString()); - - protected DocumentViewController documentViewController; - - protected Document currentDocument; - - private SwingController controller; - - protected JTree signatureTree; - private DefaultMutableTreeNode rootTreeNode; - private DefaultTreeModel treeModel; - // show progress of the signature validation process. - protected JProgressBar progressBar; - // task to complete in separate thread - protected SigVerificationTask sigVerificationTask; - // status label for validation progress reporting. - protected JLabel progressLabel; - - // time class to manage gui updates - protected Timer timer; - // refresh rate of gui elements - private static final int REFRESH_TIME = 100; - - protected JScrollPane scrollPane; - private GridBagConstraints constraints; - protected DocumentViewModel documentViewModel; - - // message bundle for internationalization - protected ResourceBundle messageBundle; - protected NodeSelectionListener nodeSelectionListener; - - public SignaturesPanel(SwingController controller) { - super(true); - setFocusable(true); - this.controller = controller; - this.messageBundle = this.controller.getMessageBundle(); - buildUI(); - } - - private void buildUI() { - rootTreeNode = new DefaultMutableTreeNode(messageBundle.getString("viewer.utilityPane.signatures.tab.title")); - rootTreeNode.setAllowsChildren(true); - treeModel = new DefaultTreeModel(rootTreeNode); - signatureTree = new SignaturesTree(treeModel); - signatureTree.setRootVisible(false); - signatureTree.setExpandsSelectedPaths(true); - signatureTree.setShowsRootHandles(true); - signatureTree.setScrollsOnExpand(true); - nodeSelectionListener = new NodeSelectionListener(signatureTree); - signatureTree.addMouseListener(nodeSelectionListener); - - this.setLayout(new BorderLayout()); - scrollPane = new JScrollPane(signatureTree, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - scrollPane.getVerticalScrollBar().setUnitIncrement(20); - scrollPane.getHorizontalScrollBar().setUnitIncrement(20); - - // setup validation progress bar and status label - progressBar = new JProgressBar(0, 1); - progressBar.setValue(0); - progressBar.setVisible(false); - progressLabel = new JLabel(""); - progressLabel.setVisible(false); - timer = new Timer(REFRESH_TIME, new TimerListener()); - - /** - * Build signature tree GUI - */ - GridBagLayout layout = new GridBagLayout(); - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.weighty = 0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(10, 5, 1, 5); - - JPanel signaturePanel = new JPanel(layout); - this.add(signaturePanel); - - // add the lit to scroll pane - constraints.fill = GridBagConstraints.BOTH; - constraints.insets = new Insets(1, 5, 1, 5); - constraints.weightx = 1.0; - constraints.weighty = 1.0; - addGB(signaturePanel, scrollPane, 0, 0, 1, 1); - - // add progress label - constraints.insets = new Insets(1, 5, 1, 5); - constraints.weighty = 0; - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.anchor = GridBagConstraints.EAST; - progressLabel.setAlignmentX(JLabel.RIGHT_ALIGNMENT); - addGB(signaturePanel, progressLabel, 0, 1, 1, 1); - - // add progress - constraints.insets = new Insets(5, 5, 1, 5); - constraints.fill = GridBagConstraints.HORIZONTAL; - addGB(signaturePanel, progressBar, 0, 2, 1, 1); - } - - /** - * Called from the worker task to add a new signature node to the tree. It is assumed that - * this call is made from the AWT thread. - * - * @param signatureWidgetAnnotation annotation to add to tree. - */ - public void addSignature(SignatureWidgetAnnotation signatureWidgetAnnotation) { - if (signatureWidgetAnnotation != null) { - SignatureDictionary signatureDictionary = signatureWidgetAnnotation.getSignatureDictionary(); - // filter any unsigned signer fields. - if (signatureDictionary.getEntries().size() > 0) { - SignatureTreeNode tmp = new SignatureTreeNode(signatureWidgetAnnotation, messageBundle); - tmp.refreshSignerNode(); - tmp.setAllowsChildren(true); - // insert and expand the root node. - treeModel.insertNodeInto(tmp, rootTreeNode, rootTreeNode.getChildCount()); - signatureTree.expandPath(new TreePath(rootTreeNode)); - } - } - } - - /** - * Called from the worker task to add a new unsigned signature node to the tree. It is assumed that - * this call is made from the AWT thread. - * - * @param signatures list off unsigned signatures annotation to add to tree. - */ - public void addUnsignedSignatures(ArrayList signatures) { - DefaultMutableTreeNode unsignedFieldNode = new DefaultMutableTreeNode( - messageBundle.getString("viewer.utilityPane.signatures.tab.certTree.unsigned.label")); - treeModel.insertNodeInto(unsignedFieldNode, rootTreeNode, - rootTreeNode.getChildCount()); - for (SignatureWidgetAnnotation signature : signatures) { - SignatureDictionary signatureDictionary = signature.getSignatureDictionary(); - // filter for only unsigned signer fields. - if (signatureDictionary.getEntries().size() == 0) { - DefaultMutableTreeNode field = - new DefaultMutableTreeNode(signature.getFieldDictionary().getPartialFieldName()); - field.setAllowsChildren(false); - unsignedFieldNode.add(field); - } - } - signatureTree.expandPath(new TreePath(rootTreeNode)); - signatureTree.expandPath(new TreePath(unsignedFieldNode)); - revalidate(); - } - - /** - * Updates the data fields on a signature tree node after verification has taken place. It is assumed - * this method is always called from the AWT thread. - * - * @param signatureWidgetAnnotation annotation to update - * @param signatureTreeNode node that will be updated. - */ - public void updateSignature(SignatureWidgetAnnotation signatureWidgetAnnotation, - SignatureTreeNode signatureTreeNode) { - if (signatureWidgetAnnotation != null) { - try { - TreePath treePath = new TreePath(signatureTreeNode.getPath()); - boolean isExpanded = signatureTree.isExpanded(treePath); - signatureTreeNode.validateSignatureNode(); - signatureTreeNode.refreshSignerNode(); - treeModel.reload(); - if (isExpanded) { - signatureTree.expandPath(new TreePath(signatureTreeNode.getPath())); - } - } catch (SignatureIntegrityException e) { - logger.log(Level.WARNING, "Could not build signature node.", e); - } - } - } - - /** - * Shows the signatureValidationDialog for the given SignatureWidgetAnnotation. This method should - * be called from the AWT thread. - * - * @param signatureWidgetAnnotation annotation to show the properties of. - */ - public void showSignatureValidationDialog(SignatureWidgetAnnotation signatureWidgetAnnotation) { - if (signatureWidgetAnnotation != null) { - // show the dialog - SignatureFieldDictionary fieldDictionary = signatureWidgetAnnotation.getFieldDictionary(); - if (fieldDictionary != null) { - SignatureValidator signatureValidator = signatureWidgetAnnotation.getSignatureValidator(); - if (signatureValidator != null) { - new SignatureValidationDialog(controller.getViewerFrame(), - messageBundle, signatureWidgetAnnotation, signatureValidator).setVisible(true); - } - } - - } - } - - /** - * Set the current document instance and starts the validation process of any found signature annotations. - * - * @param document current document, can be null. - */ - public void setDocument(Document document) { - - // First have to stop any existing validation processes. - if (timer != null) { - timer.stop(); - } - if (sigVerificationTask != null) { - sigVerificationTask.stop(); - while (sigVerificationTask.isCurrentlyVerifying()) { - try { - Thread.sleep(50L); - } catch (Exception e) { - // intentional - } - } - } - - this.currentDocument = document; - documentViewController = controller.getDocumentViewController(); - documentViewModel = documentViewController.getDocumentViewModel(); - - // clear the previously loaded signature tree. - if (rootTreeNode != null) { - resetTree(); - // set title - rootTreeNode.setAllowsChildren(true); - signatureTree.setRootVisible(false); - } - - if (this.currentDocument != null && - currentDocument.getCatalog().getInteractiveForm() != null) { - InteractiveForm interactiveForm = currentDocument.getCatalog().getInteractiveForm(); - final ArrayList signatures = interactiveForm.getSignatureFields(); - // build out the tree - if (signatures.size() > 0) { - if (!timer.isRunning()) { - // show the progress components. - progressLabel.setVisible(true); - progressBar.setVisible(true); - // clean the previous results and repaint the tree - resetTree(); - // start a new verification task - sigVerificationTask = new SigVerificationTask(this, controller, messageBundle); - progressBar.setMaximum(sigVerificationTask.getLengthOfTask()); - // start the task and the timer - sigVerificationTask.verifyAllSignatures(); - timer.start(); - } - } - } - } - - /** - * Reset the tree for a new document or a new validation. - */ - protected void resetTree() { - signatureTree.setSelectionPath(null); - rootTreeNode.removeAllChildren(); - treeModel.nodeStructureChanged(rootTreeNode); - } - - /** - * Component clean on on document window tear down. - */ - public void dispose() { - this.removeAll(); - sigVerificationTask = null; - controller = null; - documentViewModel = null; - currentDocument = null; - timer = null; - } - - /** - * NodeSelectionListener handles the root node context menu creation display and command execution. - */ - class NodeSelectionListener extends MouseAdapter { - protected JTree tree; - protected JPopupMenu contextMenu; - private SignatureTreeNode signatureTreeNode; - - NodeSelectionListener(JTree tree) { - this.tree = tree; - - // add context menu for quick access to validating and signature properties. - contextMenu = new JPopupMenu(); - JMenuItem validateMenu = new JMenuItem(messageBundle.getString( - "viewer.annotation.signature.menu.validateSignature.label")); - validateMenu.addActionListener(new validationActionListener()); - contextMenu.add(validateMenu); - contextMenu.add(new JPopupMenu.Separator()); - JMenuItem signaturePropertiesMenu = new JMenuItem(messageBundle.getString( - "viewer.annotation.signature.menu.signatureProperties.label")); - signaturePropertiesMenu.addActionListener(new SignaturesPropertiesActionListener(tree)); - contextMenu.add(signaturePropertiesMenu); - contextMenu.add(new JPopupMenu.Separator()); - JMenuItem signaturePageNavigationMenu = new JMenuItem(messageBundle.getString( - "viewer.annotation.signature.menu.signaturePageNavigation.label")); - signaturePageNavigationMenu.addActionListener(new SignaturesPageNavigationListener()); - contextMenu.add(signaturePageNavigationMenu); - } - - public void mouseClicked(MouseEvent e) { - int x = e.getX(); - int y = e.getY(); - int row = tree.getRowForLocation(x, y); - TreePath path = tree.getPathForRow(row); - if (path != null) { - Object node = path.getLastPathComponent(); - if (node instanceof SignatureCertTreeNode) { - // someone clicked on the show certificate node. - // create new dialog to show certificate properties. - SignatureCertTreeNode selectedSignatureCert = (SignatureCertTreeNode) node; - new CertificatePropertiesDialog(controller.getViewerFrame(), messageBundle, - selectedSignatureCert.getCertificateChain()) - .setVisible(true); - } else if (node instanceof SignatureTreeNode && - (e.getButton() == MouseEvent.BUTTON3 || e.getButton() == MouseEvent.BUTTON2)) { - signatureTreeNode = (SignatureTreeNode) node; - // show context menu. - contextMenu.show(e.getComponent(), e.getX(), e.getY()); - } - - } - } - - public SignatureTreeNode getSignatureTreeNode() { - return signatureTreeNode; - } - } - - /** - * GridBag constructor helper - * - * @param panel parent adding component too. - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan rowspane of field - * @param colSpan colspane of field. - */ - private void addGB(JPanel panel, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - panel.add(component, constraints); - } - - /** - * Shows the SignatureValidationDialog dialog. - */ - class validationActionListener implements ActionListener { - public void actionPerformed(ActionEvent actionEvent) { - if (!sigVerificationTask.isCurrentlyVerifying()) { - // validate the signature and show the summary dialog. - final SignatureTreeNode signatureTreeNode = nodeSelectionListener.getSignatureTreeNode(); - SignatureWidgetAnnotation signatureWidgetAnnotation = signatureTreeNode.getOutlineItem(); - if (!timer.isRunning()) { - // update gui components - progressLabel.setVisible(true); - progressBar.setVisible(true); - progressBar.setMaximum(1); - // start the task and the timer - sigVerificationTask.verifySignature(signatureWidgetAnnotation, signatureTreeNode); - timer.start(); - } - } - } - } - - /** - * Navigates to the page the selected signature annotation exists on. - */ - class SignaturesPageNavigationListener implements ActionListener { - public void actionPerformed(ActionEvent e) { - if (nodeSelectionListener.getSignatureTreeNode() != null) { - final SignatureTreeNode signatureTreeNode = nodeSelectionListener.getSignatureTreeNode(); - SignatureWidgetAnnotation signatureWidgetAnnotation = signatureTreeNode.getOutlineItem(); - // turn out the parent is seldom used correctly and generally just points to page zero. - // so we should - Document document = controller.getDocument(); - int pages = controller.getPageTree().getNumberOfPages(); - boolean found = false; - for (int i = 0; i < pages && !found; i++) { - // check is page's annotation array for a matching reference. - ArrayList annotationReferences = document.getPageTree().getPage(i).getAnnotationReferences(); - if (annotationReferences != null) { - for (Reference reference : annotationReferences) { - if (reference.equals(signatureWidgetAnnotation.getPObjectReference())) { - controller.showPage(i); - found = true; - break; - } - } - } - } - } - } - } - - /** - * Command object for displaying the SignaturePropertiesDialog. - */ - class SignaturesPropertiesActionListener implements ActionListener { - protected JTree tree; - - public SignaturesPropertiesActionListener(JTree tree) { - this.tree = tree; - } - - public void actionPerformed(ActionEvent e) { - if (nodeSelectionListener.getSignatureTreeNode() != null) { - final SignatureTreeNode signatureTreeNode = nodeSelectionListener.getSignatureTreeNode(); - new SignaturePropertiesDialog(controller.getViewerFrame(), - messageBundle, signatureTreeNode.getOutlineItem()).setVisible(true); - - } - } - } - - /** - * The actionPerformed method in this class is called each time the Timer "goes off". - */ - class TimerListener implements ActionListener { - public void actionPerformed(ActionEvent evt) { - progressBar.setValue(sigVerificationTask.getCurrent()); - String s = sigVerificationTask.getMessage(); - if (s != null) { - progressLabel.setText(s); - } - // update the text and stop the timer when the validation is completed or terminated. - if (sigVerificationTask.isDone() || !sigVerificationTask.isCurrentlyVerifying()) { - // update search status - timer.stop(); - sigVerificationTask.stop(); - - // update progress bar then hide it. - progressBar.setValue(progressBar.getMinimum()); - progressBar.setVisible(false); - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignaturesTree.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignaturesTree.java deleted file mode 100644 index b07d7011a9..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/signatures/SignaturesTree.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.utility.signatures; - -import org.icepdf.ri.common.utility.outline.OutlineItemTreeNode; - -import javax.swing.*; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreeSelectionModel; - -/** - * SignaturesTree is a JTree derivative whose nodes are SignatureTreeNode objects, - * each of which refers to a document signature. The signature can be used to - * authenticate the identity of user and the documents contents. A node can be - * clicked on for more information pertaining to the signatures validity. - * - * @see OutlineItemTreeNode - * @since 6.1 - */ -@SuppressWarnings("serial") -public class SignaturesTree extends JTree { - - public SignaturesTree(TreeModel newModel) { - super(newModel); - getSelectionModel().setSelectionMode( - TreeSelectionModel.SINGLE_TREE_SELECTION); - setRootVisible(true); - setScrollsOnExpand(true); - - // setup a custom cell render - setCellRenderer(new SignatureCellRender()); - - // old font was Arial with is no go for linux. - setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 13)); - setRowHeight(18); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/thumbs/ThumbnailsPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/thumbs/ThumbnailsPanel.java deleted file mode 100644 index 72cb845b25..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/utility/thumbs/ThumbnailsPanel.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.utility.thumbs; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.PageTree; -import org.icepdf.ri.common.PageThumbnailComponent; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.ModifiedFlowLayout; -import org.icepdf.ri.util.PropertiesManager; - -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.AdjustmentEvent; -import java.awt.event.AdjustmentListener; - -/** - * The ThumbnailsPanel class is responsible for showing a document preview - * of all pages in a document. This panel is show as a tab in the utility - * panel of the Viewer RI. - * - * @since 4.3 - */ -@SuppressWarnings("serial") -public class ThumbnailsPanel extends JPanel { - - protected DocumentViewController documentViewController; - protected Document currentDocument; - protected PropertiesManager propertiesManager; - protected DocumentViewModel documentViewModel; - protected float thumbNailZoom = 0.1f; // default zoom is 10% - - protected static final int MAX_PAGE_SIZE_READ_AHEAD = 10; - - private SwingController controller; - - public ThumbnailsPanel(SwingController controller, - PropertiesManager propertiesManager) { - this.controller = controller; - this.propertiesManager = propertiesManager; - // assign thumbnail zoom from propertiesManager if available - if (propertiesManager != null) { - thumbNailZoom = propertiesManager.getFloat( - PropertiesManager.PROPERTY_UTILITYPANE_THUMBNAILS_ZOOM); - } - } - - public void setDocument(Document document) { - this.currentDocument = document; - documentViewController = controller.getDocumentViewController(); - - if (document != null) { - buildUI(); - } else { - // tear down the old container. - this.removeAll(); - } - } - - public void dispose() { - this.removeAll(); - } - - private void buildUI() { - - final ModifiedFlowLayout layout = new ModifiedFlowLayout(); - final JPanel pageThumbsPanel = new JPanel(layout); - this.setLayout(new BorderLayout()); - JScrollPane scrollPane = new JScrollPane(pageThumbsPanel, - JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, - JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - scrollPane.getVerticalScrollBar().setUnitIncrement(20); - scrollPane.getHorizontalScrollBar().setUnitIncrement(20); - this.add(scrollPane, - BorderLayout.CENTER); - - scrollPane.getViewport().addChangeListener(new ChangeListener() { - public void stateChanged(ChangeEvent e) { - JViewport tmp = (JViewport) e.getSource(); - Dimension dim = layout.computeSize(tmp.getWidth(), pageThumbsPanel); - pageThumbsPanel.setPreferredSize(dim); - } - }); - - scrollPane.getVerticalScrollBar().addAdjustmentListener( - new AdjustmentListener() { - public void adjustmentValueChanged(AdjustmentEvent e) { - if (!e.getValueIsAdjusting()) { - repaint(); - } - } - }); - - // load the page components into the layout - PageThumbnailComponent pageThumbnailComponent = null; - PageTree pageTree = currentDocument.getPageTree(); - int numberOfPages = currentDocument.getNumberOfPages(); - int avgPageWidth = 0; - int avgPageHeight = 0; - - // add components for every page in the document - for (int i = 0; i < numberOfPages; i++) { - // also a way to pass in an average document size. - if (i < MAX_PAGE_SIZE_READ_AHEAD) { - pageThumbnailComponent = - new PageThumbnailComponent( - controller, scrollPane, pageTree, i, thumbNailZoom); - avgPageWidth += pageThumbnailComponent.getPreferredSize().width; - avgPageHeight += pageThumbnailComponent.getPreferredSize().height; - } else if (i > MAX_PAGE_SIZE_READ_AHEAD) { - pageThumbnailComponent = - new PageThumbnailComponent(controller, scrollPane, pageTree, i, - avgPageWidth, avgPageHeight, thumbNailZoom); - } - // calculate average page size - else if (i == MAX_PAGE_SIZE_READ_AHEAD) { - avgPageWidth /= (MAX_PAGE_SIZE_READ_AHEAD); - avgPageHeight /= (MAX_PAGE_SIZE_READ_AHEAD); - pageThumbnailComponent = - new PageThumbnailComponent(controller, scrollPane, pageTree, i, - avgPageWidth, avgPageHeight, thumbNailZoom); - } - pageThumbsPanel.add(pageThumbnailComponent); - } - - pageThumbsPanel.revalidate(); - scrollPane.validate(); - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AbstractDocumentView.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AbstractDocumentView.java deleted file mode 100644 index 76cb0fad04..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AbstractDocumentView.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.ri.common.tools.*; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.AdjustmentEvent; -import java.awt.event.FocusEvent; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      The AbstractDocumentView class is implemented by the four predefined page views; - * OneColumnPageView, OnePageView, TwoColumnPageView and TwoPageView. Most of - * common work is implemented in this class which aid developers in defining their - * own custom page views.

      - * - * @since 2.5 - */ -public abstract class AbstractDocumentView - extends JComponent - implements DocumentView, PropertyChangeListener, MouseListener { - - private static final Logger logger = - Logger.getLogger(AbstractDocumentView.class.toString()); - - // background colour - public static Color BACKGROUND_COLOUR; - - static { - // sets the shadow colour of the decorator. - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.background.color", "#808080"); - int colorValue = ColorUtil.convertColor(color); - BACKGROUND_COLOUR = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("808080", 16)); - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading page shadow colour"); - } - } - } - - // general layout of page component spacing. - public static int verticalSpace = 2; - public static int horizontalSpace = 1; - public static int layoutInserts = 0; - - protected DocumentViewController documentViewController; - - protected JScrollPane documentScrollpane; - protected JPanel pagesPanel; - protected boolean disposing; - - protected Document currentDocument; - - protected DocumentViewModel documentViewModel; - - // current page view tool. - protected ToolHandler currentTool; - - // mouse wheel zoom, always on regardless of tool ctr-wheel mouse rotation - // for zoom in and out. - protected MouseWheelZoom mouseWheelZoom; - - /** - * Creates a new instance of AbstractDocumentView. - * - * @param documentViewController controller for MVC - * @param documentScrollpane scrollpane used to view pages - * @param documentViewModel model to represent view - */ - public AbstractDocumentView(DocumentViewController documentViewController, - JScrollPane documentScrollpane, - DocumentViewModel documentViewModel) { - this.documentViewController = documentViewController; - this.documentScrollpane = documentScrollpane; - this.documentViewModel = documentViewModel; - - currentDocument = this.documentViewModel.getDocument(); - - setFocusable(true); - // add focus listener - addFocusListener(this); - - // add mouse listener - addMouseListener(this); - - // wheel listener - mouseWheelZoom = new MouseWheelZoom(documentViewController, documentScrollpane); - documentScrollpane.addMouseWheelListener(mouseWheelZoom); - - // listen for scroll bar manipulators - documentViewController.getHorizontalScrollBar().addAdjustmentListener(this); - documentViewController.getVerticalScrollBar().addAdjustmentListener(this); - - // add a focus management listener. - KeyboardFocusManager focusManager = - KeyboardFocusManager.getCurrentKeyboardFocusManager(); - focusManager.addPropertyChangeListener(this); - - } - - public void propertyChange(PropertyChangeEvent evt) { - String prop = evt.getPropertyName(); - Object newValue = evt.getNewValue(); - Object oldValue = evt.getOldValue(); - if ("focusOwner".equals(prop) && - newValue instanceof AnnotationComponent) { - // the correct annotations for the properties pane - if (logger.isLoggable(Level.FINE)) { - logger.fine("Selected Annotation " + newValue); - } - DocumentViewController documentViewController = - getParentViewController(); - documentViewController.firePropertyChange( - PropertyConstants.ANNOTATION_FOCUS_GAINED, - evt.getOldValue(), - evt.getNewValue()); - - } else if ("focusOwner".equals(prop) && - oldValue instanceof AnnotationComponent) { - // the correct annotations for the properties pane - if (logger.isLoggable(Level.FINE)) { - logger.fine("Deselected Annotation " + oldValue); - } - DocumentViewController documentViewController = - getParentViewController(); - documentViewController.firePropertyChange( - PropertyConstants.ANNOTATION_FOCUS_LOST, - evt.getOldValue(), - evt.getNewValue()); - } - } - - public DocumentViewController getParentViewController() { - return documentViewController; - } - - public DocumentViewModel getViewModel() { - return documentViewModel; - } - - public void invalidate() { - super.invalidate(); - pagesPanel.invalidate(); - } - - public void dispose() { - - currentDocument = null; - - // clean up scroll listeners - documentViewController.getHorizontalScrollBar().removeAdjustmentListener(this); - documentViewController.getVerticalScrollBar().removeAdjustmentListener(this); - - // remove custom handlers - if (currentTool != null) { - removeMouseListener(currentTool); - removeMouseMotionListener(currentTool); - } - - // mouse/wheel listener - documentScrollpane.removeMouseWheelListener(mouseWheelZoom); - removeMouseListener(this); - - // focus management - removeFocusListener(this); - // add a focus management listener. - KeyboardFocusManager focusManager = - KeyboardFocusManager.getCurrentKeyboardFocusManager(); - focusManager.removePropertyChangeListener(this); - } - - /** - * invalidates page components - */ - public abstract void updateDocumentView(); - - public ToolHandler uninstallCurrentTool() { - if (currentTool != null) { - currentTool.uninstallTool(); - removeMouseListener(currentTool); - removeMouseMotionListener(currentTool); - if (currentTool instanceof TextSelectionViewHandler) { - documentScrollpane.removeMouseWheelListener((TextSelectionViewHandler) currentTool); - } - } - return currentTool; - } - - public void installCurrentTool(ToolHandler currentTool) { - if (currentTool != null) { - currentTool.installTool(); - addMouseListener(currentTool); - addMouseMotionListener(currentTool); - this.currentTool = currentTool; - } - } - - public ToolHandler getCurrentToolHandler() { - return currentTool; - } - - public void setToolMode(final int viewToolMode) { - uninstallCurrentTool(); - // assign the correct tool handler - switch (viewToolMode) { - case DocumentViewModel.DISPLAY_TOOL_PAN: - currentTool = new PanningHandler(documentViewController, - documentViewModel, this); - break; - case DocumentViewModel.DISPLAY_TOOL_ZOOM_IN: - currentTool = new ZoomInViewHandler(documentViewController, - documentViewModel, this); - break; - case DocumentViewModel.DISPLAY_TOOL_ZOOM_DYNAMIC: - currentTool = new DynamicZoomHandler(documentViewController, - documentScrollpane); - break; - case DocumentViewModel.DISPLAY_TOOL_TEXT_SELECTION: - currentTool = new TextSelectionViewHandler(documentViewController, - documentViewModel, this); - documentScrollpane.addMouseWheelListener((TextSelectionViewHandler) currentTool); - break; - case DocumentViewModel.DISPLAY_TOOL_SELECTION: - currentTool = new AnnotationSelectionHandler( - documentViewController, - null, - documentViewModel); - break; - default: - currentTool = null; - break; - } - if (currentTool != null) { - currentTool.installTool(); - addMouseListener(currentTool); - addMouseMotionListener(currentTool); - } - } - - /** - * Paints the selection box for this page view. - * - * @param g Java graphics context to paint to. - */ - public void paintComponent(Graphics g) { - if (currentTool != null) { - currentTool.paintTool(g); - } - } - - public void adjustmentValueChanged(AdjustmentEvent e) { - - } - - public void focusGained(FocusEvent e) { - - } - - public void focusLost(FocusEvent e) { - - } - - public void mouseClicked(MouseEvent e) { - requestFocus(); - } - - public void mousePressed(MouseEvent e) { - - } - - public void mouseReleased(MouseEvent e) { - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - /** - * Utility method for determining if the mouse event occurred over a - * page in the page view. - * - * @param e mouse event in this coordinates space - * @return component that mouse event is over or null if not over a page. - */ - private AbstractPageViewComponent isOverPageComponent(MouseEvent e) { - // mouse -> page broadcast . - Component comp = findComponentAt(e.getPoint()); - if (comp instanceof AbstractPageViewComponent) { - return (AbstractPageViewComponent) comp; - } else { - return null; - } - } - - public JScrollPane getDocumentScrollpane() { - return documentScrollpane; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AbstractDocumentViewModel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AbstractDocumentViewModel.java deleted file mode 100644 index a8db6faf27..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AbstractDocumentViewModel.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.Memento; -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.PageTree; -import org.icepdf.ri.common.UndoCaretaker; - -import javax.swing.*; -import java.awt.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; -import java.util.logging.Logger; - -/** - *

      The AbstractDocumentViewModel is responsible for keeping the state of the - * document view. The AbstractDocumentViewModel also stores an list of - * PageViewComponents who's state is update as the model changes. The - * AbstractDocumentViewModel can be swapped into different page views quickly - * and efficiently.

      - * - * @see org.icepdf.ri.common.views.DocumentViewModelImpl - * @since 2.5 - */ -public abstract class AbstractDocumentViewModel implements DocumentViewModel { - - private static final Logger log = - Logger.getLogger(AbstractDocumentViewModel.class.toString()); - - // document that model is associated. - protected Document currentDocument; - - // Pages that have selected text. - private HashMap selectedPageText; - // select all state flag, optimization for painting select all state lazily - private boolean selectAll; - protected List pageComponents; - // annotation memento caretaker - protected UndoCaretaker undoCaretaker; - // currently selected annotation - protected AnnotationComponent currentAnnotation; - // page view settings - protected float userZoom = 1.0f, oldUserZoom = 1.0f; - protected float userRotation, oldUserRotation; - protected int currentPageIndex, oldPageIndex; - protected int pageBoundary = Page.BOUNDARY_CROPBOX; - // page tool settings - protected int userToolModeFlag, oldUserToolModeFlag; - - // 10 pages doesn't take to long to look at, any more and people will notice - // the rest of the page sizes will be figured out later. - protected static final int MAX_PAGE_SIZE_READ_AHEAD = 10; - - public AbstractDocumentViewModel(Document currentDocument) { - this.currentDocument = currentDocument; - // create new instance of the undoCaretaker - undoCaretaker = new UndoCaretaker(); - } - - protected abstract AbstractPageViewComponent buildPageViewComponent(DocumentViewModel documentViewModel, - PageTree pageTree, final int pageIndex, - JScrollPane parentScrollPane, - int width, int height); - - public Document getDocument() { - return currentDocument; - } - - public List getPageComponents() { - return pageComponents; - } - - public boolean setViewCurrentPageIndex(int pageIndex) { - boolean changed = pageIndex != currentPageIndex; - oldPageIndex = currentPageIndex; - currentPageIndex = pageIndex; - return changed; - } - - public int getViewCurrentPageIndex() { - return currentPageIndex; - } - - /** - * Gets the list of components that have a selected state. The - * WeakReference must be check to make sure the page was not disposed of - * for for some reason by the the memory manager. - * - * @return list of pages that are in a selected state. - */ - public ArrayList getSelectedPageText() { - if (selectedPageText != null) { - Set keySet = selectedPageText.keySet(); - ArrayList selectedPages = new ArrayList(keySet.size()); - for (Integer pageIndex : keySet) { - selectedPages.add(selectedPageText.get(pageIndex)); - } - return selectedPages; - } else { - return null; - } - } - - /** - * Gets the selected all state of the document pages view. - * - * @return true if all pages are ina selected state, false otherwise. - */ - public boolean isSelectAll() { - return selectAll; - } - - /** - * Sets the select all state of the text in the document. If true the - * document text is all selected; otherwise, false. This is only a flag - * and must be interpreted by the pages and page view components. - * - * @param selectAll to to specify all text is selected, false to specify - * no text is selected - */ - public void setSelectAll(boolean selectAll) { - this.selectAll = selectAll; - } - - /** - * Adds the specified page to selected page cache. No checking is done - * to make sure of selected text. The caches is used as an optimization - * to make sure selected text can be cleared quickly. - * - * @param pageComponent pageView component to add to list. - */ - public void addSelectedPageText(AbstractPageViewComponent pageComponent) { - if (selectedPageText == null) { - selectedPageText = new HashMap(); - } - selectedPageText.put(pageComponent.getPageIndex(), pageComponent); - } - - /** - * Removes the specified page to selected page cache. No checking is done - * to make sure of selected text. The caches is used as an optimization - * to make sure selected text can be cleared quickly. - * - * @param pageComponent pageView component to add to list. - */ - public void removeSelectedPageText(AbstractPageViewComponent pageComponent) { - if (selectedPageText == null) { - selectedPageText = new HashMap(); - } - selectedPageText.remove(pageComponent.getPageIndex()); - } - - /** - * Clears cache used to store which pages have selected state. - */ - public void clearSelectedPageText() { - if (selectedPageText != null) { - selectedPageText.clear(); - } - selectAll = false; - } - - /** - * Sets the zoom factor of the page visualization. A zoom factor of 1.0f - * is equal to 100% or actual size. A zoom factor of 0.5f is equal to 50% - * of the original size. - * - * @param viewZoom zoom factor - * @return if zoom actually changed - */ - public boolean setViewZoom(float viewZoom) { - boolean changed = userZoom != viewZoom; - if (changed) { - // apply the change - oldUserZoom = userZoom; - userZoom = viewZoom; - } - return changed; - } - - public float getViewZoom() { - return userZoom; - } - - public boolean setViewRotation(float viewRotation) { - boolean changed = userRotation != viewRotation; - if (changed) { - // apply the change - oldUserRotation = userRotation; - userRotation = viewRotation; - } - return changed; - } - - /** - * Returns the zoom factor of the page visualization. A zoom factor of 1.0f - * is equal to 100% or actual size. A zoom factor of 0.5f is equal to 50% - * of the original size. - * - * @return zoom factor - */ - public float getViewRotation() { - return userRotation; - } - - public boolean setViewToolMode(final int viewToolMode) { - boolean changed = viewToolMode != userToolModeFlag; - if (changed) { - // apply the change - oldUserToolModeFlag = userToolModeFlag; - userToolModeFlag = viewToolMode; - } - return changed; - } - - public int getViewToolMode() { - return userToolModeFlag; - } - - public boolean isViewToolModeSelected(final int viewToolMode) { - return userToolModeFlag == viewToolMode; - } - - /** - * Sets the page boundary used to paint a page. - * - * @param pageBoundary page bounds - */ - public void setPageBoundary(int pageBoundary) { - this.pageBoundary = pageBoundary; - } - - public int getPageBoundary() { - return pageBoundary; - } - - public Rectangle getPageBounds(int pageIndex) { - Rectangle pageBounds = new Rectangle(); - if (pageComponents != null && pageIndex < pageComponents.size()) { - Component pageViewComponentImpl = pageComponents.get(pageIndex); - if (pageViewComponentImpl != null) { - Component parentComponent = pageViewComponentImpl; - Dimension size = pageViewComponentImpl.getPreferredSize(); - pageBounds.setSize(size.width, size.height); - while (parentComponent != null && - !(parentComponent instanceof DocumentView)) { - pageBounds.x += parentComponent.getBounds().x; - pageBounds.y += parentComponent.getBounds().y; - parentComponent = parentComponent.getParent(); - } - } - } - return pageBounds; - } - - public void dispose() { - - if (pageComponents != null) { - for (AbstractPageViewComponent pageComponent : pageComponents) { - if (pageComponent != null) { - pageComponent.dispose(); - } - } - pageComponents.clear(); - } - } - - /** - * Gets the currently selected annotation in the document model. - * - * @return currently selected annotation, null if there is none. - */ - public AnnotationComponent getCurrentAnnotation() { - return currentAnnotation; - } - - /** - * Sets the current annotation. This is mainly called by the UI tools - * when editing and selecting page annotations. - * - * @param currentAnnotation annotation to make current. - */ - public void setCurrentAnnotation(AnnotationComponent currentAnnotation) { - // clear the previously selected state. - if (this.currentAnnotation != null) { - this.currentAnnotation.setSelected(false); - this.currentAnnotation.repaint(); - } - this.currentAnnotation = currentAnnotation; - // select the new selection if valid - if (this.currentAnnotation != null) { - this.currentAnnotation.setSelected(true); - } - } - - /** - * Gets annotation caretaker responsible for saving states as defined - * by the memento pattern. - * - * @return document level annotation care taker. - */ - public UndoCaretaker getAnnotationCareTaker() { - return undoCaretaker; - } - - public void addMemento(Memento oldMementoState, Memento newMementoState) { - undoCaretaker.addState(oldMementoState, newMementoState); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AbstractPageViewComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AbstractPageViewComponent.java deleted file mode 100644 index e6e115ee37..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AbstractPageViewComponent.java +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.events.PaintPageEvent; -import org.icepdf.core.events.PaintPageListener; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.PageTree; -import org.icepdf.core.util.*; -import org.icepdf.ri.common.views.listeners.DefaultPageViewLoadingListener; -import org.icepdf.ri.common.views.listeners.PageViewLoadingListener; - -import javax.swing.*; -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.lang.ref.SoftReference; -import java.util.concurrent.Callable; -import java.util.concurrent.FutureTask; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * This class contains all the functionality for showing a pages content. This view works closely with the clip - * provided by a parent JScrollPane component to optimize memory usage. Page content is painted to a back buffer - * which is painted by the component when ready. The back buffer is scaled on subsequent paints to show content and - * is later replaced with a new buffer that is painted with the current page properties. - */ -public abstract class AbstractPageViewComponent - extends JLayeredPane - implements PageViewComponent { - - private static final Logger logger = - Logger.getLogger(AbstractPageViewComponent.class.toString()); - - protected static final int PAGE_BOUNDARY_BOX = Page.BOUNDARY_CROPBOX; - - private static Color pageColor; - protected static int pageBufferPadding = 250; - protected static boolean progressivePaint = true; - - static { - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.paper.color", "#FFFFFF"); - int colorValue = ColorUtil.convertColor(color); - pageColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("FFFFFF", 16)); - } catch (NumberFormatException e) { - logger.warning("Error reading page paper color."); - } - // buffer size padding in pixels - pageBufferPadding = Defs.intProperty("org.icepdf.core.views.bufferpadding", 250); - // progressive paint of first page loat. - progressivePaint = Defs.booleanProperty("org.icepdf.core.views.page.progressivePaint", true); - } - - // flags for painting annotations and text highlights. - protected boolean paintAnnotations = true; - protected boolean paintSearchHighlight = false; - - // view mvc parents - protected DocumentView parentDocumentView; - protected DocumentViewModel documentViewModel; - protected DocumentViewController documentViewController; - - // scrollPane is very important for optimization of multiple page views. - protected JScrollPane parentScrollPane; - protected PageTree pageTree; - protected int pageIndex; - - // page properties for a given view state. - protected Rectangle pageSize; - protected float pageZoom, pageRotation; - protected int pageBoundaryBox; - protected PageBufferStore pageBufferStore; - // systems graphics configuration for creating a pages back buffer. - protected GraphicsConfiguration graphicsConfiguration; - - // Main worker task. - protected FutureTask pageImageCaptureTask; - - public AbstractPageViewComponent(DocumentViewModel documentViewModel, PageTree pageTree, - final int pageIndex, JScrollPane parentScrollPane, int width, int height) { - // needed to propagate mouse events. - this.documentViewModel = documentViewModel; - this.parentScrollPane = parentScrollPane; - this.pageTree = pageTree; - this.pageIndex = pageIndex; - - // current state. - if (documentViewModel != null) { - pageZoom = documentViewModel.getViewZoom(); - pageRotation = documentViewModel.getViewRotation(); - pageBoundaryBox = documentViewModel.getPageBoundary(); - } else { - pageZoom = 1.0f; - pageRotation = 0; - pageBoundaryBox = PAGE_BOUNDARY_BOX; - } - - // setup the store for the pageBufferPadding and current clip - pageBufferStore = new PageBufferStore(); - - // initialize page size - pageSize = new Rectangle(); - if (documentViewModel != null && width == 0 && height == 0) { - calculatePageSize(pageSize, documentViewModel.getViewRotation(), documentViewModel.getViewZoom()); - } else { - pageSize.setSize(width, height); - } - } - - public Dimension getPreferredSize() { - return pageSize.getSize(); - } - - public Dimension getSize() { - return pageSize.getSize(); - } - - public void clearSelectedText() { - // on mouse click clear the currently selected sprints - Page currentPage = getPage(); - // clear selected text. - if (currentPage.isInitiated()) { - try { - if (currentPage.getViewText() != null) { - currentPage.getViewText().clearSelected(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - /** - * Sets the text that is contained in the specified rectangle and the - * given mouse pointer. The cursor and selection rectangle must be in - * in page space. - * - * @param cursorLocation location of cursor or mouse. - * @param selection rectangle of text to include in selection. - */ - public void setSelectionRectangle(Point cursorLocation, Rectangle selection) { - - } - - /** - * Clear any internal data structures that represent selected text and - * repaint the component. - */ - public void clearSelectionRectangle() { - - } - - public int getPageIndex() { - return pageIndex; - } - - public Page getPage() { - return pageTree.getPage(pageIndex); - } - - public void setDocumentViewCallback(DocumentView parentDocumentView) { - this.parentDocumentView = parentDocumentView; - documentViewController = this.parentDocumentView.getParentViewController(); - } - - public static boolean isAnnotationTool(final int displayTool) { - return displayTool == DocumentViewModel.DISPLAY_TOOL_SELECTION || - displayTool == DocumentViewModel.DISPLAY_TOOL_LINK_ANNOTATION || - displayTool == DocumentViewModel.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION || - displayTool == DocumentViewModel.DISPLAY_TOOL_SQUIGGLY_ANNOTATION || - displayTool == DocumentViewModel.DISPLAY_TOOL_STRIKEOUT_ANNOTATION || - displayTool == DocumentViewModel.DISPLAY_TOOL_UNDERLINE_ANNOTATION; - } - - /** - * Called from parent controls when a UI control has manipulated the view, property - * change is picked up and the view is updated accordingly. Responds to - * PropertyConstants.DOCUMENT_VIEW_ROTATION_CHANGE and - * PropertyConstants.DOCUMENT_VIEW_ZOOM_CHANGE. If the worker is currently working - * is is cancel with interrupts. - * - * @param propertyConstant document view change property. - * @param oldValue old value - * @param newValue new value - */ - public void updateView(String propertyConstant, Object oldValue, Object newValue) { - if (pageImageCaptureTask != null && !pageImageCaptureTask.isDone()) { - pageImageCaptureTask.cancel(true); - } - if (PropertyConstants.DOCUMENT_VIEW_ROTATION_CHANGE.equals(propertyConstant)) { - pageRotation = (Float) newValue; - } else if (PropertyConstants.DOCUMENT_VIEW_ZOOM_CHANGE.equals(propertyConstant)) { - pageZoom = (Float) newValue; - } else if (PropertyConstants.DOCUMENT_VIEW_REFRESH_CHANGE.equals(propertyConstant)) { - // nothing to do but repaint - } else if (PropertyConstants.DOCUMENT_VIEW_DEMO_MODE_CHANGE.equals(propertyConstant)) { - // re-initialized the page. - pageBufferStore.setDirty(true); - Page page = getPage(); - page.getLibrary().disposeFontResources(); - page.resetInitializedState(); - } - calculatePageSize(pageSize, pageRotation, pageZoom); - pageBufferStore.setDirty(true); - } - - /** - * Checks if this page intersects the viewport - * - * @return true if page is visible in viewport, false otherwise. - * @throws NullPointerException if the parent scrollPane is null. - */ - private boolean isPageIntersectViewport() { - Rectangle pageBounds = documentViewModel != null ? documentViewModel.getPageBounds(pageIndex) : getBounds(); - return pageBounds != null && this.isShowing() && - pageBounds.intersects(parentScrollPane.getViewport().getViewRect()); - } - - /** - * Calculates the page size for the rotation and zoom. The new values are assigned to the pageSize. - * - * @param pageSize rectangle to update, new rectangle will not be created. - * @param rotation rotation of page. - * @param zoom zoom of page - */ - protected void calculatePageSize(Rectangle pageSize, float rotation, float zoom) { - if (pageTree != null) { - Page currentPage = pageTree.getPage(pageIndex); - if (currentPage != null) { - pageSize.setSize(currentPage.getSize(pageBoundaryBox, - rotation, zoom).toDimension()); - } - } - } - - @Override - protected void paintComponent(Graphics g) { - // create a copy so we can set our own state with out affecting the parent graphics conttent. - Graphics2D g2d = (Graphics2D) g.create(0, 0, pageSize.width, pageSize.height); - GraphicsRenderingHints grh = GraphicsRenderingHints.getDefault(); - g2d.setRenderingHints(grh.getRenderingHints(GraphicsRenderingHints.SCREEN)); - // page location in the the entire view. - calculateBufferLocation(); - - // paint the paper - g2d.setColor(pageColor); - g2d.fillRect(0, 0, pageSize.width, pageSize.height); - - // paint the pageBufferPadding, but get the latest copy encase it was returned extra quick - BufferedImage pageImage = pageBufferStore.getImageReference(); - if (pageImage != null) { - Rectangle paintingClip = pageBufferStore.getImageLocation(); - // check if we should scale and rotate the current capture - if (pageZoom != pageBufferStore.getPageZoom() || - pageRotation != pageBufferStore.getPageRotation()) { - g2d.transform(calculateBufferAffineTransform()); - pageBufferStore.setDirty(true); - } - g2d.drawImage(pageImage, paintingClip.x, paintingClip.y, null); - } - g2d.dispose(); - } - - /** - * Calculates where we should be painting the new buffer and kicks off the the worker if the buffer - * is deemed dirty. The Parent scrollpane viewport is taken into account to setup the clipping. - */ - protected void calculateBufferLocation() { - - // grab a reference to the graphics configuration via the AWT thread, if we get it on the worker thread - // it sometimes return null. - graphicsConfiguration = parentScrollPane.getGraphicsConfiguration(); - - // update page size as we may have a page that's larger then the average document size. - calculatePageSize(pageSize, pageRotation, pageZoom); - - // page location in the the entire view. - Rectangle pageLocation = documentViewModel != null ? - documentViewModel.getPageBounds(pageIndex) : new Rectangle(pageSize); - Rectangle viewPort = parentScrollPane.getViewport().getViewRect(); - Rectangle imageLocation; - Rectangle imageClipLocation; - if (pageLocation.width < viewPort.width || pageLocation.height < viewPort.height) { - // if page is smaller then viewport then we use the full page size. - imageLocation = new Rectangle(0, 0, pageLocation.width, pageLocation.height); - imageClipLocation = new Rectangle(imageLocation); - } else { - // otherwise we create a pageBufferPadding based on the viewport size plus some padding - imageClipLocation = viewPort.intersection(pageLocation); - // move the clip relative to page coordinates - imageClipLocation.setLocation( - imageClipLocation.x - pageLocation.x, imageClipLocation.y - pageLocation.y); - // we want the image to be a bit bigger to make scrolling look a little smoother. - imageLocation = new Rectangle(imageClipLocation.x - pageBufferPadding, - imageClipLocation.y - pageBufferPadding, - imageClipLocation.width + pageBufferPadding * 2, - imageClipLocation.height + pageBufferPadding * 2); - // we're using the AWT thread to check for scroll repaints, - if (pageImageCaptureTask != null && pageBufferStore.getImageLocation() != null) { - Rectangle imageAbsoluteLocation = new Rectangle(pageBufferStore.getImageLocation()); - imageAbsoluteLocation.setLocation(imageAbsoluteLocation.x + pageLocation.x, - imageAbsoluteLocation.y + pageLocation.y); - if (!imageAbsoluteLocation.contains(viewPort.intersection(pageLocation))) { - pageBufferStore.setDirty(true); - } - } - } - - // check if we need create or refresh the back pageBufferPadding. - if (pageBufferStore.isDirty() || pageBufferStore.getImageReference() == null) { - // start future task to paint back pageBufferPadding - if (pageImageCaptureTask == null || pageImageCaptureTask.isDone() || pageImageCaptureTask.isCancelled()) { - pageImageCaptureTask = new FutureTask( - new PageImageCaptureTask(this, imageLocation, imageClipLocation, - pageZoom, - pageRotation)); - Library.execute(pageImageCaptureTask); - } - } - } - - /** - * Calculates the affine transform that paints the old buffered image using the current scale and rotation. This - * avoid the back buffer flicker. Once the worker captures the new buffer we swap in the new buffer. - * todo, still needs some work with regards to rotation of the buffer. - * - * @return transform needed to paint the previous out of sync buffer in the correct place. - */ - private AffineTransform calculateBufferAffineTransform() { - AffineTransform at = new AffineTransform(); - if (pageZoom != pageBufferStore.getPageZoom()) { - double pageScale = pageZoom / (double) pageBufferStore.getPageZoom(); - at.scale(pageScale, pageScale); - } - // get the page size of the currently painted image we are trying to scale or rotate. - if (pageRotation != pageBufferStore.getPageRotation()) { - double rotation = 0; - rotation = pageBufferStore.getPageRotation() - pageRotation; - if (rotation < 0) { - rotation += 360; - } - Rectangle imageLocation = pageBufferStore.getPageSize(); - if (rotation == 90) { - at.translate(imageLocation.height, 0); - } else if (rotation == 180) { - at.translate(imageLocation.width, 0); - } else if (rotation == 270) { - at.translate(imageLocation.height, -imageLocation.width); - } - double theta = rotation * Math.PI / 180.0; - at.rotate(theta); - } - return at; - } - - /** - * The worker of any successful page paint. The worker takes a snapshot of the given page state - * and paint the desired image to buffer. One completed the the new buffer is stuffed into - * the pageBufferStore instance with properties so that it can be painted in the correct thread - * when the component is repainted. - */ - public class PageImageCaptureTask implements Callable, PaintPageListener { - - private float zoom; - private float rotation; - private Rectangle imageLocation; - private Rectangle imageClipLocation; - private JComponent parent; - - public PageImageCaptureTask(JComponent parent, Rectangle imageLocation, Rectangle imageClipLocation, - float zoom, float rotation) { - this.zoom = zoom; - this.rotation = rotation; - this.parent = parent; - this.imageLocation = imageLocation; - this.imageClipLocation = imageClipLocation; - } - - public Object call() throws Exception { - if (!isPageIntersectViewport()) { - pageTeardownCallback(); - return null; - } - // paint page. - Page page = pageTree.getPage(pageIndex); - // page loading progress - PageViewLoadingListener pageLoadingListener = new DefaultPageViewLoadingListener(parent, documentViewController); - boolean isFirstProgressivePaint = false; - try { - if (documentViewController != null) page.addPageProcessingListener(pageLoadingListener); - // page init, interruptible - page.init(); - pageInitializedCallback(page); - - BufferedImage pageBufferImage = graphicsConfiguration.createCompatibleImage( - imageLocation.width, imageLocation.height, - BufferedImage.TYPE_INT_ARGB); - Graphics g2d = pageBufferImage.createGraphics(); - - // if we don't have a soft reference then we are likely on a first clean paint at which - // point we can kick off the animated paint. - if (progressivePaint && pageBufferStore.getImageReference() == null) { - page.addPaintPageListener(this); - isFirstProgressivePaint = true; - pageBufferStore.setState(pageBufferImage, imageLocation, imageClipLocation, pageSize, - zoom, rotation, true); - } - g2d.setClip(0, 0, imageLocation.width, imageLocation.height); - g2d.translate(-imageLocation.x, -imageLocation.y); - // paint page interruptible - page.paint(g2d, GraphicsRenderingHints.SCREEN, pageBoundaryBox, rotation, zoom, - paintAnnotations, paintSearchHighlight); - g2d.dispose(); - // init and paint thread went under interrupted, we can move the back pageBufferPadding to the front. - pageBufferStore.setState(pageBufferImage, imageLocation, imageClipLocation, pageSize, - zoom, rotation, false); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.finer("Interrupted page capture task: " + e.getMessage() + " " + pageIndex); - // flush the buffer if this is our first paint. - if (isFirstProgressivePaint) pageBufferStore.setImageReference(null); - } catch (Throwable e) { - logger.log(Level.WARNING, "Error during page capture task: " + e.getMessage() + " " + pageIndex, e); - // avoid a repaint as we'll likely get caught in an infinite loop. - } finally { - page.removePaintPageListener(this); - page.removePageProcessingListener(pageLoadingListener); - } - // queue a repaint, regardless of outcome - SwingUtilities.invokeLater(new Runnable() { - public void run() { - repaint(); - } - }); - - notifyAll(); - return null; - } - - public void paintPage(PaintPageEvent event) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - repaint(); - } - }); - } - } - - /** - * Synchronized page buffer property store, insures that a page capture occurs using the correct properties. - */ - protected class PageBufferStore { - - // last page buffer store, - private SoftReference imageReference; - // paint location if buffer is clipped to be smaller then the page size. - private Rectangle imageLocation; - // location of the current clip, generally the viewport intersection with the page bounds. - private Rectangle imageClipLocation; - private float pageZoom, pageRotation; - // page size at the given zoom and location. - private Rectangle pageSize; - // dirty flag. - private boolean isDirty; - - private final Object objectLock = new Object(); - - PageBufferStore() { - imageReference = new SoftReference(null); - } - - void setState(BufferedImage pageBufferImage, Rectangle imageLocation, Rectangle imageClipLocation, - Rectangle pageSize, float pageZoom, float pageRotation, boolean isDirty) { - synchronized (objectLock) { - this.imageReference = new SoftReference(pageBufferImage); - this.imageLocation = imageLocation; - this.imageClipLocation = imageClipLocation; - this.pageSize = pageSize; - this.pageZoom = pageZoom; - this.pageRotation = pageRotation; - this.isDirty = isDirty; - } - } - - void setImageReference(BufferedImage bufferedImage) { - synchronized (objectLock) { - this.imageReference = new SoftReference(bufferedImage); - } - } - - public BufferedImage getImageReference() { - synchronized (objectLock) { - return imageReference.get(); - } - } - - Rectangle getImageLocation() { - synchronized (objectLock) { - return imageLocation; - } - } - - Rectangle getImageClipLocation() { - synchronized (objectLock) { - return imageClipLocation; - } - } - - Rectangle getPageSize() { - synchronized (objectLock) { - return pageSize; - } - } - - float getPageZoom() { - synchronized (objectLock) { - return pageZoom; - } - } - - float getPageRotation() { - synchronized (objectLock) { - return pageRotation; - } - } - - public boolean isDirty() { - synchronized (objectLock) { - return isDirty; - } - } - - public void setDirty(boolean dirty) { - synchronized (objectLock) { - this.isDirty = dirty; - } - } - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AnnotationCallback.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AnnotationCallback.java deleted file mode 100644 index 6af5ed8c35..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AnnotationCallback.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.actions.Action; -import org.icepdf.core.pobjects.annotations.Annotation; - -/** - *

      Annotation callback allows developers to control how Annotation and - * their actions are executed. Developers also have have the option to - * change annotation visibility attributes such as border style, border color - * and border stroke width before the annotation is painted.

      - * - * @author ICEsoft Technologies, Inc. - * @see org.icepdf.ri.common.views.DocumentViewController#setAnnotationCallback(AnnotationCallback) - * @since 2.6 - */ -public interface AnnotationCallback { - - /** - *

      Implemented Annotation Callback method. When an annotation is activated - * in a PageViewComponent it passes the annotation to this method for - * processing. The PageViewComponent take care of drawing the annotation - * states but it up to this method to process the annotation.

      - *

      Form Widgets submit and reset actions are also handled by this callback.

      - * - * @param annotation annotation that was activated by a user via the - * PageViewComponent. - * @param action the action event that was fired when the annotation was clicked. This can be - * the A or AA entry. - * @param x x-coordinate of input device click that initiated the annotation action. - * @param y y-coordinate of input device click that initiated the annotation action. - */ - public void processAnnotationAction(Annotation annotation, Action action, int x, int y); - - /** - *

      Implemented Annotation Callback method. This method is called when a - * pages annotations been initialized but before the page has been painted. - * This method blocks the

      - * - * @param page page that has been initialized. The pages annotations are - * available via an accessor method. - */ - public void pageAnnotationsInitialized(Page page); - - - /** - * New annotation created with view tool. - * - * @param page page that annotation was added to. - * @param annotationComponent annotation component to be added to page. - */ - public void newAnnotation(PageViewComponent page, - AnnotationComponent annotationComponent); - - /** - * Update the annotation and ready state for save. - * - * @param annotationComponent annotation component to be added to page. - */ - public void updateAnnotation(AnnotationComponent annotationComponent); - - /** - * Remove the annotation and ready state for save. - * - * @param pageComponent page that annotation should be removed. - * @param annotationComponent annotation component to be added to page. - */ - public void removeAnnotation(PageViewComponent pageComponent, - AnnotationComponent annotationComponent); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AnnotationComponent.java deleted file mode 100644 index 3c0600753f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/AnnotationComponent.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.annotations.Annotation; - -/** - * AnnotationComponent interfaces. Oulines two main methods needed for - * management and state saving but avoids having to load the Swing/awt libraries - * unless necessary. - * - * @since 4.0 - */ -public interface AnnotationComponent { - - /** - * Gets wrapped annotation object. - * - * @return annotation that this component wraps. - */ - public Annotation getAnnotation(); - - /** - * Refreshs the annotations bounds rectangle. This method insures that - * the bounds have been correctly adjusted for the current page transformation - * In a none visual representation this method may not have to do anything. - */ - public void refreshDirtyBounds(); - - /** - * Refreshed the annotation rectangle by inverting the components current - * bounds with the current page transformation. - */ - public void refreshAnnotationRect(); - - /** - * Component has focus. - * - * @return true if has focus, false otherwise. - */ - public boolean hasFocus(); - - /** - * Component is editable, contents can be updated in ui - */ - public boolean isEditable(); - - /** - * Component is editable, contents can be updated in ui - */ - public boolean isShowInvisibleBorder(); - - /** - * Component highlight/select border is draw on mouse over. - */ - public boolean isRollover(); - - /** - * Component is movable. - */ - public boolean isMovable(); - - /** - * Component is resizable. - */ - public boolean isResizable(); - - /** - * border has defined style. - * - * @return - */ - public boolean isBorderStyle(); - - public boolean isSelected(); - - public Document getDocument(); - - public int getPageIndex(); - - public PageViewComponent getParentPageView(); - - public void setSelected(boolean selected); - - public void repaint(); - - public void resetAppearanceShapes(); - - public PageViewComponent getPageViewComponent(); - - public void dispose(); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/CollectionDocumentView.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/CollectionDocumentView.java deleted file mode 100644 index 361b918fbc..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/CollectionDocumentView.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.views; - -import org.icepdf.core.pobjects.FileSpecification; -import org.icepdf.core.pobjects.NameTree; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.StringObject; -import org.icepdf.core.util.Library; -import org.icepdf.core.util.Utils; - -import javax.swing.*; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import java.awt.*; -import java.awt.event.AdjustmentEvent; -import java.awt.event.AdjustmentListener; -import java.util.HashMap; -import java.util.List; - -/** - * The CollectionDocumentView is used for documents that specify a PDF Package. - * A PDF package contains a list of embedded files, much like a zip of related - * documents. When initialized each embedded document is represented as an - * thumbnail icon in a flow layout. - * - * @since 5.1.0 - */ -public class CollectionDocumentView extends AbstractDocumentView { - - private static final long serialVersionUID = 7220521612114533227L; - - - public CollectionDocumentView(DocumentViewController documentViewController, - JScrollPane documentScrollpane, DocumentViewModel documentViewModel) { - super(documentViewController, documentScrollpane, documentViewModel); - - // put all the gui elements together - buildGUI(); - } - - private void buildGUI() { - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - - final ModifiedFlowLayout layout = new ModifiedFlowLayout(); - layout.setHgap(15); - layout.setVgap(15); - pagesPanel = new JPanel(layout); - pagesPanel.setBackground(BACKGROUND_COLOUR); - this.setLayout(new BorderLayout()); - this.add(pagesPanel, - BorderLayout.CENTER); - - documentScrollpane.getViewport().addChangeListener(new ChangeListener() { - public void stateChanged(ChangeEvent e) { - JViewport tmp = (JViewport) e.getSource(); - Dimension dim = layout.computeSize(tmp.getWidth(), pagesPanel); - pagesPanel.setPreferredSize(dim); - } - }); - - documentScrollpane.getVerticalScrollBar().addAdjustmentListener( - new AdjustmentListener() { - public void adjustmentValueChanged(AdjustmentEvent e) { - if (!e.getValueIsAdjusting()) { - repaint(); - } - } - }); - - // load the page components into the layout - DocumentViewComponent documentViewComponent; - Library library = currentDocument.getCatalog().getLibrary(); - NameTree embeddedFilesNameTree = currentDocument.getCatalog().getEmbeddedFilesNameTree(); - if (embeddedFilesNameTree != null) { - List filePairs = embeddedFilesNameTree.getNamesAndValues(); - - // add components for every page in the document - for (int i = 0, max = filePairs.size(); i < max; i += 2) { - // get the name and document for - // file name and file specification pairs. - String fileName = Utils.convertStringObject(library, (StringObject) filePairs.get(i)); - HashMap tmp = (HashMap) library.getObject((Reference) filePairs.get(i + 1)); - - // file specification has the document stream - FileSpecification fileSpec = new FileSpecification(library, tmp); - tmp = fileSpec.getEmbeddedFileDictionary(); - - // create the stream instance from the embedded file streams File entry. - Reference fileRef = (Reference) tmp.get(FileSpecification.F_KEY); - - documentViewComponent = new DocumentViewComponent(library, fileName, fileRef); - JPanel documentViewPanel = new JPanel(); - documentViewPanel.setLayout(new BoxLayout(documentViewPanel, BoxLayout.Y_AXIS)); - documentViewPanel.setBackground(BACKGROUND_COLOUR); - PageViewDecorator pageViewComponent = new PageViewDecorator(documentViewComponent); - pageViewComponent.setAlignmentX(Component.CENTER_ALIGNMENT); - documentViewPanel.add(pageViewComponent); - JLabel fileNameLabel = new JLabel(fileName); - fileNameLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - documentViewPanel.add(fileNameLabel); - pagesPanel.add(documentViewPanel); - } - pagesPanel.revalidate(); - documentScrollpane.validate(); - } - } - - @Override - public void dispose() { - super.dispose(); - this.removeMouseListener(this); - pagesPanel.removeAll(); - } - - @Override - public void updateDocumentView() { - - } - - public int getNextPageIncrement() { - return 0; - } - - public int getPreviousPageIncrement() { - return 0; - } - - public Dimension getDocumentSize() { - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/Controller.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/Controller.java deleted file mode 100644 index c40bca26df..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/Controller.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.search.DocumentSearchController; -import org.icepdf.ri.util.PropertiesManager; - -import java.util.ResourceBundle; - -/** - * A Controller is the glue between the model and view components. - * These methods allow the different parts of the view to remain - * in lock-step with each other and have access to the model, - * as necessary - * - * @since 2.0 - */ -public interface Controller { - /** - * A Document is the root of the object hierarchy, giving access - * to the contents of a PDF file. - * Significantly, getDocument().getCatalog().getPageTree().getPage(int pageNumber) - * gives access to each Page, so that it might be drawn. - * - * @return Document root of the PDF file. - */ - public Document getDocument(); - - /** - * When viewing a PDF file, one or more pages may be viewed at - * a single time, but this page is the single page which is most - * predominantly being displayed. - * - * @return The zero-based index of the current Page being displayed - */ - public int getCurrentPageNumber(); - - /** - * Each Page may have its own rotation, but on top of that, the user - * may select to have the Page further rotated by 90, 180 or 270 degrees. - * - * @return The user's requested rotation - */ - public float getUserRotation(); - - /** - * The Page being shown may be zoomed in or out, to show more detail, - * or provide an overview. - * - * @return The user's requested zoom - */ - public float getUserZoom(); - - /** - * Gets controller responsible for Page view UI interaction. - * - * @return document view controller. - */ - public DocumentViewController getDocumentViewController(); - - /** - * Gets controller responsible for the document text searches. - * - * @return page view controller. - */ - public DocumentSearchController getDocumentSearchController(); - - /** - * Sets the tool mode used for the controller view. Tools such as - * text selection, panning and annotation selection can be used. - * - * @param toolType tool mode constants defined in DocumentViewModel - */ - public void setDocumentToolMode(final int toolType); - - /** - * Gets the message bundle used by this class. Message bundle resources - * are loaded via the JVM default locale. - * - * @return message bundle used by this class. - */ - public ResourceBundle getMessageBundle(); - - /** - * Gets the properties manager used to build a dynamically created UI. - * - * @return currently properties manager instance. - */ - public PropertiesManager getPropertiesManager(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentView.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentView.java deleted file mode 100644 index 4fcbd06cff..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentView.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.ri.common.tools.ToolHandler; - -import java.awt.*; -import java.awt.event.AdjustmentListener; -import java.awt.event.FocusListener; - -/** - *

      The DocumentView interface should be used when create a new multipage view.

      - * - * @see org.icepdf.ri.common.views.AbstractDocumentView - * @since 2.5 - */ -public interface DocumentView extends AdjustmentListener, FocusListener { - /** - * Indicates that a two column view will have odd-numbered pages on the left. - */ - public int LEFT_VIEW = 0; - /** - * Indicates that a two column view will have odd-numbered pages on the right. - */ - public int RIGHT_VIEW = 1; - - /** - * Get the next page index. This will number will very depending on the - * page view type. Two column page views usually increment page counts by 2 - * and single page views by 1 page. - * - * @return number of pages to increment page count on a page increment command. - */ - public int getNextPageIncrement(); - - /** - * Get the previous page index. This will number will very depending on the - * page view type. Two column page views usually increment page counts by 2 - * and single page views by 1 page. - * - * @return number of pages to increment page count on a page increment command. - */ - public int getPreviousPageIncrement(); - - /** - * Gets the total size of the document view. This size will very depending - * on the view type. The size dimension has been normalized to a zoom - * factor of 1.0f and rotation is taken care off. - * - * @return size of document in pixels for all pages represented in the view. - */ - public Dimension getDocumentSize(); - - /** - * Parent document view controller - * - * @return document view controller - */ - public DocumentViewController getParentViewController(); - - /** - * Gets the view model associated with this document view. - * - * @return document view model used by this view. - */ - public DocumentViewModel getViewModel(); - - /** - * Dispose all resources associated with this views. - */ - public void dispose(); - - /** - * Update the child components which make up this view. - */ - public void updateDocumentView(); - - /** - * Sets the tool type/mode that is to be enabled for the particular - * view. Mouse and keyboard listeners are associated with this call. No - * actual state is stored in the view this is only for setup purposes. The - * tool state is stored in the DocumentViewModel. - * - * @param viewToolMode tool mode type. - */ - public void setToolMode(final int viewToolMode); - - /** - * Uninstalls the current tool Handler. - * - * @return tool handler taht was removed. - */ - public ToolHandler uninstallCurrentTool(); - - /** - * Installs the current tool handler. - * - * @param currentTool tool ot install. - */ - public void installCurrentTool(ToolHandler currentTool); - - /** - * Component repaint call. - */ - public void repaint(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewComponent.java deleted file mode 100644 index f976645974..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewComponent.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.views; - -import org.icepdf.core.pobjects.*; -import org.icepdf.core.util.GraphicsRenderingHints; -import org.icepdf.core.util.Library; -import org.icepdf.ri.viewer.WindowManager; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.image.BufferedImage; -import java.io.InputStream; -import java.lang.ref.SoftReference; - -/** - * Each document in the collection will be represented by a DocumentViewComponent. - * When double click the respective document will be opened in a new viewer - * window if the file name ends width ".pdf". - * - * @since 5.1.0 - */ -public class DocumentViewComponent extends JComponent implements MouseListener, Runnable { - - private static final long serialVersionUID = -8881023489246309889L; - - private Library parentLibrary; - private Reference fileReference; - private String fileName; - private boolean isPdfDocument; - - public static final String PDF_EXTENSION = ".pdf"; - - private static int minimumThumbHeight = 110; - private static int minimumThumbWidth = 85; - - private Dimension pageSize = new Dimension(minimumThumbWidth, minimumThumbHeight); - private SoftReference documentThumbNail = - new SoftReference(null); - - public DocumentViewComponent(Library parentLibrary, String fileName, Reference fileReference) { - this.parentLibrary = parentLibrary; - this.fileName = fileName; - this.fileReference = fileReference; - - addMouseListener(this); - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - - // grab thread from the library and capture the first page of the document - // and then clean up, as we might never access the document again - isPdfDocument = fileName.toLowerCase().endsWith(PDF_EXTENSION); - if (isPdfDocument) { - Library.execute(this); - } - } - - /** - * Kick off the rendering of the first page for preview purposes, document - * is closed after the thumbnail is created. - */ - public void run() { - - try { - Stream fileStream = (Stream) parentLibrary.getObject(fileReference); - InputStream fileInputStream = fileStream.getDecodedByteArrayInputStream(); - Document embeddedDocument = new Document(); - embeddedDocument.setInputStream(fileInputStream, fileName); - // capture the first page. - Page page = embeddedDocument.getPageTree().getPage(0); - page.init(); - - // calculate how big/small the thumbnail needs to be - PDimension defaultSize = page.getSize(Page.BOUNDARY_CROPBOX, 0, 1f); - float scale = minimumThumbHeight / (float) defaultSize.getHeight(); - pageSize = page.getSize(Page.BOUNDARY_CROPBOX, 0, scale).toDimension(); - - int pageWidth = (int) pageSize.getWidth(); - int pageHeight = (int) pageSize.getHeight(); - - BufferedImage image = ImageUtility.createTranslucentCompatibleImage(pageWidth, pageHeight); - Graphics g = image.createGraphics(); - - page.paint(g, GraphicsRenderingHints.PRINT, - Page.BOUNDARY_CROPBOX, 0, scale); - g.dispose(); - - documentThumbNail = new SoftReference(image); - - // que the repaint. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - revalidate(); - repaint(); - } - }); - - // close the document. - embeddedDocument.dispose(); - - } catch (Throwable ex) { - isPdfDocument = false; - } - } - - public void paintComponent(Graphics gg) { - // paint the thumbnail if any - BufferedImage pageThumbNail = documentThumbNail.get(); - if (pageThumbNail != null) { - Graphics2D g = (Graphics2D) gg; - g.drawImage(pageThumbNail, 0, 0, null); - } - } - - public Dimension getPreferredSize() { - return pageSize; - } - - /** - * On a mouse double click we attempt to lod the PDF document in a new - * viewer window. - * - * @param e mouse event. - */ - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2 && isPdfDocument) { - try { - Stream fileStream = (Stream) parentLibrary.getObject(fileReference); - InputStream fileInputStream = fileStream.getDecodedByteArrayInputStream(); - Document embeddedDocument = new Document(); - embeddedDocument.setInputStream(fileInputStream, fileName); - WindowManager.getInstance().newWindow(embeddedDocument, fileName); - } catch (Throwable ex) { - ex.printStackTrace(); - } - } - } - - public void mousePressed(MouseEvent e) { - - } - - public void mouseReleased(MouseEvent e) { - - } - - public void mouseEntered(MouseEvent e) { - - } - - public void mouseExited(MouseEvent e) { - - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewController.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewController.java deleted file mode 100644 index 143d3d526f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewController.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.SecurityCallback; -import org.icepdf.core.pobjects.Destination; -import org.icepdf.core.pobjects.Document; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.KeyListener; - - -/** - *

      The DocumentViewControllerImpl is the controler in the MVC for multipage view - * management. This controller is used to manipulate the one column, one page, - * two column and two page views.

      - *

      - *

      The Swing implementation of multiple view usesa the folowing MVC base - * classes: - *

      - * - * @see org.icepdf.ri.common.views.AbstractDocumentView - * @see org.icepdf.ri.common.views.AbstractDocumentViewModel - * @see org.icepdf.ri.common.views.DocumentViewControllerImpl - * @since 2.5 - */ -public interface DocumentViewController { - - /** - * Set the view to show the page at the specified zoom level. - */ - public static final int PAGE_FIT_NONE = 1; - - /** - * Set the view to show the page at actual size - */ - public static final int PAGE_FIT_ACTUAL_SIZE = 2; - - /** - * Set the view to show the page at actual size - */ - public static final int PAGE_FIT_WINDOW_HEIGHT = 3; - - /** - * Set the view to show the page at actual size - */ - public static final int PAGE_FIT_WINDOW_WIDTH = 4; - - - public static final int CURSOR_HAND_OPEN = 1; - - public static final int CURSOR_HAND_CLOSE = 2; - - public static final int CURSOR_ZOOM_IN = 3; - - public static final int CURSOR_ZOOM_OUT = 4; - - public static final int CURSOR_WAIT = 6; - - public static final int CURSOR_SELECT = 7; - - public static final int CURSOR_DEFAULT = 8; - - public static final int CURSOR_HAND_ANNOTATION = 9; - - public static final int CURSOR_TEXT_SELECTION = 10; - - public static final int CURSOR_CROSSHAIR = 11; - - public static final int CURSOR_MAGNIFY = 12; - - public void setDocument(Document document); - - public Document getDocument(); - - public void closeDocument(); - - public void dispose(); - - public Container getViewContainer(); - - public Controller getParentController(); - - public void setViewType(final int documentView); - - public int getViewMode(); - - public boolean setFitMode(final int fitMode); - - public int getFitMode(); - - public void setDocumentViewType(final int documentView, final int fitMode); - - public boolean setCurrentPageIndex(int pageNumber); - - public int setCurrentPageNext(); - - public int setCurrentPagePrevious(); - - public void setDestinationTarget(Destination destination); - - public int getCurrentPageIndex(); - - public int getCurrentPageDisplayValue(); - - public void setZoomLevels(float[] zoomLevels); - - public float[] getZoomLevels(); - - public boolean setZoom(float userZoom); - - public boolean setZoomIn(); - - public boolean setZoomIn(Point point); - - boolean setZoomCentered(float zoom, Point centeringPoint, boolean becauseOfValidFitMode); - - boolean setZoomToViewPort(float zoom, Point viewPortPosition, int pageIndex, boolean becauseOfValidFitMode); - - public boolean setZoomOut(); - - public boolean setZoomOut(Point point); - - public float getZoom(); - - public boolean setRotation(float userRotation); - - public float getRotation(); - - public float setRotateRight(); - - public float setRotateLeft(); - - public boolean setToolMode(final int viewToolMode); - - public int getToolMode(); - - public boolean isToolModeSelected(final int viewToolMode); - - public void requestViewFocusInWindow(); - - public void setViewCursor(final int cursorType); - - public Cursor getViewCursor(final int cursorType); - - public int getViewCursor(); - - public void setViewKeyListener(KeyListener l); - - public Adjustable getHorizontalScrollBar(); - - public Adjustable getVerticalScrollBar(); - - public JViewport getViewPort(); - - public void setAnnotationCallback(AnnotationCallback annotationCallback); - - public void setSecurityCallback(SecurityCallback securityCallback); - - public void deleteCurrentAnnotation(); - - public void deleteAnnotation(AnnotationComponent annotationComponent); - - public void undo(); - - public void redo(); - - public AnnotationCallback getAnnotationCallback(); - - public SecurityCallback getSecurityCallback(); - - public DocumentViewModel getDocumentViewModel(); - - public DocumentView getDocumentView(); - - public void clearSelectedText(); - - public void clearHighlightedText(); - - public void clearSelectedAnnotations(); - - public void assignSelectedAnnotation(AnnotationComponent annotationComponent); - - public void selectAllText(); - - public String getSelectedText(); - - public void firePropertyChange(String event, int oldValue, int newValue); - - public void firePropertyChange(String event, Object oldValue, Object newValue); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewControllerImpl.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewControllerImpl.java deleted file mode 100644 index d010a43f05..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewControllerImpl.java +++ /dev/null @@ -1,1316 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.SecurityCallback; -import org.icepdf.core.pobjects.Destination; -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.NamedDestinations; -import org.icepdf.core.pobjects.PageTree; -import org.icepdf.core.search.DocumentSearchController; -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.PopupAnnotationComponent; -import org.icepdf.ri.images.Images; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ComponentEvent; -import java.awt.event.ComponentListener; -import java.awt.event.KeyListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      The DocumentViewControllerImpl is responsible for controlling the four - * default view models specified by the PDF specification. This class is used - * associated with the SwingController, but all view specific control is passed - * to this class.

      - * - * @since 2.5 - */ -@SuppressWarnings("serial") -public class DocumentViewControllerImpl - implements DocumentViewController, ComponentListener, PropertyChangeListener { - - private static final Logger logger = - Logger.getLogger(DocumentViewControllerImpl.class.toString()); - - /** - * Displays a one page at a time view. - */ - public static final int ONE_PAGE_VIEW = 1; - /** - * Displays a the pages in one column. - */ - public static final int ONE_COLUMN_VIEW = 2; - /** - * Displays the pages two at a time, with odd-numbered pages on the left. - */ - public static final int TWO_PAGE_LEFT_VIEW = 3; - /** - * Displays the pages in two columns, with odd-numbered pages on the left. - */ - public static final int TWO_COLUMN_LEFT_VIEW = 4; - /** - * Displays the pages two at a time, with event-numbered pages on the left. - */ - public static final int TWO_PAGE_RIGHT_VIEW = 5; - /** - * Displays the pages in two columns, with even-numbered pages on the left. - */ - public static final int TWO_COLUMN_RIGHT_VIEW = 6; - /** - * Displays the pages in two columns, with even-numbered pages on the left. - */ - public static final int USE_ATTACHMENTS_VIEW = 7; - /** - * Zoom factor used when zooming in or out. - */ - public static final float ZOOM_FACTOR = 1.2F; - /** - * Rotation factor used with rotating document. - */ - public static final float ROTATION_FACTOR = 90F; - - protected float[] zoomLevels; - - protected Document document; - - protected DocumentViewModel documentViewModel; - protected DocumentView documentView; - - protected JScrollPane documentViewScrollPane; - - protected int viewportWidth, oldViewportWidth; - protected int viewportHeight, oldViewportHeight; - protected int viewType, oldViewType; - protected int viewportFitMode, oldViewportFitMode; - protected int cursorType; - protected SwingController viewerController; - protected AnnotationCallback annotationCallback; - protected SecurityCallback securityCallback; - protected PropertyChangeSupport changes = new PropertyChangeSupport(this); - - - public DocumentViewControllerImpl(final SwingController viewerController) { - - this.viewerController = viewerController; - - documentViewScrollPane = new JScrollPane(); - documentViewScrollPane.getViewport().setBackground(AbstractDocumentView.BACKGROUND_COLOUR); - - // set scroll bar speeds - documentViewScrollPane.getVerticalScrollBar().setUnitIncrement(20); - documentViewScrollPane.getHorizontalScrollBar().setUnitIncrement(20); - - // add a delete key functionality for annotation edits. - Action deleteAnnotation = new AbstractAction() { - public void actionPerformed(ActionEvent e) { - if (documentViewModel != null) { - deleteCurrentAnnotation(); - viewerController.reflectUndoCommands(); - } - } - }; - InputMap inputMap = documentViewScrollPane.getInputMap( - JComponent.WHEN_IN_FOCUSED_WINDOW); - inputMap.put(KeyStroke.getKeyStroke("DELETE"), - "removeSelectedAnnotation"); - documentViewScrollPane.getActionMap().put("removeSelectedAnnotation", - deleteAnnotation); - } - - public Document getDocument() { - return document; - } - - - public void setDocument(Document newDocument) { - // clean up any previous documents - if (document != null) { - document.dispose(); - document = null; - } - document = newDocument; - - // clean up old document model and create a new one - if (documentViewModel != null) { - documentViewModel.dispose(); - documentViewModel = null; - } - documentViewModel = createDocumentViewMode(document, documentViewScrollPane); - - // setup view type - setViewType(); - - // remove re-size listener. - documentViewScrollPane.addComponentListener(this); - documentViewScrollPane.validate(); - } - - /** - * Initialize a DocumentViewModel implementation. Can be over ridden to provide custom DocumentViewModel - * implementation. - * - * @param document document that will be opened - * @param documentViewScrollPane parent scrollPane of view. - * @return DocumentViewModel for this view. - */ - protected DocumentViewModel createDocumentViewMode(Document document, JScrollPane documentViewScrollPane) { - return new DocumentViewModelImpl(document, documentViewScrollPane); - } - - // we should be resetting some view settings, mainly zoom, rotation, tool and current page - // Also, null document but do not dispose, this is the responsibility of Controller, we might - // want to inject another document to view. - public void closeDocument() { - - // remove re-size listener. - documentViewScrollPane.removeComponentListener(this); - - // dispose the view - if (documentView != null) { - documentViewScrollPane.remove((JComponent) documentView); - documentView.dispose(); - documentView = null; - } - - // close current document - if (documentViewModel != null) { - documentViewModel.dispose(); - documentViewModel = null; - } - - -// setFitMode(PAGE_FIT_NONE); - setCurrentPageIndex(0); - setZoom(1); - setRotation(0); -// setToolMode(DocumentViewModelImpl.DISPLAY_TOOL_NONE); - setViewCursor(DocumentViewControllerImpl.CURSOR_DEFAULT); - - } - - public Adjustable getHorizontalScrollBar() { - return documentViewScrollPane.getHorizontalScrollBar(); - } - - public Adjustable getVerticalScrollBar() { - return documentViewScrollPane.getVerticalScrollBar(); - } - - public JViewport getViewPort() { - return documentViewScrollPane.getViewport(); - } - - /** - * Set an annotation callback. - * - * @param annotationCallback annotation callback associated with this document - * view. - */ - public void setAnnotationCallback(AnnotationCallback annotationCallback) { - this.annotationCallback = annotationCallback; - } - - public void setSecurityCallback(SecurityCallback securityCallback) { - this.securityCallback = securityCallback; - } - - public void clearSelectedAnnotations() { - if (documentViewModel.getCurrentAnnotation() != null) { - documentViewModel.getCurrentAnnotation().setSelected(false); - // fire change event - firePropertyChange(PropertyConstants.ANNOTATION_DESELECTED, - documentViewModel.getCurrentAnnotation(), - null); - documentViewModel.setCurrentAnnotation(null); - } - } - - public void assignSelectedAnnotation(AnnotationComponent annotationComponent) { - firePropertyChange(PropertyConstants.ANNOTATION_SELECTED, - documentViewModel.getCurrentAnnotation(), - annotationComponent); - documentViewModel.setCurrentAnnotation(annotationComponent); - } - - /** - * Clear selected text in all pages that make up the current document - */ - public void clearSelectedText() { - ArrayList selectedPages = - documentViewModel.getSelectedPageText(); - documentViewModel.setSelectAll(false); - if (selectedPages != null && - selectedPages.size() > 0) { - for (AbstractPageViewComponent pageComp : selectedPages) { - if (pageComp != null && pageComp instanceof PageViewComponentImpl) { - pageComp.clearSelectedText(); - } - } - selectedPages.clear(); - documentView.repaint(); - } - // fire property change - firePropertyChange(PropertyConstants.TEXT_DESELECTED, - null, - null); - - } - - /** - * Clear highlighted text in all pages that make up the current document - */ - public void clearHighlightedText() { - DocumentSearchController searchController = - viewerController.getDocumentSearchController(); - searchController.clearAllSearchHighlight(); - documentView.repaint(); - } - - /** - * Sets the selectAll status flag as true. Text selection requires that - * a pages content has been parsed and can be quite expensive for long - * documents. The page component will pick up on this plag and paint the - * selected state. If the content is copied to the clipboard we go - * thought he motion of parsing every page. - */ - public void selectAllText() { - documentViewModel.setSelectAll(true); - documentView.repaint(); - firePropertyChange(PropertyConstants.TEXT_SELECT_ALL, null, null); - } - - public String getSelectedText() { - StringBuilder selectedText = new StringBuilder(); - try { - // regular page selected by user mouse, keyboard or api - if (!documentViewModel.isSelectAll()) { - ArrayList selectedPages = - documentViewModel.getSelectedPageText(); - if (selectedPages != null && - selectedPages.size() > 0) { - for (AbstractPageViewComponent pageComp : selectedPages) { - if (pageComp != null) { - int pageIndex = pageComp.getPageIndex(); - selectedText.append(document.getPageText(pageIndex).getSelected()); - } - } - } - } - // select all text - else { - Document document = documentViewModel.getDocument(); - // iterate over each page in the document - for (int i = 0; i < document.getNumberOfPages(); i++) { - selectedText.append(viewerController.getDocument().getPageText(i)); - } - } - - } catch (InterruptedException e) { - logger.log(Level.SEVERE, "Page text extraction thread interrupted.", e); - } - return selectedText.toString(); - } - - /** - * Gets the annotation callback. - * - * @return annotation callback associated with this document. - */ - public AnnotationCallback getAnnotationCallback() { - return annotationCallback; - } - - /** - * Gets the security callback. - * - * @return security callback associated with this document. - */ - public SecurityCallback getSecurityCallback() { - return securityCallback; - } - - public DocumentView getDocumentView() { - return documentView; - } - - public synchronized void setViewKeyListener(KeyListener l) { - if (documentView != null) - ((JComponent) documentView).addKeyListener(l); - } - - public void setDestinationTarget(Destination destination) { - - if (documentView == null || documentViewModel == null) { - return; - } - - // check for a named destination def, and if so do the lookup. - NamedDestinations namedDestinations = document.getCatalog().getDestinations(); - if (namedDestinations != null) { - Destination tmp = namedDestinations.getDestination(destination.getNamedDestination()); - if (tmp != null) { - destination = tmp; - } - } - - if (destination == null || destination.getPageReference() == null) { - return; - } - - // get the page number associated with the destination - int pageNumber = getPageTree().getPageNumber(destination.getPageReference()); - if (pageNumber < 0) { - return; - } - - // ready our view port for manipulation - JViewport documentViewport = (documentViewScrollPane != null) ? - documentViewScrollPane.getViewport() : null; - - if (documentViewport != null) { - - // get location of page in document view - Rectangle pageBounds = documentViewModel.getPageBounds(pageNumber); - - // Only apply destination if rotation is 0 - // todo: implement rotation calculation for destination offset - if (documentViewModel.getViewRotation() == 0 && pageBounds != null) { - - setCurrentPageIndex(pageNumber); - - // apply zoom, from destination - if (destination.getZoom() != null && - destination.getZoom() > 0.0f) { - setZoomCentered(destination.getZoom(), null, false); - } - Point newViewPosition = new Point(pageBounds.getLocation()); - float zoom = getZoom(); - - // Process top destination coordinate - Rectangle viewportBounds = ((JComponent) documentView).getBounds(); - Rectangle viewportRect = documentViewport.getViewRect(); - if (logger.isLoggable(Level.FINER)) { - logger.finer("viewPort bounds " + viewportBounds); - logger.finer("viewPort rect " + viewportRect); - logger.finer("page bounds " + pageBounds); - logger.finer("page " + pageNumber); - logger.finer("top/left " + destination.getTop() + " " + destination.getLeft()); - } - if (destination.getTop() != null && destination.getTop() != 0) { - // calculate potential new y value - newViewPosition.y = pageBounds.y + pageBounds.height - (int) (destination.getTop() * zoom); - } - if ((newViewPosition.y + viewportRect.height) > viewportBounds.height) { - newViewPosition.y = viewportBounds.height - viewportRect.height; - } - - // Process left destination coordinate - if (destination.getLeft() != null && destination.getLeft() != 0) { - // calculate potential new y value - newViewPosition.x = pageBounds.x + (int) (destination.getLeft() * zoom); - } - if ((newViewPosition.x + viewportRect.width) > viewportBounds.width) { - newViewPosition.x = viewportBounds.width - viewportRect.width; - } - - // make sure documentViewport is not negative - if (newViewPosition.x < 0) - newViewPosition.x = 0; - if (newViewPosition.y < 0) - newViewPosition.y = 0; - - // finally apply the documentViewport position - documentViewport.setViewPosition(newViewPosition); - int oldPageIndex = documentViewModel.getViewCurrentPageIndex(); - documentViewModel.setViewCurrentPageIndex(pageNumber); - firePropertyChange(PropertyConstants.DOCUMENT_CURRENT_PAGE, - oldPageIndex, pageNumber); - } - // Otherwise go to the indented page number with out applying - // destination coordinates. - else { - setCurrentPageIndex(pageNumber); - } - - viewerController.updateDocumentView(); - } - } - - public void dispose() { - if (documentView != null) { - documentView.dispose(); - documentView = null; - } - if (documentViewModel != null) { - documentViewModel.dispose(); - documentViewModel = null; - } - } - - /** - * The controller will own the scrollpane and will insert different views - * into it. - */ - public Container getViewContainer() { - return documentViewScrollPane; - } - - public Controller getParentController() { - return viewerController; - } - - - public int getViewMode() { - return viewType; - } - - /** - * View Builder for known doc view types - * - * @param documentViewType view type, - */ - public void setViewType(final int documentViewType) { - oldViewType = viewType; - viewType = documentViewType; - // build the new view; - if (documentView != null) { - documentView.uninstallCurrentTool(); - } - setViewType(); - } - - /** - * Revert to the previously set view type. - */ - public void revertViewType() { - viewType = oldViewType; - setViewType(viewType); - } - - /** - * Sets the view type, one column, two column, single page etc. - */ - protected void setViewType() { - - // check if there is current view, if so dispose it - if (documentView != null) { - documentViewScrollPane.remove((JComponent) documentView); - documentViewScrollPane.validate(); - documentView.dispose(); - } - - if (documentViewModel == null) { - return; - } - - // create the desired view with the current viewModel. - createDocumentView(viewType); - - // as it may have been inactive - // notify the view of the tool change - documentView.setToolMode(documentViewModel.getViewToolMode()); - - // add the new view the scroll pane - documentViewScrollPane.setViewportView((Component) documentView); - documentViewScrollPane.validate(); - - // re-apply the fit mode - viewerController.setPageFitMode(viewportFitMode, true); - - // set current page - setCurrentPageIndex(documentViewModel.getViewCurrentPageIndex()); - } - - /** - * Creates the specified view type used by the setVieType() call. Can - * be over ridden to create new or custom views. - * - * @param viewType view type constant - */ - protected void createDocumentView(int viewType) { - if (viewType == ONE_COLUMN_VIEW) { - documentView = - new OneColumnPageView(this, documentViewScrollPane, documentViewModel); - } else if (viewType == ONE_PAGE_VIEW) { - documentView = - new OnePageView(this, documentViewScrollPane, documentViewModel); - } else if (viewType == TWO_COLUMN_LEFT_VIEW) { - documentView = - new TwoColumnPageView(this, documentViewScrollPane, - documentViewModel, - DocumentView.LEFT_VIEW); - } else if (viewType == TWO_PAGE_LEFT_VIEW) { - documentView = - new TwoPageView(this, documentViewScrollPane, - documentViewModel, - DocumentView.LEFT_VIEW); - } else if (viewType == TWO_COLUMN_RIGHT_VIEW) { - documentView = - new TwoColumnPageView(this, documentViewScrollPane, - documentViewModel, - DocumentView.RIGHT_VIEW); - } else if (viewType == TWO_PAGE_RIGHT_VIEW) { - documentView = - new TwoPageView(this, documentViewScrollPane, - documentViewModel, - DocumentView.RIGHT_VIEW); - } else if (viewType == USE_ATTACHMENTS_VIEW) { - documentView = - new CollectionDocumentView(this, documentViewScrollPane, - documentViewModel); - } else { - documentView = - new OneColumnPageView(this, documentViewScrollPane, documentViewModel); - } - - ((JComponent) documentView).addPropertyChangeListener(this); - - } - - public void propertyChange(PropertyChangeEvent evt) { - if (documentView != null) { - String prop = evt.getPropertyName(); - Object newValue = evt.getNewValue(); - Object oldValue = evt.getOldValue(); - // propagate the even to each page. - if (PropertyConstants.DOCUMENT_VIEW_REFRESH_CHANGE.equals(prop) || - PropertyConstants.DOCUMENT_VIEW_DEMO_MODE_CHANGE.equals(prop) || - PropertyConstants.DOCUMENT_VIEW_ZOOM_CHANGE.equals(prop) || - PropertyConstants.DOCUMENT_VIEW_ROTATION_CHANGE.equals(prop)) { - List pageComponents = documentViewModel.getPageComponents(); - for (AbstractPageViewComponent pageViewComponent : pageComponents) { - // pass in zoom, rotation etc, or get form model.... - pageViewComponent.updateView(prop, oldValue, newValue); - } - } - } - } - - public boolean setFitMode(final int fitMode) { - - if (documentViewModel == null || viewType == - DocumentViewControllerImpl.USE_ATTACHMENTS_VIEW) { - return false; - } - - boolean changed = fitMode != viewportFitMode; - viewportFitMode = fitMode; - - if (document != null) { - - // update fit - float newZoom = documentViewModel.getViewZoom(); - if (viewportFitMode == PAGE_FIT_ACTUAL_SIZE) { - newZoom = 1.0f; - } else if (viewportFitMode == PAGE_FIT_WINDOW_HEIGHT) { - if (documentView != null && documentViewScrollPane != null) { - float viewportHeight = documentViewScrollPane.getViewport().getViewRect().height; - float pageViewHeight = documentView.getDocumentSize().height; - - // pageViewHeight insert padding on each side. - pageViewHeight += AbstractDocumentView.layoutInserts * 2; - - if (viewportHeight > 0) { - newZoom = (viewportHeight / pageViewHeight); - } else { - newZoom = 1.0f; - } - } - } else if (viewportFitMode == PAGE_FIT_WINDOW_WIDTH) { - if (documentView != null && documentViewScrollPane != null) { - float viewportWidth = documentViewScrollPane.getViewport().getViewRect().width; - float pageViewWidth = documentView.getDocumentSize().width; - // test if the scroll bar is not present, if so then we - // should consider that the scroll bar will be visible after the - // fit width is applied. - if (!documentViewScrollPane.getVerticalScrollBar().isVisible()) { - viewportWidth -= documentViewScrollPane.getVerticalScrollBar().getWidth(); - } - // add insert padding on each side. - pageViewWidth += AbstractDocumentView.layoutInserts * 2; - - if (viewportWidth > 0) { - newZoom = (viewportWidth / pageViewWidth); - } else { - newZoom = 1.0f; - } - } - } - - // If we're scrolled all the way to the top, center to top of document when zoom, - // otherwise the view will zoom into the general center of the page - if (getVerticalScrollBar().getValue() == 0) { - setZoomCentered(newZoom, new Point(0, 0), true); - } else { - setZoomCentered(newZoom, null, true); - } - } - - return changed; - } - - public int getFitMode() { - return viewportFitMode; - } - - public void setDocumentViewType(final int documentView, final int fitMode) { - setViewType(documentView); - setFitMode(fitMode); - } - - public boolean setCurrentPageIndex(int pageIndex) { - - if (documentViewModel == null) { - return false; - } - - boolean changed; - // make sure that new index is a valid choice. - if (pageIndex < 0) { - pageIndex = 0; - } else if (pageIndex > document.getNumberOfPages() - 1) { - pageIndex = document.getNumberOfPages() - 1; - } - int oldPageIndex = documentViewModel.getViewCurrentPageIndex(); - changed = documentViewModel.setViewCurrentPageIndex(pageIndex); - - if (documentView != null) { - documentView.updateDocumentView(); - } - - // get location of page in view port - Rectangle preferedPageOffset = documentViewModel.getPageBounds(getCurrentPageIndex()); - if (preferedPageOffset != null) { - // scroll the view port to the correct location - Rectangle currentViewSize = ((JComponent) documentView).getBounds(); - - // check to see of the preferedPageOffset will actually be possible. If the - // pages is smaller then the view port we need to correct x,y coordinates. - if (preferedPageOffset.x + preferedPageOffset.width > - currentViewSize.width) { - preferedPageOffset.x = currentViewSize.width - preferedPageOffset.width; - } - - if (preferedPageOffset.y + preferedPageOffset.height > - currentViewSize.height) { - preferedPageOffset.y = currentViewSize.height - preferedPageOffset.height; - } - - documentViewScrollPane.getViewport().setViewPosition(preferedPageOffset.getLocation()); - documentViewScrollPane.revalidate(); - } - firePropertyChange(PropertyConstants.DOCUMENT_CURRENT_PAGE, - oldPageIndex, pageIndex); - - return changed; - } - - public int setCurrentPageNext() { - int increment = 0; - if (documentViewModel != null) { - increment = documentView.getNextPageIncrement(); - int current = documentViewModel.getViewCurrentPageIndex(); - if ((current + increment) < document.getNumberOfPages()) { - documentViewModel.setViewCurrentPageIndex(current + increment); - } else { - documentViewModel.setViewCurrentPageIndex(document.getNumberOfPages() - 1); - } - } - return increment; - } - - public int setCurrentPagePrevious() { - int decrement = 0; - if (documentViewModel != null) { - decrement = documentView.getPreviousPageIncrement(); - int current = documentViewModel.getViewCurrentPageIndex(); - if ((current - decrement) >= 0) { - documentViewModel.setViewCurrentPageIndex(current - decrement); - } else { - documentViewModel.setViewCurrentPageIndex(0); - } - } - return decrement; - } - - public int getCurrentPageIndex() { - if (documentViewModel == null) { - return -1; - } - return documentViewModel.getViewCurrentPageIndex(); - } - - public int getCurrentPageDisplayValue() { - if (documentViewModel == null) { - return -1; - } - return documentViewModel.getViewCurrentPageIndex() + 1; - } - - public float[] getZoomLevels() { - return zoomLevels; - } - - public void setZoomLevels(float[] zoomLevels) { - this.zoomLevels = zoomLevels; - } - - /** - * Sets the zoom factor of the page visualization. A zoom factor of 1.0f - * is equal to 100% or actual size. A zoom factor of 0.5f is equal to 50% - * of the original size. - * - * @param viewZoom zoom factor - * @return if zoom actually changed - */ - public boolean setZoom(float viewZoom) { - return setZoomCentered(viewZoom, null, false); - } - - public boolean setZoomIn() { - return setZoomIn(null); - } - - public boolean setZoomOut() { - return setZoomOut(null); - } - - public float getZoom() { - if (documentViewModel != null) { - return documentViewModel.getViewZoom(); - } else { - return 0; - } - } - - /** - * Returns the zoom factor of the page visualization. A zoom factor of 1.0f - * is equal to 100% or actual size. A zoom factor of 0.5f is equal to 50% - * of the original size. - * - * @return zoom factor - */ - public float getRotation() { - if (documentViewModel == null) { - return -1; - } - return documentViewModel.getViewRotation(); - } - - public float setRotateRight() { - if (documentViewModel == null) { - return -1; - } - float viewRotation = documentViewModel.getViewRotation(); - viewRotation -= ROTATION_FACTOR; - if (viewRotation < 0) - viewRotation += 360; - setRotation(viewRotation); - return viewRotation; - } - - public float setRotateLeft() { - if (documentViewModel == null) { - return -1; - } - float viewRotation = documentViewModel.getViewRotation(); - viewRotation += ROTATION_FACTOR; - viewRotation %= 360; - setRotation(viewRotation); - return viewRotation; - } - - public boolean setRotation(float viewRotation) { - if (documentViewModel == null) { - return false; - } - float oldRotation = documentViewModel.getViewRotation(); - boolean changed = documentViewModel.setViewRotation(viewRotation); - if (changed) { - // send out the property change event. - ((JComponent) documentView).invalidate(); - ((JComponent) documentView).firePropertyChange(PropertyConstants.DOCUMENT_VIEW_ROTATION_CHANGE, oldRotation, viewRotation); - ((JComponent) documentView).revalidate(); - } - return changed; - - } - - public boolean setToolMode(final int viewToolMode) { - - if (documentViewModel != null) { - boolean changed = documentViewModel.setViewToolMode(viewToolMode); - // update the view and page components so the correct tool handler - // can ge assigned. - if (changed) { - // notify the view of the tool change - if (documentView != null) - documentView.setToolMode(viewToolMode); - - // notify the page components of the tool change. - List pageComponents = - documentViewModel.getPageComponents(); - for (AbstractPageViewComponent page : pageComponents) { - ((PageViewComponentImpl) page).setToolMode(viewToolMode); - } - } - return changed; - } else { - return false; - } - } - - public boolean isToolModeSelected(final int viewToolMode) { - return getToolMode() == viewToolMode; - } - - public int getToolMode() { - if (documentViewModel == null) { - return DocumentViewModelImpl.DISPLAY_TOOL_NONE; - } - return documentViewModel.getViewToolMode(); - } - - public void setViewCursor(final int cursorType) { - this.cursorType = cursorType; - Cursor cursor = getViewCursor(cursorType); - if (documentViewScrollPane != null) { - if (documentViewScrollPane.getViewport() != null) - documentViewScrollPane.getViewport().setCursor(cursor); - } - } - - public int getViewCursor() { - return cursorType; - } - - public Cursor getViewCursor(final int currsorType) { - Cursor c; - String imageName; - - if (currsorType == CURSOR_DEFAULT) { - return Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); - } else if (currsorType == CURSOR_WAIT) { - return Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); - } else if (currsorType == CURSOR_SELECT) { - return Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); - } else if (currsorType == CURSOR_HAND_OPEN) { - imageName = "hand_open.gif"; - } else if (currsorType == CURSOR_HAND_CLOSE) { - imageName = "hand_closed.gif"; - } else if (currsorType == CURSOR_ZOOM_IN) { - imageName = "zoom_in.gif"; - } else if (currsorType == CURSOR_ZOOM_OUT) { - imageName = "zoom_out.gif"; - } else if (currsorType == CURSOR_MAGNIFY) { - imageName = "zoom.gif"; - } else if (currsorType == CURSOR_HAND_ANNOTATION) { - return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); - } else if (currsorType == CURSOR_TEXT_SELECTION) { - return Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR); - } else if (currsorType == CURSOR_CROSSHAIR) { - return Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR); - } else { - return Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); - } - - Toolkit tk = Toolkit.getDefaultToolkit(); - Dimension bestSize = tk.getBestCursorSize(24, 24); - if (bestSize.width != 0) { - - Point cursorHotSpot = new Point(12, 12); - try { - ImageIcon cursorImage = new ImageIcon(Images.get(imageName)); - c = tk.createCustomCursor(cursorImage.getImage(), cursorHotSpot, imageName); - } catch (RuntimeException ex) { - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, - "Trying to load image: " + imageName, ex); - } - throw ex; - } - } else { - c = Cursor.getDefaultCursor(); - logger.warning("System does not support custom cursors"); - } - return c; - } - - public void requestViewFocusInWindow() { - if (documentViewScrollPane != null) - documentViewScrollPane.requestFocus(); - } - - /** - * Increases the current page visualization zoom factor by 20%. - * - * @param p Recenter the scrollPane here - */ - public boolean setZoomIn(Point p) { - float zoom = getZoom() * ZOOM_FACTOR; - return setZoomCentered(zoom, p, false); - } - - /** - * Decreases the current page visualization zoom factor by 20%. - * - * @param p Recenter the scrollPane here - */ - public boolean setZoomOut(Point p) { - float zoom = getZoom() / ZOOM_FACTOR; - return setZoomCentered(zoom, p, false); - } - - /** - * Utility function for centering the view Port around the given point. - * - * @param centeringPoint which the view is to be centered on. - */ - private void zoomCenter(Point centeringPoint, float previousZoom, float zoom) { - // make sure the point is not null - if (centeringPoint == null) { - centeringPoint = getCenteringPoint(); - } - - if (centeringPoint == null || documentViewScrollPane == null) - return; - - // get view port information - int viewPortWidth = documentViewScrollPane.getViewport().getWidth(); - int viewPortHeight = documentViewScrollPane.getViewport().getHeight(); - - int scrollPaneX = documentViewScrollPane.getViewport().getViewPosition().x; - int scrollPaneY = documentViewScrollPane.getViewport().getViewPosition().y; - - Dimension pageViewSize = ((JComponent) documentView).getPreferredSize(); - int pageViewWidth = pageViewSize.width; - int pageViewHeight = pageViewSize.height; - - // calculate center coordinates of view port x,y - centeringPoint.setLocation(centeringPoint.x - (viewPortWidth / 2), - centeringPoint.y - (viewPortHeight / 2)); - - // compensate centering point to make sure that preferred site is - // respected when moving the view port x,y. - - // Special case when page height or width is smaller then the viewPort - // size. Respect the zoom but don't try and center on the click - if (pageViewWidth < viewPortWidth || pageViewHeight < viewPortHeight) { - if (centeringPoint.x >= pageViewWidth - viewPortWidth || - centeringPoint.x < 0) { - centeringPoint.x = scrollPaneX; - } - - if (centeringPoint.y >= pageViewHeight - viewPortHeight || - centeringPoint.y < 0) { - centeringPoint.y = scrollPaneY; - } - } - // Special case 2: compensate for click where it is not possible to center - // the page with out shifting the view port paste the pages width - else { - // adjust horizontal - if (centeringPoint.x + viewPortWidth > pageViewWidth) { - centeringPoint.x = (pageViewWidth - viewPortWidth); - } else if (centeringPoint.x < 0) { - centeringPoint.x = 0; - } - - // adjust vertical - if (centeringPoint.y + viewPortHeight > pageViewHeight) { - centeringPoint.y = (pageViewHeight - viewPortHeight); - } else if (centeringPoint.y < 0) { - centeringPoint.y = 0; - } - } - // not sure why, but have to set twice for reliable results - documentViewScrollPane.getViewport().setViewPosition(centeringPoint); - documentViewScrollPane.getViewport().setViewPosition(centeringPoint); - } - - - /** - * Zoom to a new zoom level, centered at a specific point. - * - * @param zoom zoom level which should be in the range of zoomLevels array - * @param becauseOfValidFitMode true will update ui elements with zoom state. - * @param centeringPoint point to center on. - * @return true if the zoom level changed, false otherwise. - */ - public boolean setZoomCentered(float zoom, Point centeringPoint, boolean becauseOfValidFitMode) { - if (documentViewModel == null) { - return false; - } - // make sure the zoom falls in between the zoom range - zoom = calculateZoom(zoom); - - // set a default centering point if null - if (centeringPoint == null) { - centeringPoint = getCenteringPoint(); - } - // grab previous zoom so that zoom factor can be calculated - float previousZoom = getZoom(); - - // apply zoom - float oldZoom = documentViewModel.getViewZoom(); - boolean changed = documentViewModel.setViewZoom(zoom); - - if (changed) { - ((JComponent) documentView).invalidate(); - // send out the property change event. - ((JComponent) documentView).firePropertyChange(PropertyConstants.DOCUMENT_VIEW_ZOOM_CHANGE, oldZoom, zoom); - // get the view port validate the viewport and shift the components - ((JComponent) documentView).revalidate(); - } - // center zoom calculation, find current center and pass - // it along to zoomCenter function. - if (changed && centeringPoint != null) { - centeringPoint.setLocation( - (centeringPoint.x / previousZoom) * zoom, - (centeringPoint.y / previousZoom) * zoom); - } - // still center on click - zoomCenter(centeringPoint, previousZoom, zoom); - - // update the UI controls - if (viewerController != null) { - viewerController.doCommonZoomUIUpdates(becauseOfValidFitMode); - } - - return changed; - } - - private float calculateZoom(float zoom) { - if (zoomLevels != null) { - if (zoom < zoomLevels[0]) - zoom = zoomLevels[0]; - else if (zoom > zoomLevels[zoomLevels.length - 1]) - zoom = zoomLevels[zoomLevels.length - 1]; - } - return zoom; - } - - /** - * Zoom to a new zoom level, the viewPort position is set by the addition - * of the zoomPointDelta to the page bounds as defined by the view. - * - * @param zoom zoom level which should be in the range of zoomLevels array - * @param becauseOfValidFitMode true will update ui elements with zoom state. - * @param zoomPointDelta point to center on. - * @param pageIndex page to zoom in on. - * @return true if the zoom level changed, false otherwise. - */ - public boolean setZoomToViewPort(float zoom, Point zoomPointDelta, int pageIndex, - boolean becauseOfValidFitMode) { - if (documentViewModel == null) { - return false; - } - // make sure the zoom falls in between the zoom range - zoom = calculateZoom(zoom); - - // set a default centering point if null - if (zoomPointDelta == null) { - zoomPointDelta = new Point(); - } - // grab previous zoom so that zoom factor can be calculated - float previousZoom = getZoom(); - // apply zoom - boolean changed = documentViewModel.setViewZoom(zoom); - if (changed) { - ((JComponent) documentView).firePropertyChange(PropertyConstants.DOCUMENT_VIEW_ZOOM_CHANGE, previousZoom, zoom); - documentViewScrollPane.invalidate(); - documentViewScrollPane.validate(); - documentViewScrollPane.getViewport().getView().invalidate(); - documentViewScrollPane.getViewport().getView().validate(); - } - - // center zoom calculation, find current center and pass - // it along to zoomCenter function. - if (changed) { - Rectangle bounds = documentViewModel.getPageBounds(pageIndex); - zoomPointDelta.setLocation( - (zoomPointDelta.x / previousZoom) * zoom, - (zoomPointDelta.y / previousZoom) * zoom); - zoomPointDelta.setLocation(bounds.x + zoomPointDelta.x, - bounds.y + zoomPointDelta.y); - // view hasn't been update yet so we double set the position to make it take effect. - getViewPort().setViewPosition(zoomPointDelta); - getViewPort().setViewPosition(zoomPointDelta); - } - - // update the UI controls - if (viewerController != null) { - viewerController.doCommonZoomUIUpdates(becauseOfValidFitMode); - } - - return changed; - } - - - /** - * Utility method for finding the center point of the viewport - * - * @return current center of view port. - */ - private Point getCenteringPoint() { - Point centeringPoint = null; - if (documentViewScrollPane != null) { - int x = documentViewScrollPane.getViewport().getViewPosition().x + - (documentViewScrollPane.getViewport().getWidth() / 2); - int y = documentViewScrollPane.getViewport().getViewPosition().y + - (documentViewScrollPane.getViewport().getHeight() / 2); - centeringPoint = new Point(x, y); - } - return centeringPoint; - } - - /** - * Gives access to the currently openned Document's Catalog's PageTree - * - * @return PageTree - */ - private PageTree getPageTree() { - if (document == null) - return null; - return document.getPageTree(); - } - - public DocumentViewModel getDocumentViewModel() { - return documentViewModel; - } - - // - // ComponentListener interface - // - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void componentHidden(ComponentEvent e) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void componentMoved(ComponentEvent e) { - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void componentResized(ComponentEvent e) { - Object src = e.getSource(); - if (src == null) - return; - // we need to update the document view, if fit width of fit height is - // selected we need to adjust the zoom level appropriately. - if (src == documentViewScrollPane) { - setFitMode(getFitMode()); - } - } - - /** - * SwingController takes AWT/Swing events, and maps them to its own events - * related to PDF Document manipulation - */ - public void componentShown(ComponentEvent e) { - - } - - public void firePropertyChange(String event, int oldValue, int newValue) { - changes.firePropertyChange(event, oldValue, newValue); - } - - /** - * Fires property change events for Page view UI changes such as: - *
    • focus gained/lost
    • - *
    • annotation state change such as move or resize
    • - *
    • new annotation crreated, currently only for new link annotations
    • - *
    • - * - * @param event property being changes - * @param oldValue old value, null if no old value - * @param newValue new annotation value. - */ - public void firePropertyChange(String event, Object oldValue, - Object newValue) { - changes.firePropertyChange(event, oldValue, newValue); - } - - public void addPropertyChangeListener(PropertyChangeListener l) { - changes.addPropertyChangeListener(l); - } - - public void deleteCurrentAnnotation() { - AbstractAnnotationComponent annotationComponent = (AbstractAnnotationComponent) - documentViewModel.getCurrentAnnotation(); - if (!(annotationComponent instanceof PopupAnnotationComponent)) { - deleteAnnotation(annotationComponent); - } - } - - public void deleteAnnotation(AnnotationComponent annotationComponent) { - if (documentViewModel != null && annotationComponent != null) { - - // parent component - PageViewComponent pageComponent = - annotationComponent.getPageViewComponent(); - - if (annotationCallback != null) { - annotationCallback.removeAnnotation(pageComponent, annotationComponent); - } - - // fire event notification - firePropertyChange(PropertyConstants.ANNOTATION_DELETED, - documentViewModel.getCurrentAnnotation(), - null); - - // clear previously selected annotation and fire event. - assignSelectedAnnotation(null); - - // repaint the view. - documentView.repaint(); - } - } - - public void undo() { - // repaint the view. - documentView.repaint(); - } - - public void redo() { - // repaint the view. - documentView.repaint(); - } - - public void removePropertyChangeListener(PropertyChangeListener l) { - changes.removePropertyChangeListener(l); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewModel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewModel.java deleted file mode 100644 index 6e61a5df53..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewModel.java +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.Memento; -import org.icepdf.core.pobjects.Document; - -import java.awt.*; -import java.util.ArrayList; -import java.util.List; - -/** - * The DocumentViewModel interface contains common accessors and modifiers needed - * to represent a document view state. - * - * @see org.icepdf.ri.common.views.AbstractDocumentViewModel - * @since 2.5 - */ -public interface DocumentViewModel { - /** - * Display tool constant for adding a pan tool. - */ - public int DISPLAY_TOOL_PAN = 1; - /** - * Display tool constant for adding a zoom in tool. - */ - public int DISPLAY_TOOL_ZOOM_IN = 2; - /** - * Display tool constant for adding a zoom out tool. - */ - public int DISPLAY_TOOL_ZOOM_OUT = 3; - /** - * Display tool constant for adding a zoom out tool. - */ - public int DISPLAY_TOOL_ZOOM_DYNAMIC = 4; - /** - * Display tool constant for adding a text selection tool. - */ - public int DISPLAY_TOOL_TEXT_SELECTION = 5; - /** - * Display tool constant for adding a text selection tool. - */ - public int DISPLAY_TOOL_SELECTION = 6; - /** - * Display tool constant for creating new link annotation. - */ - public int DISPLAY_TOOL_LINK_ANNOTATION = 7; - /** - * Display tool constant for creating new highlight annotation. - */ - public int DISPLAY_TOOL_HIGHLIGHT_ANNOTATION = 8; - /** - * Display tool constant for creating new underline annotation. - */ - public int DISPLAY_TOOL_UNDERLINE_ANNOTATION = 9; - /** - * Display tool constant for creating new squiggly annotation. - */ - public int DISPLAY_TOOL_SQUIGGLY_ANNOTATION = 10; - /** - * Display tool constant for creating new strikeout annotation. - */ - public int DISPLAY_TOOL_STRIKEOUT_ANNOTATION = 11; - - /** - * Display tool constant for creating new line annotation. - */ - public int DISPLAY_TOOL_LINE_ANNOTATION = 12; - - /** - * Display tool constant for creating new line annotation. - */ - public int DISPLAY_TOOL_LINE_ARROW_ANNOTATION = 13; - - /** - * Display tool constant for creating new line annotation. - */ - public int DISPLAY_TOOL_SQUARE_ANNOTATION = 14; - - /** - * Display tool constant for creating new line annotation. - */ - public int DISPLAY_TOOL_CIRCLE_ANNOTATION = 15; - - /** - * Display tool constant for creating new line annotation. - */ - public int DISPLAY_TOOL_INK_ANNOTATION = 16; - - /** - * Display tool constant for creating new line annotation. - */ - public int DISPLAY_TOOL_FREE_TEXT_ANNOTATION = 17; - - /** - * Display tool constant for creating new line annotation. - */ - public int DISPLAY_TOOL_TEXT_ANNOTATION = 18; - - /** - * Display tool constant for setting no tools - */ - public int DISPLAY_TOOL_NONE = 50; - /** - * Display tool constant for showing user that gui is busy - */ - public int DISPLAY_TOOL_WAIT = 51; - - /** - * Gets the PDF document object associated with this views. - * - * @return PDF document which is associated with this view. - */ - public Document getDocument(); - - /** - * Gets a list of document pages that have selected text elements. The - * pages are referenced so that they will be removed automatically if - * the memory manage needs to dispose of a page. - * - * @return list Weakly referenced pages - */ - public ArrayList getSelectedPageText(); - - /** - * Adds the specified page to the list of selected pages. - * - * @param pageComponent pageView component to add to list. - */ - public void addSelectedPageText(AbstractPageViewComponent pageComponent); - - /** - * Remove the specified page to the list of selected pages. - * - * @param pageComponent pageView component to add to list. - */ - public void removeSelectedPageText(AbstractPageViewComponent pageComponent); - - /** - * Returns true if all text in the document should be in a selected state. - * - * @return true if document is in select all text text state, false otherwise. - */ - public boolean isSelectAll(); - - /** - * Sets the selected all text state. - * - * @param selectAll true to select all text, false otherwise. - */ - public void setSelectAll(boolean selectAll); - - /** - * Clears all pages in a selected state. - */ - public void clearSelectedPageText(); - - /** - * Gets the page components associated with this view model. - * - * @return vector of page components. - */ - public List getPageComponents(); - - /** - * Sets the view model current page index. - * - * @param pageIndex zero based current pages page index of the document. - * @return true if the page index could be set, false otherwise. - */ - public boolean setViewCurrentPageIndex(int pageIndex); - - /** - * Gets the current page index represented in this model. - * - * @return zero based page page index. - */ - public int getViewCurrentPageIndex(); - - /** - * Sets the models zoom level. - * - * @param viewZoom zoom value - * @return true if the view zoom was set correctly otherwise, false. - */ - public boolean setViewZoom(float viewZoom); - - /** - * Gets the view model zoom level. - * - * @return zoom level of this view model - */ - public float getViewZoom(); - - /** - * Sets the view rotation of this model. - * - * @param viewRotation rotation in degrees - * @return true if the view rotation was set correctly, otherwise false. - */ - public boolean setViewRotation(float viewRotation); - - /** - * Gets the view rotation of the model. - * - * @return view rotation of the model - */ - public float getViewRotation(); - - /** - * Sets the view tool mode. - * - * @param viewToolMode selected tool mode, pan, zoom and et. - * @return true if the view tool was set correctly, false otherwise. - */ - public boolean setViewToolMode(int viewToolMode); - - /** - * Gets the tool mode. - * - * @return tool mode. - */ - public int getViewToolMode(); - - /** - * Checks if the specified tool mode is set in the view model. - * - * @param viewToolMode tool model to check if selected. - * @return true if specified tool mode is selected, otherwise false. - */ - public boolean isViewToolModeSelected(int viewToolMode); - - /** - * Gets the page bound of the specified page Index. - * - * @param pageIndex zero based page index. - * @return bounds of specified page. If page index. is not valid, null is returned. - */ - public Rectangle getPageBounds(int pageIndex); - - /** - * Free resources associated with this model. - */ - public void dispose(); - - /** - * Sets the page boundtry used to paint a page. - * - * @param pageBoundary page bounds - */ - public void setPageBoundary(final int pageBoundary); - - /** - * Gets the page boundary used to paint document pages. - * - * @return page boundary type as defined in the class Page. - */ - public int getPageBoundary(); - - /** - * Gets the currently selected annotation - * - * @return currently selected annotations. - */ - public AnnotationComponent getCurrentAnnotation(); - - /** - * Sets teh current annotation - * - * @param currentAnnotation annotation to set as current - */ - public void setCurrentAnnotation(AnnotationComponent currentAnnotation); - - /** - * Adds memento state to the care taker. - * - * @param oldMementoState original state. - * @param newMementoState new state. - */ - public void addMemento(Memento oldMementoState, - Memento newMementoState); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewModelImpl.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewModelImpl.java deleted file mode 100644 index 067acc99bb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/DocumentViewModelImpl.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.PageTree; - -import javax.swing.*; -import java.util.ArrayList; - -/** - *

      Default Swing implementation of the AbstractDocumentViewModel class. The - * constructor for this class constructs the needed PageViewComponentImpl objects - * and associates a reference to the parent JScrollPane.

      - *

      - *

      Swing specific setup is handle by this class.

      - * - * @since 2.5 - */ -public class DocumentViewModelImpl extends AbstractDocumentViewModel { - - public DocumentViewModelImpl(Document document, JScrollPane parentScrollPane) { - // construct abstract parent - super(document); - - // load the page components into the layout - AbstractPageViewComponent pageViewComponent = null; - PageTree pageTree = document.getPageTree(); - int numberOfPages = document.getNumberOfPages(); - int avgPageWidth = 0; - int avgPageHeight = 0; - - // add components for every page in the document - pageComponents = new ArrayList(numberOfPages); - for (int i = 0; i < numberOfPages; i++) { - // also a way to pass in an average document size. - if (i < MAX_PAGE_SIZE_READ_AHEAD) { - pageViewComponent = - buildPageViewComponent(this, pageTree, i, parentScrollPane, 0, 0); - avgPageWidth += pageViewComponent.getPreferredSize().width; - avgPageHeight += pageViewComponent.getPreferredSize().height; - } else if (i > MAX_PAGE_SIZE_READ_AHEAD) { - pageViewComponent = - buildPageViewComponent(this, pageTree, i, - parentScrollPane, - avgPageWidth, avgPageHeight); - } - // calculate average page size - else if (i == MAX_PAGE_SIZE_READ_AHEAD) { - avgPageWidth /= (MAX_PAGE_SIZE_READ_AHEAD); - avgPageHeight /= (MAX_PAGE_SIZE_READ_AHEAD); - pageViewComponent = buildPageViewComponent(this, pageTree, i, - parentScrollPane, - avgPageWidth, avgPageHeight); - } - pageComponents.add(pageViewComponent); - } - } - - protected AbstractPageViewComponent buildPageViewComponent( - DocumentViewModel documentViewModel, PageTree pageTree, final int pageIndex, - JScrollPane parentScrollPane, int width, int height){ - return new PageViewComponentImpl(this, pageTree, pageIndex, parentScrollPane, width, height); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/ModifiedFlowLayout.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/ModifiedFlowLayout.java deleted file mode 100644 index 18c395f718..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/ModifiedFlowLayout.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.views; - -import java.awt.*; - -/** - * Modified Flow layout allos the layout to be recalculated when parent container - * is resized. - */ -public class ModifiedFlowLayout extends FlowLayout { - - private static final long serialVersionUID = -5384365489254593185L; - - public ModifiedFlowLayout() { - super(); - } - - public Dimension computeSize(int w, Container target) { - synchronized (target.getTreeLock()) { - int hgap = getHgap(); - int vgap = getVgap(); - - if (w == 0) - w = Integer.MAX_VALUE; - - Insets insets = target.getInsets(); - if (insets == null) - insets = new Insets(0, 0, 0, 0); - int reqdWidth = 0; - - int maxwidth = w - (insets.left + insets.right + hgap * 2); - int n = target.getComponentCount(); - int x = 0; - int y = insets.top + vgap; - int rowHeight = 0; - - for (int i = 0; i < n; i++) { - Component c = target.getComponent(i); - if (c.isVisible()) { - Dimension d = c.getPreferredSize(); - if ((x == 0) || ((x + d.width) <= maxwidth)) { - // fits in current row. - if (x > 0) { - x += hgap; - } - x += d.width; - rowHeight = Math.max(rowHeight, d.height); - } else { - x = d.width; - y += vgap + rowHeight; - rowHeight = d.height; - } - reqdWidth = Math.max(reqdWidth, x); - } - } - y += rowHeight; - y += insets.bottom; - return new Dimension(reqdWidth + insets.left + insets.right, y); - } - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/OneColumnPageView.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/OneColumnPageView.java deleted file mode 100644 index 4e3b85e0df..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/OneColumnPageView.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.ri.common.CurrentPageChanger; -import org.icepdf.ri.common.KeyListenerPageColumnChanger; -import org.icepdf.ri.common.SwingController; - -import javax.swing.*; -import java.awt.*; -import java.util.List; - - -/** - *

      Constructs a one column page view as defined in the PDF specification. A one - * column page view displays pages continuously in one column.

      - *

      - *

      Page views are basic containers which use Swing Layout Containers to - * place pages

      - * - * @since 2.5 - */ -@SuppressWarnings("serial") -public class OneColumnPageView extends AbstractDocumentView { - - // specialized listeners for different gui operations - protected CurrentPageChanger currentPageChanger; - - protected KeyListenerPageColumnChanger keyListenerPageChanger; - - public OneColumnPageView(DocumentViewController documentDocumentViewController, - JScrollPane documentScrollpane, - DocumentViewModel documentViewModel) { - - super(documentDocumentViewController, documentScrollpane, documentViewModel); - - // used to redirect mouse events - this.documentScrollpane = documentScrollpane; - - // put all the gui elements together - buildGUI(); - - // add the first of many tools need for this views and others like it. - currentPageChanger = - new CurrentPageChanger(documentScrollpane, this, - documentViewModel.getPageComponents()); - - // add page changing key listeners - if (this.documentViewController.getParentController() instanceof SwingController) { - keyListenerPageChanger = - KeyListenerPageColumnChanger.install((SwingController) this.documentViewController.getParentController(), - this.documentScrollpane, this, currentPageChanger); - } - } - - private void buildGUI() { - // add all page components to grid layout panel - pagesPanel = new JPanel(); - pagesPanel.setBackground(BACKGROUND_COLOUR); - // one column equals single page view continuous - GridLayout gridLayout = new GridLayout(0, 1, horizontalSpace, verticalSpace); - pagesPanel.setLayout(gridLayout); - - // use a grid bag to center the page component panel - GridBagConstraints gbc = new GridBagConstraints(); - gbc.weighty = 1.0; // allows vertical resizing - gbc.weightx = 1.0; // allows horizontal resizing - gbc.insets = // component spacer [top, left, bottom, right] - new Insets(layoutInserts, layoutInserts, layoutInserts, layoutInserts); - gbc.gridwidth = GridBagConstraints.REMAINDER; // one component per row - - this.setLayout(new GridBagLayout()); - this.add(pagesPanel, gbc); - - // finally add all the components - // add components for every page in the document - List pageComponents = - documentViewModel.getPageComponents(); - - if (pageComponents != null) { - for (PageViewComponent pageViewComponent : pageComponents) { - if (pageViewComponent != null) { - pageViewComponent.setDocumentViewCallback(this); - // add component to layout - pagesPanel.add(new PageViewDecorator( - (AbstractPageViewComponent) pageViewComponent)); - } - } - } - } - - // nothing needs to be done for a column view as all components are already - // available - public void updateDocumentView() { - } - - /** - * Returns a next page increment of one. - */ - public int getNextPageIncrement() { - return 1; - } - - /** - * Returns a previous page increment of one. - */ - public int getPreviousPageIncrement() { - return 1; - } - - public void dispose() { - disposing = true; - // remove utilities - if (currentPageChanger != null) { - currentPageChanger.dispose(); - } - if (keyListenerPageChanger != null) { - keyListenerPageChanger.uninstall(); - } - - // trigger a re-layout - pagesPanel.removeAll(); - pagesPanel.invalidate(); - - // make sure we call super. - super.dispose(); - } - - public Dimension getDocumentSize() { - float pageViewWidth = 0; - float pageViewHeight = 0; - if (pagesPanel != null) { - int currCompIndex = documentViewController.getCurrentPageIndex(); - int numComponents = pagesPanel.getComponentCount(); - if (currCompIndex >= 0 && currCompIndex < numComponents) { - Component comp = pagesPanel.getComponent(currCompIndex); - if (comp instanceof PageViewDecorator) { - PageViewDecorator pvd = (PageViewDecorator) comp; - Dimension dim = pvd.getPreferredSize(); - pageViewWidth = dim.width; - pageViewHeight = dim.height; - } - } - } - // normalize the dimensions to a zoom level of zero. - float currentZoom = documentViewModel.getViewZoom(); - pageViewWidth = Math.abs(pageViewWidth / currentZoom); - pageViewHeight = Math.abs(pageViewHeight / currentZoom); - - // add any horizontal padding from layout manager - pageViewWidth += AbstractDocumentView.horizontalSpace * 2; - pageViewHeight += AbstractDocumentView.verticalSpace * 2; - return new Dimension((int) pageViewWidth, (int) pageViewHeight); - } - - public void paintComponent(Graphics g) { - Rectangle clipBounds = g.getClipBounds(); - // paint background gray - g.setColor(BACKGROUND_COLOUR); - g.fillRect(clipBounds.x, clipBounds.y, clipBounds.width, clipBounds.height); - // paint selection box - super.paintComponent(g); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/OnePageView.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/OnePageView.java deleted file mode 100644 index 7943f5b210..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/OnePageView.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.ri.common.KeyListenerPageChanger; -import org.icepdf.ri.common.MouseWheelListenerPageChanger; -import org.icepdf.ri.common.SwingController; - -import javax.swing.*; -import java.awt.*; - -/** - *

      Constructs a one page view as defined in the PDF specification. A one - * page view displays one page at a time.

      - *

      - *

      Page views are basic containers which use Swing Layout Containers to - * place pages

      - * - * @since 2.5 - */ -@SuppressWarnings("serial") -public class OnePageView extends AbstractDocumentView { - - protected Object pageChangerListener; - - protected KeyListenerPageChanger keyListenerPageChanger; - - - public OnePageView(DocumentViewController documentDocumentViewController, - JScrollPane documentScrollpane, - DocumentViewModel documentViewModel) { - - super(documentDocumentViewController, documentScrollpane, documentViewModel); - - // used to redirect mouse events - this.documentScrollpane = documentScrollpane; - - // put all the gui elements together - buildGUI(); - - // add page changing key listeners - if (this.documentViewController.getParentController() instanceof SwingController) { - pageChangerListener = - MouseWheelListenerPageChanger.install( - (SwingController) this.documentViewController.getParentController(), - this.documentScrollpane, this); - - keyListenerPageChanger = - KeyListenerPageChanger.install( - (SwingController) this.documentViewController.getParentController(), - this.documentScrollpane, this); - } - - } - - private void buildGUI() { - // add all page components to gridlayout panel - pagesPanel = new JPanel(); - pagesPanel.setBackground(BACKGROUND_COLOUR); - // one column equals single page view continuous - GridLayout gridLayout = new GridLayout(0, 1, horizontalSpace, verticalSpace); - pagesPanel.setLayout(gridLayout); - - // use a gridBag to center the page component panel - GridBagConstraints gbc = new GridBagConstraints(); - gbc.weighty = 1.0; // allows vertical resizing - gbc.weightx = 1.0; // allows horizontal resizing - gbc.insets = // component spacer [top, left, bottom, right] - new Insets(layoutInserts, layoutInserts, layoutInserts, layoutInserts); - gbc.gridwidth = GridBagConstraints.REMAINDER; // one component per row - - // finally add all the components - // add components for every page in the document - updateDocumentView(); - - this.setLayout(new GridBagLayout()); - this.add(pagesPanel, gbc); - - } - - public void updateDocumentView() { - - java.util.List pageComponents = - documentViewModel.getPageComponents(); - - if (pageComponents != null) { - - PageViewComponent pageViewComponent = - pageComponents.get(documentViewModel.getViewCurrentPageIndex()); - if (pageViewComponent != null) { - - // remove old component - pagesPanel.removeAll(); - - pageViewComponent.setDocumentViewCallback(this); - // add component to layout - pagesPanel.add(new PageViewDecorator( - (AbstractPageViewComponent) pageViewComponent)); - ((AbstractPageViewComponent) pageViewComponent).validate(); - } - - // make sure we have setup all pages with callback call. - for (PageViewComponent pageViewCom : pageComponents) { - if (pageViewCom != null) { - pageViewCom.setDocumentViewCallback(this); - } - } - } - } - - /** - * Returns a next page increment of one. - */ - public int getNextPageIncrement() { - return 1; - } - - /** - * Returns a previous page increment of one. - */ - public int getPreviousPageIncrement() { - return 1; - } - - public void dispose() { - disposing = true; - // remove utilities - if (pageChangerListener != null) { - MouseWheelListenerPageChanger.uninstall(documentScrollpane, - pageChangerListener); - } - if (keyListenerPageChanger != null) { - keyListenerPageChanger.uninstall(); - } - - // trigger a re-layout - pagesPanel.removeAll(); - pagesPanel.invalidate(); - - // make sure we call super. - super.dispose(); - } - - public Dimension getDocumentSize() { - float pageViewWidth = 0; - float pageViewHeight = 0; - if (pagesPanel != null) { - int count = pagesPanel.getComponentCount(); - Component comp; - // should only have one page view decorator for single page view. - for (int i = 0; i < count; i++) { - comp = pagesPanel.getComponent(i); - if (comp instanceof PageViewDecorator) { - PageViewDecorator pvd = (PageViewDecorator) comp; - Dimension dim = pvd.getPreferredSize(); - pageViewWidth = dim.width; - pageViewHeight = dim.height; - break; - } - } - } - // normalize the dimensions to a zoom level of zero. - float currentZoom = documentViewModel.getViewZoom(); - pageViewWidth = Math.abs(pageViewWidth / currentZoom); - pageViewHeight = Math.abs(pageViewHeight / currentZoom); - - // add any horizontal padding from layout manager - pageViewWidth += AbstractDocumentView.horizontalSpace * 2; - pageViewHeight += AbstractDocumentView.verticalSpace * 2; - return new Dimension((int) pageViewWidth, (int) pageViewHeight); - } - - public void paintComponent(Graphics g) { - Rectangle clipBounds = g.getClipBounds(); - // paint background gray - g.setColor(BACKGROUND_COLOUR); - g.fillRect(clipBounds.x, clipBounds.y, clipBounds.width, clipBounds.height); - // paint selection box - super.paintComponent(g); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/PageViewComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/PageViewComponent.java deleted file mode 100644 index 556aea6457..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/PageViewComponent.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.pobjects.Page; - -/** - *

      The PageViewComponent interfaces should be used by any page view - * implementation to represent a single page view. The methods defined in this - * interface are the most commonly used methods and are used by the - * AbstractDocumentView and AbstractDocumentViewModel.

      - * - * @see org.icepdf.ri.common.views.PageViewComponentImpl - * @since 2.0 - */ -public interface PageViewComponent { - - /** - * Set the parent Document View class which is responsible for drawing and - * the general management of PageViewComponents for a particular view. - * - * @param parentDocumentView type of view, single page, continuous, etc. - */ - void setDocumentViewCallback(DocumentView parentDocumentView); - - /** - * Gets the page index which this PageViewComponent is drawing. - * - * @return zero pages page index of the page drawn by this component. - */ - int getPageIndex(); - - /** - * Called to free resources used by this component. - */ - void dispose(); - - /** - * Called from parent controls when a UI control has manipulated the view, property - * change is picked up and the view is updated accordingly. If the worker is currently working - * it should be canceled with an interrupt. - * - * @param propertyConstant document view change property. - * @param oldValue old value - * @param newValue new value - */ - void updateView(String propertyConstant, Object oldValue, Object newValue); - - /** - * This callback is called when the page is successfully initialized at which point an implementation may - * like to work with the page object before the parent method turns. This method should return as quickly - * as possible. - * - * @param page page that was just initialized. - */ - void pageInitializedCallback(Page page); - - - /** - * This callback is called when a page is scheduled for dispose. This generally only happens when the page - * goes out of view and it and it's resources are no longer needed. This method in the default implementation - * is executed on a worker thread. Any AWT work should be queued to run on the AWT thread. - */ - void pageTeardownCallback(); - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/PageViewComponentImpl.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/PageViewComponentImpl.java deleted file mode 100644 index f7e014ba96..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/PageViewComponentImpl.java +++ /dev/null @@ -1,439 +0,0 @@ -package org.icepdf.ri.common.views; - -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.PageTree; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.ChoiceWidgetAnnotation; -import org.icepdf.core.pobjects.annotations.FreeTextAnnotation; -import org.icepdf.core.pobjects.annotations.TextWidgetAnnotation; -import org.icepdf.core.pobjects.graphics.text.PageText; -import org.icepdf.core.search.DocumentSearchController; -import org.icepdf.core.util.GraphicsRenderingHints; -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.ri.common.tools.*; -import org.icepdf.ri.common.views.annotations.AbstractAnnotationComponent; -import org.icepdf.ri.common.views.annotations.AnnotationComponentFactory; -import org.icepdf.ri.common.views.annotations.PopupAnnotationComponent; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; -import java.awt.geom.AffineTransform; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Logger; - -/** - * @since 6.2 heavily modified behaviour for cpu and memory enhancements. - */ -@SuppressWarnings("serial") -public class PageViewComponentImpl extends AbstractPageViewComponent implements FocusListener { - - private static final Logger logger = - Logger.getLogger(PageViewComponentImpl.class.toString()); - - // currently selected tool - protected ToolHandler currentToolHandler; - - // we always keep around a page selection tool, it's only called from the parent view - // component, this allows for multiple page selection. - protected TextSelectionPageHandler textSelectionPageHandler; - - // annotations component for this pageViewComp. - protected ArrayList annotationComponents; - - public PageViewComponentImpl(DocumentViewModel documentViewModel, PageTree pageTree, final int pageIndex, - JScrollPane parentScrollPane, int width, int height) { - super(documentViewModel, pageTree, pageIndex, parentScrollPane, width, height); - setFocusable(true); - addFocusListener(this); - // text selection handler - textSelectionPageHandler = new TextSelectionPageHandler(documentViewController, this, documentViewModel); - // fully dynamic view, so we need to make sure we don't paint annotations to the buffer. - paintAnnotations = false; - } - - public void setDocumentViewCallback(DocumentView parentDocumentView) { - super.setDocumentViewCallback(parentDocumentView); - textSelectionPageHandler.setDocumentViewController(documentViewController); - } - - @Override - protected void paintComponent(Graphics g) { - super.paintComponent(g); - - Graphics2D g2d = (Graphics2D) g.create(0, 0, pageSize.width, pageSize.height); - GraphicsRenderingHints grh = GraphicsRenderingHints.getDefault(); - g2d.setRenderingHints(grh.getRenderingHints(GraphicsRenderingHints.SCREEN)); - - // paint the annotation components. - paintAnnotationComponents(g2d); - // paint selected and highlighted text. - paintTextSelection(g2d); - - // paint annotation handler effect if any. - if (currentToolHandler != null) { - currentToolHandler.paintTool(g2d); - } - if (documentViewModel.getViewToolMode() == DocumentViewModel.DISPLAY_TOOL_TEXT_SELECTION) { - textSelectionPageHandler.paintTool(g2d); - } - g2d.dispose(); - } - - public void dispose() { - // remove annotation listeners. - removeMouseMotionListener(currentToolHandler); - removeMouseListener(currentToolHandler); - // remove focus listener - removeFocusListener(this); - // dispose annotations components - if (annotationComponents != null) { - for (int i = 0, max = annotationComponents.size(); i < max; i++) { - annotationComponents.get(i).dispose(); - } - } - } - - /** - * Sets the tool mode for the current page component implementation. When - * a tool mode is assigned the respective tool handler is registered and - * various event listeners are registered. - * - * @param viewToolMode view tool modes as defined in - * DocumentViewMode.DISPLAY_TOOL_* - */ - public void setToolMode(final int viewToolMode) { - if (currentToolHandler != null) { - currentToolHandler.uninstallTool(); - removeMouseListener(currentToolHandler); - removeMouseMotionListener(currentToolHandler); - currentToolHandler = null; - } - // assign the correct tool handler - switch (viewToolMode) { - case DocumentViewModel.DISPLAY_TOOL_ZOOM_IN: - currentToolHandler = new ZoomInPageHandler( - documentViewController, - this, - documentViewModel); - break; - case DocumentViewModel.DISPLAY_TOOL_SELECTION: - // no handler is needed for selection as it is handle by - // each annotation. - currentToolHandler = new AnnotationSelectionHandler( - documentViewController, - this, - documentViewModel); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_LINK_ANNOTATION: - // handler is responsible for the initial creation of the annotation - currentToolHandler = new LinkAnnotationHandler( - documentViewController, - this, - documentViewModel); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION: - // handler is responsible for the initial creation of the annotation - currentToolHandler = new HighLightAnnotationHandler( - documentViewController, - this, - documentViewModel); - ((HighLightAnnotationHandler) currentToolHandler).createTextMarkupAnnotation(null); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_STRIKEOUT_ANNOTATION: - currentToolHandler = new StrikeOutAnnotationHandler( - documentViewController, - this, - documentViewModel); - ((StrikeOutAnnotationHandler) currentToolHandler).createTextMarkupAnnotation(null); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_UNDERLINE_ANNOTATION: - currentToolHandler = new UnderLineAnnotationHandler( - documentViewController, - this, - documentViewModel); - ((UnderLineAnnotationHandler) currentToolHandler).createTextMarkupAnnotation(null); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_LINE_ANNOTATION: - currentToolHandler = new LineAnnotationHandler( - documentViewController, - this, - documentViewModel); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_LINE_ARROW_ANNOTATION: - currentToolHandler = new LineArrowAnnotationHandler( - documentViewController, - this, - documentViewModel); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_SQUARE_ANNOTATION: - currentToolHandler = new SquareAnnotationHandler( - documentViewController, - this, - documentViewModel); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_CIRCLE_ANNOTATION: - currentToolHandler = new CircleAnnotationHandler( - documentViewController, - this, - documentViewModel); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_INK_ANNOTATION: - currentToolHandler = new InkAnnotationHandler( - documentViewController, - this, - documentViewModel); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_FREE_TEXT_ANNOTATION: - currentToolHandler = new FreeTextAnnotationHandler( - documentViewController, - this, - documentViewModel); - documentViewController.clearSelectedText(); - break; - case DocumentViewModel.DISPLAY_TOOL_TEXT_ANNOTATION: - currentToolHandler = new TextAnnotationHandler( - documentViewController, - this, - documentViewModel); - documentViewController.clearSelectedText(); - break; - default: - currentToolHandler = null; - } - if (currentToolHandler != null) { - currentToolHandler.installTool(); - addMouseListener(currentToolHandler); - addMouseMotionListener(currentToolHandler); - } - } - - /** - * Gets a list of the annotation components used in this page view. - * - * @return list of annotation components, can be null. - */ - public ArrayList getAnnotationComponents() { - return annotationComponents; - } - - /** - * Gets the page components TextSelectionPageHandler. Each page has one and it directly accessed by the - * TextSelectionViewHandler. All other tools are created/disposed as the tools are selected. - * - * @return page's instance of the text selection handler. - */ - public TextSelectionPageHandler getTextSelectionPageHandler() { - return textSelectionPageHandler; - } - - public ToolHandler getCurrentToolHandler() { - return currentToolHandler; - } - - private void paintTextSelection(Graphics g) { - // Lazy paint of highlight and select all text states. - Page currentPage = getPage(); - // paint any highlighted words - DocumentSearchController searchController = - documentViewController.getParentController().getDocumentSearchController(); - if (currentPage != null && currentPage.isInitiated() && - // make sure we don't accidentally block the awt ui thread, but we still - // want to paint search text and text selection if text selection tool is selected. - (searchController.isSearchHighlightRefreshNeeded(pageIndex, null) || - documentViewModel.isViewToolModeSelected(DocumentViewModel.DISPLAY_TOOL_TEXT_SELECTION) || - documentViewModel.isViewToolModeSelected(DocumentViewModel.DISPLAY_TOOL_HIGHLIGHT_ANNOTATION) || - documentViewModel.isViewToolModeSelected(DocumentViewModel.DISPLAY_TOOL_STRIKEOUT_ANNOTATION) || - documentViewModel.isViewToolModeSelected(DocumentViewModel.DISPLAY_TOOL_UNDERLINE_ANNOTATION)) - ) { - try { - PageText pageText = currentPage.getViewText(); - if (pageText != null) { - // paint any highlighted words - if (searchController.isSearchHighlightRefreshNeeded(pageIndex, pageText)) { - searchController.searchHighlightPage(pageIndex); - } - // if select all we'll want to paint the selected text. - if (documentViewModel.isSelectAll()) { - documentViewModel.addSelectedPageText(this); - pageText.selectAll(); - } - // paint selected text. - TextSelection.paintSelectedText(g, this, documentViewModel); - } - } catch (InterruptedException e) { - logger.fine("Interrupt exception during view text fetch."); - } - } else if (currentPage != null && !currentPage.isInitiated()) { - // there is good chance a page has been disposed on a large document, but if we have search hit we need - // to repaint the page, setting the buffer to dirty will reinitialize the page on the next paint cycle. - if (searchController.isSearchHighlightRefreshNeeded(pageIndex, null)) { - pageBufferStore.setDirty(true); - } - } - } - - private void paintAnnotationComponents(Graphics g) { - Page currentPage = getPage(); - if (currentPage != null && annotationComponents != null) { - Graphics2D gg2 = (Graphics2D) g; - // save draw state. - AffineTransform prePaintTransform = gg2.getTransform(); - Color oldColor = gg2.getColor(); - Stroke oldStroke = gg2.getStroke(); - // apply page transform. - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - gg2.transform(at); - // get current tool state, we don't want to draw the highlight - // state if the selection tool is selected. - boolean notSelectTool = - documentViewModel.getViewToolMode() != - DocumentViewModel.DISPLAY_TOOL_SELECTION; - // paint all annotations on top of the content buffer - AnnotationComponent annotation; - for (int i = 0; i < annotationComponents.size(); i++) { - annotation = annotationComponents.get(i); - if (annotation != null && ((Component) annotation).isVisible() && - !(annotation.getAnnotation() instanceof FreeTextAnnotation - && ((AbstractAnnotationComponent) annotation).isActive()) && - !(annotation.getAnnotation() instanceof TextWidgetAnnotation - && ((AbstractAnnotationComponent) annotation).isActive()) && - !(annotation.getAnnotation() instanceof ChoiceWidgetAnnotation - && ((AbstractAnnotationComponent) annotation).isActive())) { - annotation.getAnnotation().render(gg2, - GraphicsRenderingHints.SCREEN, - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom(), - annotation.hasFocus() && notSelectTool); - } - } - // post paint clean up. - gg2.setColor(oldColor); - gg2.setStroke(oldStroke); - gg2.setTransform(prePaintTransform); - } - } - - public void focusGained(FocusEvent e) { - int oldCurrentPage = documentViewModel.getViewCurrentPageIndex(); - documentViewModel.setViewCurrentPageIndex(pageIndex); - documentViewController.firePropertyChange(PropertyConstants.DOCUMENT_CURRENT_PAGE, - oldCurrentPage, - pageIndex); - } - - public void focusLost(FocusEvent e) { - } - - public void updateView(String propertyConstant, Object oldValue, Object newValue) { - super.updateView(propertyConstant, oldValue, newValue); - // revalidate the annotation components. - if (PropertyConstants.DOCUMENT_VIEW_ROTATION_CHANGE.equals(propertyConstant) || - PropertyConstants.DOCUMENT_VIEW_ZOOM_CHANGE.equals(propertyConstant)) { - if (annotationComponents != null) { - for (AbstractAnnotationComponent comp : annotationComponents) { - comp.validate(); - } - } - } - } - - /** - * Add a new annotation object to this page view component. - * - * @param annotation annotation to add. - */ - public void addAnnotation(AnnotationComponent annotation) { - // delegate to handler. - if (annotationComponents == null) { - annotationComponents = new ArrayList(); - } - annotationComponents.add((AbstractAnnotationComponent) annotation); - if (annotation instanceof PopupAnnotationComponent) { - this.add((AbstractAnnotationComponent) annotation, JLayeredPane.POPUP_LAYER); - } else { - this.add((AbstractAnnotationComponent) annotation, JLayeredPane.DEFAULT_LAYER); - } - } - - /** - * Remove the specified annotation from this page view. - * - * @param annotationComp annotation to be removed. - */ - public void removeAnnotation(AnnotationComponent annotationComp) { - annotationComponents.remove(annotationComp); - this.remove((AbstractAnnotationComponent) annotationComp); - } - - public void pageInitializedCallback(Page page) { - refreshAnnotationComponents(page); - } - - public void pageTeardownCallback() { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - // we're cleaning up the page which may involve awt component manipulations o we queue - // callback on the awt thread so we don't try and paint something we just removed - annotationComponents = null; - } - }); - } - - public void refreshAnnotationComponents(Page page) { - if (page != null) { - final List annotations = page.getAnnotations(); - final AbstractPageViewComponent parent = this; - if (annotations != null && annotations.size() > 0) { - // we don't want to re-initialize the component as we'll - // get duplicates if the page has be gc'd - SwingUtilities.invokeLater(new Runnable() { - public void run() { - if (annotationComponents == null) { - annotationComponents = new ArrayList(annotations.size()); - - for (Annotation annotation : annotations) { - // parser can sometimes return an empty array depending on the PDF syntax being used. - if (annotation != null) { - final AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, documentViewController, - parent, documentViewModel); - if (comp != null ) { - // add for painting - annotationComponents.add(comp); - // add to layout - if (comp instanceof PopupAnnotationComponent) { - parent.add(comp, JLayeredPane.POPUP_LAYER); - } else { - parent.add(comp, JLayeredPane.DEFAULT_LAYER); - } - comp.revalidate(); - comp.repaint(); - } - - } - } - } - } - }); - } - } - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/PageViewDecorator.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/PageViewDecorator.java deleted file mode 100644 index 29a848c4c9..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/PageViewDecorator.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; - -import javax.swing.*; -import java.awt.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      The PageViewDecorator class adds a page border and shadow to all of the page - * views defined in the corg.icepdf.core.views.swing package. This class can - * easily be modified for extended for custom page decorations.

      - *

      - *

      By default the this class paints with the following colors:

      - *
        - *
      • paper color - default color is white, can be changed using the system - * property org.icepdf.core.views.page.paper.color - *
      • - *
      • paper border color - default color is black, can be changed using the - * system property org.icepdf.core.views.page.border.color
      • - *
      • paper shadow color - default color is darkGrey, can be changed using the - * system property org.icepdf.core.views.page.shadow.color
      • - *
      - *

      All color values can be set using the hex rgb values. - * eg. black=000000 or white=FFFFFFF.

      - * - * @since 2.5 - */ -@SuppressWarnings("serial") -public class PageViewDecorator extends JComponent { - - private static final Logger log = - Logger.getLogger(PageViewDecorator.class.toString()); - - protected JComponent pageViewComponent; - - protected static final int SHADOW_SIZE = 3; - - protected Dimension preferredSize = new Dimension(); - - private static Color pageBorderColor; - private static Color pageShadowColor; - private static Color pageColor; - static { - // sets the shadow colour of the decorator. - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.shadow.color", "#333333"); - int colorValue = ColorUtil.convertColor(color); - pageShadowColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("333333", 16)); - - } catch (NumberFormatException e) { - if (log.isLoggable(Level.WARNING)) { - log.warning("Error reading page shadow colour"); - } - } - - // background colours for paper, border and shadow. - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.paper.color", "#FFFFFF"); - int colorValue = ColorUtil.convertColor(color); - pageColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("FFFFFF", 16)); - } catch (NumberFormatException e) { - if (log.isLoggable(Level.WARNING)) { - log.warning("Error reading page paper color."); - } - } - // border colour for the page decoration. - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.border.color", "#000000"); - int colorValue = ColorUtil.convertColor(color); - pageBorderColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("000000", 16)); - } catch (NumberFormatException e) { - if (log.isLoggable(Level.WARNING)) { - log.warning("Error reading page paper color."); - } - } - } - - public PageViewDecorator(JComponent pageViewComponent) { - setLayout(new GridLayout(1, 1, 0, 0)); - - this.pageViewComponent = pageViewComponent; - Dimension size = pageViewComponent.getPreferredSize(); - preferredSize.setSize(size.width + SHADOW_SIZE, size.height + SHADOW_SIZE); - add(pageViewComponent); - } - - public Dimension getPreferredSize() { - Dimension size = pageViewComponent.getPreferredSize(); - preferredSize.setSize(size.width + SHADOW_SIZE, size.height + SHADOW_SIZE); - return preferredSize; - } - - /** - * Paints a default a black border and dark gray shadow for the given page. - * - * @param g java graphic context which is decorated with page graphics. - */ - public void paint(Graphics g) { - - Graphics2D g2d = (Graphics2D) g; - Point location = pageViewComponent.getLocation(); - Dimension size = pageViewComponent.getPreferredSize(); - - // paper - g2d.setColor(pageColor); - g2d.fillRect(location.x, location.y, size.width, size.height); - - // paper shadow - g2d.setColor(pageShadowColor); - g2d.fillRect(location.x + SHADOW_SIZE, location.y + size.height, size.width - SHADOW_SIZE, SHADOW_SIZE); - g2d.fillRect(location.x + size.width, location.y + SHADOW_SIZE, SHADOW_SIZE, size.height); - - super.paint(g); - - // paper border - g2d.setColor(pageBorderColor); - g2d.drawRect(location.x, location.y, size.width, size.height); - } - - public PageViewComponent getPageViewComponent() { - return (PageViewComponent) pageViewComponent; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/ResizableBorder.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/ResizableBorder.java deleted file mode 100644 index 706894a1bb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/ResizableBorder.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; - -import javax.swing.*; -import javax.swing.border.AbstractBorder; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * The resizable border is mainly designed to bed used with mutable annotation - * in the UI but suspect it could be used for after content manipulation. Like - * other Swing Borders the same instance can be used on multiple components. - * - * @since 4.0 - */ -@SuppressWarnings("serial") -public class ResizableBorder extends AbstractBorder { - - private static final Logger logger = - Logger.getLogger(ResizableBorder.class.toString()); - - private static Color selectColor; - private static Color outlineColor; - private static Color outlineResizeColor; - - public static final int INSETS = 5; - static { - - // sets annotation selected highlight colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.select.color", "#999999"); - int colorValue = ColorUtil.convertColor(color); - selectColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("999999", 16)); - - color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.outline.color", "#cccccc"); - colorValue = ColorUtil.convertColor(color); - outlineColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("cccccc", 16)); - - color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.outline.colorResize", "#666666"); - colorValue = ColorUtil.convertColor(color); - outlineResizeColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("666666", 16)); - - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading page annotation outline colour"); - } - } - } - - private static final int locations[] = { - SwingConstants.NORTH, SwingConstants.SOUTH, SwingConstants.WEST, - SwingConstants.EAST, SwingConstants.NORTH_WEST, - SwingConstants.NORTH_EAST, SwingConstants.SOUTH_WEST, - SwingConstants.SOUTH_EAST}; - private static final int cursors[] = { - Cursor.N_RESIZE_CURSOR, Cursor.S_RESIZE_CURSOR, Cursor.W_RESIZE_CURSOR, - Cursor.E_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR, - Cursor.SW_RESIZE_CURSOR, Cursor.SE_RESIZE_CURSOR}; - private static final Stroke dashedBorder = - new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{2, 1}, 0); - private static final Stroke solidBorder = - new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0); - - protected int resizeWidgetDim; - protected int originalResizeWidgetDim; - protected int inset; - - public ResizableBorder(int resizeBoxSize) { - this.originalResizeWidgetDim = resizeBoxSize; - } - - public Insets getBorderInsets(Component component) { - return new Insets(inset, inset, inset, inset); - } - - public void setZoom(float zoom) { - this.resizeWidgetDim = (int) (this.originalResizeWidgetDim * zoom); - this.inset = (int) (INSETS * zoom + 0.5); - } - - public boolean isBorderOpaque() { - return false; - } - - public void paintBorder(Component component, Graphics g, int x, int y, - int w, int h) { - boolean isSelected = false; - boolean isBorderStyle = false; - - boolean isEditable = false; - boolean isRollover = false; - boolean isMovable = false; - boolean isResizable = false; - boolean isShowInvisibleBorder = false; - - // get render flags from component. - if (component instanceof AnnotationComponent) { - AnnotationComponent annot = (AnnotationComponent) component; - isSelected = annot.isSelected(); - isBorderStyle = annot.isBorderStyle(); - - isEditable = annot.isEditable(); - isRollover = annot.isRollover(); - isMovable = annot.isMovable(); - isResizable = annot.isResizable(); - isShowInvisibleBorder = annot.isShowInvisibleBorder(); - } - - // if we aren't in the edit mode, then we have nothing to paint. - if (!isEditable) { - return; - } - - Graphics2D g2 = (Graphics2D) g; - g2.setStroke(dashedBorder); - - // get paint colour - if (isSelected || component.hasFocus() || isRollover) { - g2.setColor(selectColor); - } else { - g2.setColor(outlineColor); - } - - // paint border - if (isSelected || isRollover || (isShowInvisibleBorder && !isBorderStyle)) { - g2.drawRect(x, y, w - 1, h - 1); - } - - // paint resize widgets. - g2.setColor(outlineResizeColor); - g2.setStroke(solidBorder); - if ((isSelected || isRollover) && isResizable) { - for (int location : locations) { - Rectangle rect = getRectangle(x, y, w, h, location); -// g.setColor(Color.WHITE); - g2.fillRect(rect.x, rect.y, rect.width - 1, rect.height - 1); -// g.setColor(Color.BLACK); - g2.drawRect(rect.x, rect.y, rect.width - 1, rect.height - 1); - } - } - } - - - private Rectangle getRectangle(int x, int y, int w, int h, int location) { - switch (location) { - case SwingConstants.NORTH: - return new Rectangle(x + w / 2 - resizeWidgetDim / 2, y, resizeWidgetDim, resizeWidgetDim); - case SwingConstants.SOUTH: - return new Rectangle(x + w / 2 - resizeWidgetDim / 2, y + h - resizeWidgetDim, resizeWidgetDim, - resizeWidgetDim); - case SwingConstants.WEST: - return new Rectangle(x, y + h / 2 - resizeWidgetDim / 2, resizeWidgetDim, resizeWidgetDim); - case SwingConstants.EAST: - return new Rectangle(x + w - resizeWidgetDim, y + h / 2 - resizeWidgetDim / 2, resizeWidgetDim, - resizeWidgetDim); - case SwingConstants.NORTH_WEST: - return new Rectangle(x, y, resizeWidgetDim, resizeWidgetDim); - case SwingConstants.NORTH_EAST: - return new Rectangle(x + w - resizeWidgetDim, y, resizeWidgetDim, resizeWidgetDim); - case SwingConstants.SOUTH_WEST: - return new Rectangle(x, y + h - resizeWidgetDim, resizeWidgetDim, resizeWidgetDim); - case SwingConstants.SOUTH_EAST: - return new Rectangle(x + w - resizeWidgetDim, y + h - resizeWidgetDim, resizeWidgetDim, resizeWidgetDim); - } - return null; - } - - - public int getCursor(MouseEvent me) { - Component c = me.getComponent(); - boolean isEditable = false; - boolean isMovable = false; - boolean isResizable = false; - - // get render flags from component. - if (c instanceof AnnotationComponent) { - AnnotationComponent annot = (AnnotationComponent) c; - isEditable = annot.isEditable(); - isResizable = annot.isResizable(); - isMovable = annot.isMovable(); - } - - int w = c.getWidth(); - int h = c.getHeight(); - - // show resize cursors for link annotations - if (isResizable) { - for (int i = 0; i < locations.length; i++) { - Rectangle rect = getRectangle(0, 0, w, h, locations[i]); - if (rect.contains(me.getPoint())) - return cursors[i]; - } - } - if (isMovable) { - return Cursor.MOVE_CURSOR; - } - // other wise just show the move. - return Cursor.DEFAULT_CURSOR; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/TwoColumnPageView.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/TwoColumnPageView.java deleted file mode 100644 index db4399de89..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/TwoColumnPageView.java +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.ri.common.CurrentPageChanger; -import org.icepdf.ri.common.KeyListenerPageColumnChanger; -import org.icepdf.ri.common.SwingController; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; - -/** - *

      Constructs a two column page view as defined in the PDF specification. - * A two column page view displays pages in two columns with odd numbered pages - * on the left.

      - *

      - *

      Page views are basic containers which use Swing Layout Containers to - * place pages

      - * - * @since 2.5 - */ -@SuppressWarnings("serial") -public class TwoColumnPageView extends AbstractDocumentView { - - protected int viewAlignment; - - // specialized listeners for different gui operations - protected CurrentPageChanger currentPageChanger; - - protected KeyListenerPageColumnChanger keyListenerPageChanger; - - public TwoColumnPageView(DocumentViewController documentDocumentViewController, - JScrollPane documentScrollpane, - DocumentViewModel documentViewModel, - final int viewAlignment) { - - super(documentDocumentViewController, documentScrollpane, documentViewModel); - - // used to redirect mouse events - this.documentScrollpane = documentScrollpane; - - // assign view allignemnt - this.viewAlignment = viewAlignment; - - // put all the gui elements together - buildGUI(); - - // add the first of many tools need for this views and others like it. - currentPageChanger = - new CurrentPageChanger(documentScrollpane, this, - documentViewModel.getPageComponents()); - - // add page changing key listeners - if (this.documentViewController.getParentController() instanceof SwingController) { - keyListenerPageChanger = - KeyListenerPageColumnChanger.install( - (SwingController) this.documentViewController.getParentController(), - this.documentScrollpane, this, currentPageChanger); - } - } - - private void buildGUI() { - // add all page components to gridlayout panel - pagesPanel = new JPanel(); - pagesPanel.setBackground(BACKGROUND_COLOUR); - // two column equals facing page view continuous - GridLayout gridLayout = new GridLayout(0, 2, horizontalSpace, verticalSpace); - pagesPanel.setLayout(gridLayout); - - // use a gridbag to center the page component panel - GridBagConstraints gbc = new GridBagConstraints(); - gbc.weighty = 1.0; // allows vertical resizing - gbc.weightx = 1.0; // allows horizontal resizing - gbc.insets = // component spacer [top, left, bottom, right] - new Insets(layoutInserts, layoutInserts, layoutInserts, layoutInserts); - gbc.gridwidth = GridBagConstraints.REMAINDER; // one component per row - - this.setLayout(new GridBagLayout()); - this.add(pagesPanel, gbc); - - // finally add all the components - // add components for every page in the document - java.util.List pageComponents = - documentViewModel.getPageComponents(); - - if (pageComponents != null) { - PageViewComponent pageViewComponent; - for (int i = 0, max = pageComponents.size(), max2 = pageComponents.size(); - i < max && i < max2; i++) { - // save for facing page - if (i == 0 && max2 > 2 && viewAlignment == RIGHT_VIEW) { - // should be adding spacer - pagesPanel.add(new JLabel()); - } - pageViewComponent = pageComponents.get(i); - if (pageViewComponent != null) { - pageViewComponent.setDocumentViewCallback(this); - pagesPanel.add(new PageViewDecorator( - (AbstractPageViewComponent) pageViewComponent)); - } - } - } - } - - // nothing needs to be done for a column view as all components are already - // available - public void updateDocumentView() { - } - - /** - * Returns a next page increment of two. - */ - public int getNextPageIncrement() { - return 2; - } - - /** - * Returns a previous page increment of two. - */ - public int getPreviousPageIncrement() { - return 2; - } - - public void mouseReleased(MouseEvent e) { - // let the current PageListener now about the mouse release - currentPageChanger.mouseReleased(e); - } - - public void dispose() { - disposing = true; - - // remove utilities - if (currentPageChanger != null) { - currentPageChanger.dispose(); - } - if (keyListenerPageChanger != null) { - keyListenerPageChanger.uninstall(); - } - - // trigger a relayout - pagesPanel.removeAll(); - pagesPanel.invalidate(); - - // make sure we call super. - super.dispose(); - } - - public Dimension getDocumentSize() { - float pageViewWidth = 0; - float pageViewHeight = 0; - if (pagesPanel != null) { - // The page index and corresponding component index are approximately equal - // If the first page is on the right, then there's a spacer on the left, - // bumping indexes up by one. - int currPageIndex = documentViewController.getCurrentPageIndex(); - int currCompIndex = currPageIndex; - int numComponents = pagesPanel.getComponentCount(); - boolean foundCurrent = false; - while (currCompIndex >= 0 && currCompIndex < numComponents) { - Component comp = pagesPanel.getComponent(currCompIndex); - if (comp instanceof PageViewDecorator) { - PageViewDecorator pvd = (PageViewDecorator) comp; - PageViewComponent pvc = pvd.getPageViewComponent(); - if (pvc.getPageIndex() == currPageIndex) { - Dimension dim = pvd.getPreferredSize(); - pageViewWidth = dim.width; - pageViewHeight = dim.height; - foundCurrent = true; - break; - } - } - currCompIndex++; - } - if (foundCurrent) { - // Determine if the page at (currPageIndex,currCompIndex) was - // on the left or right, so that if there's a page next to - // it, whether it's earlier or later in the component list, - // so we can get it's pageViewHeight and use that for our pageViewHeight - // calculation. - // If the other component is past the ends of the component - // list, or not a PageViewDecorator, then current was either - // the first or last page in the document - boolean evenPageIndex = ((currPageIndex & 0x1) == 0); - boolean bumpedIndex = (currCompIndex != currPageIndex); - boolean onLeft = evenPageIndex ^ bumpedIndex; // XOR - int otherCompIndex = onLeft ? (currCompIndex + 1) : (currCompIndex - 1); - if (otherCompIndex >= 0 && otherCompIndex < numComponents) { - Component comp = pagesPanel.getComponent(otherCompIndex); - if (comp instanceof PageViewDecorator) { - PageViewDecorator pvd = (PageViewDecorator) comp; - Dimension dim = pvd.getPreferredSize(); - pageViewWidth = dim.width; - pageViewHeight = dim.height; - } - } - } - } - - // normalize the dimensions to a zoom level of zero. - float currentZoom = documentViewModel.getViewZoom(); - pageViewWidth = Math.abs(pageViewWidth / currentZoom); - pageViewHeight = Math.abs(pageViewHeight / currentZoom); - - // two pages wide, generalization, pages are usually the same size we - // don't bother to look at the second pages size for the time being. - pageViewWidth *= 2; - - // add any horizontal padding from layout manager - pageViewWidth += AbstractDocumentView.horizontalSpace * 4; - pageViewHeight += AbstractDocumentView.verticalSpace * 2; - - return new Dimension((int) pageViewWidth, (int) pageViewHeight); - - } - - public void paintComponent(Graphics g) { - Rectangle clipBounds = g.getClipBounds(); - g.setColor(BACKGROUND_COLOUR); - g.fillRect(clipBounds.x, clipBounds.y, clipBounds.width, clipBounds.height); - // paint selection box - super.paintComponent(g); - } - -// public void adjustmentValueChanged(AdjustmentEvent e){ -// -//// System.out.println("Adjusting " + e.getAdjustable().getValue()); -// if (e.getAdjustable().getOrientation() == Adjustable.HORIZONTAL){ -//// System.out.println("horizontal"); -// } -// else if (e.getAdjustable().getOrientation() == Adjustable.VERTICAL){ -//// System.out.println("vertical"); -//// int newValue = e.getAdjustable().getValue(); -//// System.out.println("value " + newValue); -//// e.getAdjustable().setValue(0); -// } -// } - -// public void mouseDragged(MouseEvent e) { -// Point point = e.getPoint(); -// super.mouseDragged(e); -// Point currentLocation = getLocation(); -// pageViewComponentImpl.setBounds(point.x, -// point.y, 640,480); -// } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/TwoPageView.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/TwoPageView.java deleted file mode 100644 index 76cd848c1c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/TwoPageView.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views; - -import org.icepdf.ri.common.CurrentPageChanger; -import org.icepdf.ri.common.KeyListenerPageChanger; -import org.icepdf.ri.common.MouseWheelListenerPageChanger; -import org.icepdf.ri.common.SwingController; - -import javax.swing.*; -import java.awt.*; - -/** - *

      Constructs a two page view as defined in the PDF specification. - * A two column page view displays two pages with odd numbered pages - * on the left.

      - *

      - *

      Page views are basic containers which use Swing Layout Containers to - * place pages

      - * - * @since 2.5 - */ -@SuppressWarnings("serial") -public class TwoPageView extends AbstractDocumentView { - - protected int viewAlignment; - - // specialized listeners for different gui operations - protected Object pageChangerListener; - protected KeyListenerPageChanger keyListenerPageChanger; - protected CurrentPageChanger currentPageChanger; - - public TwoPageView(DocumentViewController documentDocumentViewController, - JScrollPane documentScrollpane, - DocumentViewModel documentViewModel, - final int viewAlignment) { - - super(documentDocumentViewController, documentScrollpane, documentViewModel); - - // used to redirect mouse events - this.documentScrollpane = documentScrollpane; - - // assign view alignment - this.viewAlignment = viewAlignment; - - // put all the gui elements together - buildGUI(); - - // add page changing key listeners - if (this.documentViewController.getParentController() instanceof SwingController) { - pageChangerListener = - MouseWheelListenerPageChanger.install( - (SwingController) this.documentViewController.getParentController(), - this.documentScrollpane, this); - - keyListenerPageChanger = - KeyListenerPageChanger.install((SwingController) this.documentViewController.getParentController(), - this.documentScrollpane, this); - } - - // add the first of many tools need for this views and others like it. - currentPageChanger = - new CurrentPageChanger(documentScrollpane, this, - documentViewModel.getPageComponents(), - false); - } - - - private void buildGUI() { - // add all page components to gridlayout panel - pagesPanel = new JPanel(); - pagesPanel.setBackground(BACKGROUND_COLOUR); - // one column equals single page view continuous - GridLayout gridLayout = new GridLayout(0, 2, horizontalSpace, verticalSpace); - pagesPanel.setLayout(gridLayout); - - // use a gridbag to center the page component panel - GridBagConstraints gbc = new GridBagConstraints(); - gbc.weighty = 1.0; // allows vertical resizing - gbc.weightx = 1.0; // allows horizontal resizing - gbc.insets = // component spacer [top, left, bottom, right] - new Insets(layoutInserts, layoutInserts, layoutInserts, layoutInserts); - gbc.gridwidth = GridBagConstraints.REMAINDER; // one component per row - - // finally add all the components - // add components for every page in the document - updateDocumentView(); - - this.setLayout(new GridBagLayout()); - this.add(pagesPanel, gbc); - } - - public void updateDocumentView() { - - java.util.List pageComponents = - documentViewModel.getPageComponents(); - - if (pageComponents != null) { - // remove old component - pagesPanel.removeAll(); - pagesPanel.validate(); - AbstractPageViewComponent pageViewComponent; - int count = 0; - int index = documentViewModel.getViewCurrentPageIndex(); - int docLength = pageComponents.size(); - - - if (viewAlignment == RIGHT_VIEW && - ((index > 0 && index % 2 == 0) || (index > 0 && docLength == 2))) { - index--; - } - - for (int i = index; i < docLength && count < 2; i++) { - // save for facing page - if (i == 0 && docLength > 2 && viewAlignment == RIGHT_VIEW) { - // should be adding spacer - pagesPanel.add(new JLabel()); - count++; - } - pageViewComponent = pageComponents.get(i); - if (pageViewComponent != null) { - pageViewComponent.setDocumentViewCallback(this); - // add component to layout - pagesPanel.add(new PageViewDecorator(pageViewComponent)); - pageViewComponent.invalidate(); - pageViewComponent.validate(); - count++; - } - } - documentScrollpane.validate(); - - // make sure we have setup all pages with callback call. - for (PageViewComponent pageViewCom : pageComponents) { - if (pageViewCom != null) { - pageViewCom.setDocumentViewCallback(this); - } - } - } - } - - /** - * Returns a next page increment of two. - */ - public int getNextPageIncrement() { - return 2; - } - - /** - * Returns a previous page increment of two. - */ - public int getPreviousPageIncrement() { - return 2; - } - - public void dispose() { - disposing = true; - // remove utilities - if (pageChangerListener != null) { - MouseWheelListenerPageChanger.uninstall(documentScrollpane, - pageChangerListener); - } - if (keyListenerPageChanger != null) { - keyListenerPageChanger.uninstall(); - } - - // trigger a re-layout - pagesPanel.removeAll(); - pagesPanel.invalidate(); - - // make sure we call super. - super.dispose(); - } - - public Dimension getDocumentSize() { - float pageViewWidth = 0; - float pageViewHeight = 0; - if (pagesPanel != null) { - int count = pagesPanel.getComponentCount(); - Component comp; - // should only have one page view decorator for single page view. - for (int i = 0; i < count; i++) { - comp = pagesPanel.getComponent(i); - if (comp instanceof PageViewDecorator) { - PageViewDecorator pvd = (PageViewDecorator) comp; - Dimension dim = pvd.getPreferredSize(); - pageViewWidth = dim.width; - pageViewHeight = dim.height; - break; - } - } - } - // normalize the dimensions to a zoom level of zero. - float currentZoom = documentViewModel.getViewZoom(); - pageViewWidth = Math.abs(pageViewWidth / currentZoom); - pageViewHeight = Math.abs(pageViewHeight / currentZoom); - - // two pages wide, generalization, pages are usually the same size we - // don't bother to look at the second pages size for the time being. - pageViewWidth *= 2; - - // add any horizontal padding from layout manager - pageViewWidth += AbstractDocumentView.horizontalSpace * 4; - pageViewHeight += AbstractDocumentView.verticalSpace * 2; - - return new Dimension((int) pageViewWidth, (int) pageViewHeight); - } - - public void paintComponent(Graphics g) { - Rectangle clipBounds = g.getClipBounds(); - g.setColor(BACKGROUND_COLOUR); - g.fillRect(clipBounds.x, clipBounds.y, clipBounds.width, clipBounds.height); - // paint selection box - super.paintComponent(g); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/AbstractAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/AbstractAnnotationComponent.java deleted file mode 100644 index fbfa55e8c7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/AbstractAnnotationComponent.java +++ /dev/null @@ -1,723 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.acroform.AdditionalActionsDictionary; -import org.icepdf.core.pobjects.acroform.FieldDictionary; -import org.icepdf.core.pobjects.actions.Action; -import org.icepdf.core.pobjects.annotations.AbstractWidgetAnnotation; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.Appearance; -import org.icepdf.core.util.ColorUtil; -import org.icepdf.core.util.Defs; -import org.icepdf.core.util.PropertyConstants; -import org.icepdf.ri.common.views.*; - -import javax.swing.*; -import javax.swing.border.Border; -import javax.swing.event.MouseInputListener; -import java.awt.*; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.Rectangle2D; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * AbstractAnnotationComponent contains base functionality for annotation - * components which are used to display annotation for a given page view. This - * class controls icon state, focus and basic component states: editable, - * movable, resizable, selected and show invisible border. - * - * @since 5.0 - */ -public abstract class AbstractAnnotationComponent extends JComponent implements FocusListener, - MouseInputListener, AnnotationComponent { - - protected static final Logger logger = - Logger.getLogger(AbstractAnnotationComponent.class.toString()); - protected static boolean isInteractiveAnnotationsEnabled; - protected static Color annotationHighlightColor; - protected static float annotationHighlightAlpha; - - static { - // enables interactive annotation support. - isInteractiveAnnotationsEnabled = - Defs.sysPropertyBoolean( - "org.icepdf.core.annotations.interactive.enabled", true); - - // sets annotation selected highlight colour - try { - String color = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.highlight.color", "#000000"); - int colorValue = ColorUtil.convertColor(color); - annotationHighlightColor = - new Color(colorValue >= 0 ? colorValue : - Integer.parseInt("000000", 16)); - - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading page annotation highlight colour"); - } - } - - // set the annotation alpha value. - // sets annotation selected highlight colour - try { - String alpha = Defs.sysProperty( - "org.icepdf.core.views.page.annotation.highlight.alpha", "0.4"); - annotationHighlightAlpha = Float.parseFloat(alpha); - - } catch (NumberFormatException e) { - if (logger.isLoggable(Level.WARNING)) { - logger.warning("Error reading page annotation highlight alpha"); - } - annotationHighlightAlpha = 0.4f; - } - } - - public static final int resizeBoxSize = 4; - - // reusable border - protected static ResizableBorder resizableBorder = - new ResizableBorder(resizeBoxSize); - - protected PageViewComponentImpl pageViewComponent; - protected DocumentViewController documentViewController; - protected DocumentViewModel documentViewModel; - - protected float currentZoom; - protected float currentRotation; - - protected Annotation annotation; - protected boolean isMousePressed; - protected boolean resized; - protected boolean wasResized; - - // border state flags. - protected boolean isEditable; - protected boolean isRollover; - protected boolean isMovable; - protected boolean isResizable; - protected boolean isShowInvisibleBorder; - protected boolean isSelected; - - // drag offset - protected int dx = 0; - protected int dy = 0; - - // selection, move and resize handling. - protected int cursor; - protected Point startPos; - protected AnnotationState previousAnnotationState; - // total distance moved on mouse down/up. - protected Point startOfMousePress; - protected Point endOfMousePress; - - protected ResourceBundle messageBundle; - - public AbstractAnnotationComponent(Annotation annotation, - DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - this.pageViewComponent = (PageViewComponentImpl) pageViewComponent; - this.documentViewModel = documentViewModel; - this.documentViewController = documentViewController; - this.annotation = annotation; - messageBundle = documentViewController.getParentController().getMessageBundle(); - - // border and behavior default properties. - isEditable = !annotation.getFlagReadOnly(); - isRollover = false; - isMovable = !(annotation.getFlagReadOnly() || annotation.getFlagLocked()); - isResizable = !(annotation.getFlagReadOnly() || annotation.getFlagLocked()); - - // lock UI controls. - if (isInteractiveAnnotationsEnabled) { - addMouseListener(this); - addMouseMotionListener(this); - - // disabled focus until we are ready to implement our own handler. - setFocusable(true); - addFocusListener(this); - - // setup a resizable border. - setLayout(new BorderLayout()); - setBorder(resizableBorder); - - // set component location and original size. - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - final Rectangle location = - at.createTransformedShape(annotation.getUserSpaceRectangle()).getBounds(); - SwingUtilities.invokeLater(new Runnable() { - public void run() { - setBounds(location); - } - }); - - - // update zoom and rotation state - currentRotation = documentViewModel.getViewRotation(); - currentZoom = documentViewModel.getViewZoom(); - resizableBorder.setZoom(currentZoom); - } - - } - - public abstract boolean isActive(); - - public Document getDocument() { - return documentViewModel.getDocument(); - } - - public int getPageIndex() { - return pageViewComponent.getPageIndex(); - } - - public PageViewComponent getParentPageView() { - return pageViewComponent; - } - - public AbstractPageViewComponent getPageViewComponent() { - return pageViewComponent; - } - - public void removeMouseListeners() { - removeMouseListener(this); - removeMouseMotionListener(this); - } - - public Annotation getAnnotation() { - return annotation; - } - - public void focusGained(FocusEvent e) { - isSelected = true; - - // on mouse enter pass event to annotation callback if we are in normal viewing - // mode. A and AA dictionaries are taken into consideration. - additionalActionsHandler(AdditionalActionsDictionary.ANNOTATION_FO_KEY, null); - - repaint(); - } - - public void focusLost(FocusEvent e) { - - // if we've lost focus then drop the selected state - isSelected = false; - - // on mouse enter pass event to annotation callback if we are in normal viewing - // mode. A and AA dictionaries are taken into consideration. - additionalActionsHandler(AdditionalActionsDictionary.ANNOTATION_Bl_KEY, null); - - repaint(); - } - - protected void resize() { - if (getParent() != null) { - getParent().validate(); - } - resized = true; - } - - /** - * Refreshes the components bounds for the current page transformation. - * Bounds have are already in user space. - */ - public void refreshDirtyBounds() { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - setBounds(commonBoundsNormalization(new GeneralPath( - annotation.getUserSpaceRectangle()), at)); - } - - /** - * Refreshes/transforms the page space bounds back to user space. This - * must be done in order refresh the annotation user space rectangle after - * UI manipulation, otherwise the annotation will be incorrectly located - * on the next repaint. - */ - public void refreshAnnotationRect() { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error refreshing annotation rectangle", e); - } - // store the new annotation rectangle in its original user space - Rectangle2D rect = annotation.getUserSpaceRectangle(); - rect = new Rectangle2D.Double(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); - Rectangle bounds = getBounds(); - rect.setRect(commonBoundsNormalization(new GeneralPath(bounds), at)); - annotation.syncBBoxToUserSpaceRectangle(rect); - } - - /** - * Normalizes and the given path with the specified transform. The method - * also rounds the Rectangle2D bounds values when creating a new rectangle - * instead of truncating the values. - * - * @param shapePath path to apply transform to - * @param at transform to apply to shapePath - * @return bound value of the shape path. - */ - protected Rectangle commonBoundsNormalization(GeneralPath shapePath, - AffineTransform at) { - shapePath.transform(at); - Rectangle2D pageSpaceBound = shapePath.getBounds2D(); - return new Rectangle( - (int) Math.round(pageSpaceBound.getX()), - (int) Math.round(pageSpaceBound.getY()), - (int) Math.round(pageSpaceBound.getWidth()), - (int) Math.round(pageSpaceBound.getHeight())); - } - - public void validate() { - if (currentZoom != documentViewModel.getViewZoom() || - currentRotation != documentViewModel.getViewRotation()) { - refreshDirtyBounds(); - currentRotation = documentViewModel.getViewRotation(); - currentZoom = documentViewModel.getViewZoom(); - resizableBorder.setZoom(currentZoom); - } - - if (resized) { - refreshAnnotationRect(); - if (getParent() != null) { -// getParent().validate(); - getParent().repaint(); - } - resized = false; - wasResized = true; - } - - } - - abstract public void paintComponent(Graphics g); - - abstract public void resetAppearanceShapes(); - - public void mouseMoved(MouseEvent me) { - - int toolMode = documentViewModel.getViewToolMode(); - - if (toolMode == DocumentViewModel.DISPLAY_TOOL_SELECTION && - !(annotation.getFlagLocked() || annotation.getFlagReadOnly())) { - Border border = getBorder(); - if (border instanceof ResizableBorder) { - setCursor(Cursor.getPredefinedCursor(((ResizableBorder) border).getCursor(me))); - } - } else { - // set cursor back to the hand cursor. - setCursor(documentViewController.getViewCursor( - DocumentViewController.CURSOR_HAND_ANNOTATION)); - } - } - - public void dispose() { - removeMouseListener(this); - removeMouseMotionListener(this); - // disabled focus until we are ready to implement our own handler. - removeFocusListener(this); - } - - public void mouseExited(MouseEvent mouseEvent) { - - // set selected appearance state - annotation.setCurrentAppearance(Annotation.APPEARANCE_STREAM_NORMAL_KEY); - - // on exit pass event to annotation callback if we are in normal viewing - // mode. A and AA dictionaries are taken into consideration. - additionalActionsHandler(AdditionalActionsDictionary.ANNOTATION_X_KEY, mouseEvent); - - setCursor(Cursor.getDefaultCursor()); - isRollover = false; - repaint(); - } - - public void mouseClicked(MouseEvent e) { - // clear the selection. - requestFocus(); - - } - - public void mouseEntered(MouseEvent e) { - // reset the appearance steam - Appearance hover = annotation.getAppearances().get(Annotation.APPEARANCE_STREAM_ROLLOVER_KEY); - if (hover != null && hover.hasAlternativeAppearance()) { - // set selected appearance state - hover.setSelectedName(hover.getOnName()); - annotation.setCurrentAppearance(Annotation.APPEARANCE_STREAM_ROLLOVER_KEY); - } - - // set border highlight when mouse over. - isRollover = (documentViewModel.getViewToolMode() == - DocumentViewModel.DISPLAY_TOOL_SELECTION || - (this instanceof PopupAnnotationComponent)); - - // on mouse enter pass event to annotation callback if we are in normal viewing - // mode. A and AA dictionaries are taken into consideration. - //additionalActionsHandler(AdditionalActionsDictionary.ANNOTATION_E_KEY, e); - repaint(); - } - - public void mousePressed(MouseEvent e) { - // setup visual effect when the mouse button is pressed or held down - // inside the active area of the annotation. - isMousePressed = true; - int x = 0, y = 0; - Point point = new Point(); - if (e != null) { - x = e.getX(); - y = e.getY(); - point = e.getPoint(); - } - startOfMousePress = point; - endOfMousePress = new Point(point); // need clone not a copy... - - // check if there is a mouse down state - Appearance down = annotation.getAppearances().get(Annotation.APPEARANCE_STREAM_DOWN_KEY); - if (down != null && down.hasAlternativeAppearance()) { - if (down.getSelectedName().equals(down.getOnName())) { - down.setSelectedName(down.getOffName()); - } else { - down.setSelectedName(down.getOnName()); - } - annotation.setCurrentAppearance(Annotation.APPEARANCE_STREAM_DOWN_KEY); - } - - if (documentViewModel.getViewToolMode() == - DocumentViewModel.DISPLAY_TOOL_SELECTION && - isInteractiveAnnotationsEnabled && - !annotation.getFlagReadOnly()) { - initiateMouseMoved(e); - } - - // on mouse pressed event to annotation callback if we are in normal viewing - // mode. A and AA dictionaries are taken into consideration. - boolean actionFired = additionalActionsHandler(AdditionalActionsDictionary.ANNOTATION_D_KEY, e); - - // fire the main action associated with the - if (!actionFired && !(AbstractPageViewComponent.isAnnotationTool( - documentViewModel.getViewToolMode())) && - isInteractiveAnnotationsEnabled) { - if (documentViewController.getAnnotationCallback() != null) { - // get the A and AA entries. - Action action = annotation.getAction(); - documentViewController.getAnnotationCallback() - .processAnnotationAction(annotation, action, x, y); - } - } - repaint(); - } - - protected boolean additionalActionsHandler(Name additionalActionKey, MouseEvent e) { - if (!(AbstractPageViewComponent.isAnnotationTool( - documentViewModel.getViewToolMode())) && - isInteractiveAnnotationsEnabled) { - if (documentViewController.getAnnotationCallback() != null) { - int x = -1, y = -1; - if (e != null) { - x = e.getX(); - y = e.getY(); - } - // get the A and AA entries. - if (annotation instanceof AbstractWidgetAnnotation) { - AbstractWidgetAnnotation widgetAnnotation = (AbstractWidgetAnnotation) annotation; - FieldDictionary fieldDictionary = (FieldDictionary) widgetAnnotation.getFieldDictionary(); - if (fieldDictionary != null) { - AdditionalActionsDictionary additionalActionsDictionary = - fieldDictionary.getAdditionalActionsDictionary(); - if (additionalActionsDictionary != null && - additionalActionsDictionary.isAnnotationValue(additionalActionKey)) { - documentViewController.getAnnotationCallback() - .processAnnotationAction(annotation, - additionalActionsDictionary.getAction(additionalActionKey), - x, y); - return true; - } - } - } - } - } - return false; - } - - protected void initiateMouseMoved(MouseEvent e) { - Border border = getBorder(); - if (border != null && border instanceof ResizableBorder) { - cursor = ((ResizableBorder) border).getCursor(e); - } - startPos = e.getPoint(); - previousAnnotationState = new AnnotationState(this); - // mark annotation as selected. - documentViewController.assignSelectedAnnotation(this); - } - - public void mouseDragged(MouseEvent me) { - - if (startPos != null && isMovable && - !(annotation.getFlagLocked() || annotation.getFlagReadOnly())) { - - int x = getX(); - int y = getY(); - int w = getWidth(); - int h = getHeight(); - - dx = me.getX() - startPos.x; - dy = me.getY() - startPos.y; - - if (endOfMousePress != null) { - endOfMousePress.setLocation(endOfMousePress.x + dx, endOfMousePress.y + dy); - } - - switch (cursor) { - case Cursor.N_RESIZE_CURSOR: - if (isResizable && !(h - dy < 12)) { - setBounds(x, y + dy, w, h - dy); - resize(); - setCursor(Cursor.getPredefinedCursor(cursor)); - } - break; - - case Cursor.S_RESIZE_CURSOR: - if (isResizable && !(h + dy < 12)) { - setBounds(x, y, w, h + dy); - startPos = me.getPoint(); - resize(); - setCursor(Cursor.getPredefinedCursor(cursor)); - } - break; - - case Cursor.W_RESIZE_CURSOR: - if (isResizable && !(w - dx < 18)) { - setBounds(x + dx, y, w - dx, h); - resize(); - setCursor(Cursor.getPredefinedCursor(cursor)); - } - break; - - case Cursor.E_RESIZE_CURSOR: - if (isResizable && !(w + dx < 18)) { - setBounds(x, y, w + dx, h); - startPos = me.getPoint(); - resize(); - setCursor(Cursor.getPredefinedCursor(cursor)); - } - break; - - case Cursor.NW_RESIZE_CURSOR: - if (isResizable && !(w - dx < 18) && !(h - dy < 18)) { - setBounds(x + dx, y + dy, w - dx, h - dy); - resize(); - setCursor(Cursor.getPredefinedCursor(cursor)); - } - break; - - case Cursor.NE_RESIZE_CURSOR: - if (isResizable && !(w + dx < 18) && !(h - dy < 18)) { - setBounds(x, y + dy, w + dx, h - dy); - startPos = new Point(me.getX(), startPos.y); - resize(); - setCursor(Cursor.getPredefinedCursor(cursor)); - } - break; - - case Cursor.SW_RESIZE_CURSOR: - if (isResizable && !(w - dx < 18) && !(h + dy < 18)) { - setBounds(x + dx, y, w - dx, h + dy); - startPos = new Point(startPos.x, me.getY()); - resize(); - setCursor(Cursor.getPredefinedCursor(cursor)); - } - break; - - case Cursor.SE_RESIZE_CURSOR: - if (isResizable && !(w + dx < 18) && !(h + dy < 18)) { - setBounds(x, y, w + dx, h + dy); - startPos = me.getPoint(); - resize(); - setCursor(Cursor.getPredefinedCursor(cursor)); - } - break; - - case Cursor.MOVE_CURSOR: - if (isMovable) { - Rectangle bounds = getBounds(); - bounds.translate(dx, dy); - setBounds(bounds); - resize(); - setCursor(Cursor.getPredefinedCursor(cursor)); - } - break; - } - validate(); - } - } - - public void mouseReleased(MouseEvent mouseEvent) { - startPos = null; - isMousePressed = false; - - // reset the appearance steam - Appearance down = annotation.getAppearances().get(Annotation.APPEARANCE_STREAM_DOWN_KEY); - if (down != null && down.hasAlternativeAppearance()) { - if (down.getSelectedName().equals(down.getOnName())) { - down.setSelectedName(down.getOffName()); - } else { - down.setSelectedName(down.getOnName()); - } - } - // set selected appearance state - annotation.setCurrentAppearance(Annotation.APPEARANCE_STREAM_NORMAL_KEY); - - // check to see if a move/resize occurred and if so we add the - // state change to the memento in document view. - if (wasResized) { - wasResized = false; - - // update the bounds - refreshAnnotationRect(); - - double dx = 0; - double dy = 0; - if (startOfMousePress != null && - endOfMousePress != null) { - dx = endOfMousePress.getX() - startOfMousePress.getX(); - dy = endOfMousePress.getY() - startOfMousePress.getY(); - } - - annotation.resetAppearanceStream(dx, -dy, getPageTransform()); - - // fire new bounds change event, let the listener handle - // how to deal with the bound change. - documentViewController.firePropertyChange( - PropertyConstants.ANNOTATION_BOUNDS, - previousAnnotationState, new AnnotationState(this)); - - // notify the annotation callback of the annotation resize. - if (documentViewController.getAnnotationCallback() != null) { - documentViewController.getAnnotationCallback() - .updateAnnotation(this); - } - } - - // on mouse released event to annotation callback if we are in normal viewing - // mode. A and AA dictionaries are taken into consideration. - additionalActionsHandler(AdditionalActionsDictionary.ANNOTATION_U_KEY, mouseEvent); - - repaint(); - - } - - /** - * Convert the shapes that make up the annotation to page space so that - * they will scale correctly at different zooms. - * - * @return transformed bbox. - */ - protected Rectangle convertToPageSpace(Rectangle rect) { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error converting to page space.", e); - } - // convert the two points as well as the bbox. - Rectangle tBbox = new Rectangle(rect.x, rect.y, - rect.width, rect.height); - - tBbox = at.createTransformedShape(tBbox).getBounds(); - - return tBbox; - - } - - protected AffineTransform getPageTransform() { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error getting page transform.", e); - } - return at; - } - - /** - * Is the annotation editable - * - * @return true if editable, false otherwise. - */ - public boolean isEditable() { - return isEditable; - } - - public boolean isRollover() { - return isRollover; - } - - public boolean isBorderStyle() { - return annotation.isBorder(); - } - - public boolean isSelected() { - return isSelected; - } - - public void setSelected(boolean selected) { - isSelected = selected; - } - - public boolean isMovable() { - return isMovable; - } - - public boolean isResizable() { - return isResizable; - } - - public boolean isShowInvisibleBorder() { - return isShowInvisibleBorder; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/AnnotationComponentFactory.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/AnnotationComponentFactory.java deleted file mode 100644 index c5169b5012..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/AnnotationComponentFactory.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.acroform.FieldDictionaryFactory; -import org.icepdf.core.pobjects.annotations.AbstractWidgetAnnotation; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.TextMarkupAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.lang.reflect.Constructor; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * AnnotationComponentFactory is responsible for building an annotation component - * for given Annotation object. Generally this factor is only used by the annotation - * handlers during the creation of new annotations. When a PageComponent is - * initialized a pages Annotation list is iterated over and this class is used - * to generate the annotations components. - * - * @since 5.0 - */ -public class AnnotationComponentFactory { - - protected static final Logger logger = - Logger.getLogger(AnnotationComponentFactory.class.toString()); - - private static final String BUTTON_FIELD_CLASS = - "org.icepdf.core.pro.acroform.ButtonFieldComponent"; - private static final String CHOICE_FIELD_CLASS = - "org.icepdf.core.pro.acroform.ChoiceFieldComponent"; - private static final String TEXT_FIELD_CLASS = - "org.icepdf.core.pro.acroform.TextFieldComponent"; - private static final String SIGNATURE_FIELD_CLASS = - "org.icepdf.ri.common.views.annotations.SignatureFieldComponent"; - private static final String SIGNATURE_PRO_FIELD_CLASS = - "org.icepdf.core.pro.acroform.SignatureFieldComponent"; - - private AnnotationComponentFactory() { - } - - /** - * Creates an annotation component for the given annotation object subtype. - * - * @param annotation annotation to encapsulate with a component instance - * @param documentViewController document view controller - * @param pageViewComponent parent pageViewComponent - * @param documentViewModel document view model. - * @return annotation component of the type specified by annotation subtype - */ - public synchronized static AbstractAnnotationComponent buildAnnotationComponent( - Annotation annotation, - DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - Name subtype = annotation.getSubType(); - if (subtype != null) { - if (Annotation.SUBTYPE_LINK.equals(subtype)) { - return new LinkAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (TextMarkupAnnotation.isTextMarkupAnnotation(subtype)) { - return new TextMarkupAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_LINE.equals(subtype)) { - return new LineAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_CIRCLE.equals(subtype)) { - return new CircleAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_POLYGON.equals(subtype)) { - return new PolygonAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_POLYLINE.equals(subtype)) { - return new PolyLineAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_SQUARE.equals(subtype)) { - return new SquareAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_POPUP.equals(subtype)) { - return new PopupAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_TEXT.equals(subtype)) { - return new TextAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_INK.equals(subtype)) { - return new InkAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_FREE_TEXT.equals(subtype)) { - return new FreeTextAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } else if (Annotation.SUBTYPE_WIDGET.equals(subtype)) { - AbstractWidgetAnnotation widgetAnnotation = (AbstractWidgetAnnotation) annotation; - Name fieldType = widgetAnnotation.getFieldDictionary().getFieldType(); - // load pro interactive annotation support. - if (Document.foundIncrementalUpdater) { - if (FieldDictionaryFactory.TYPE_BUTTON.equals(fieldType)) { - return generatedWidgetField(BUTTON_FIELD_CLASS, annotation, - documentViewController, pageViewComponent, - documentViewModel); - } else if (FieldDictionaryFactory.TYPE_CHOICE.equals(fieldType)) { - return generatedWidgetField(CHOICE_FIELD_CLASS, annotation, - documentViewController, pageViewComponent, - documentViewModel); - } else if (FieldDictionaryFactory.TYPE_TEXT.equals(fieldType)) { - return generatedWidgetField(TEXT_FIELD_CLASS, annotation, - documentViewController, pageViewComponent, - documentViewModel); - } else if (FieldDictionaryFactory.TYPE_SIGNATURE.equals(fieldType)) { - return generatedWidgetField(SIGNATURE_PRO_FIELD_CLASS, annotation, - documentViewController, pageViewComponent, - documentViewModel); - } - } - // load basic widget support, selection, rendering. - else { - if (FieldDictionaryFactory.TYPE_SIGNATURE.equals(fieldType)) { - return generatedWidgetField(SIGNATURE_FIELD_CLASS, annotation, - documentViewController, pageViewComponent, - documentViewModel); - } else { - return new WidgetAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel); - } - } - } else { - return new AbstractAnnotationComponent(annotation, documentViewController, - pageViewComponent, documentViewModel) { - private static final long serialVersionUID = 409696785049691125L; - - @Override - public void resetAppearanceShapes() { - - } - - @Override - public void paintComponent(Graphics g) { - - } - - public boolean isActive() { - return false; - } - }; - } - } - return null; - } - - private static AbstractAnnotationComponent generatedWidgetField( - final String widgetFieldClassName, - Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - try { - Class widgetFieldClass = Class.forName(widgetFieldClassName); - Class[] widgetArgs = {Annotation.class, DocumentViewController.class, - AbstractPageViewComponent.class, DocumentViewModel.class}; - Constructor widgetFieldClassConstructor = - widgetFieldClass.getDeclaredConstructor(widgetArgs); - Object[] widgetParams = {annotation, documentViewController, - pageViewComponent, documentViewModel}; - return (AbstractAnnotationComponent) widgetFieldClassConstructor.newInstance(widgetParams); - } catch (Throwable e) { - logger.log(Level.WARNING, "Error generating widget field", e); - } - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/AnnotationState.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/AnnotationState.java deleted file mode 100644 index fa339582af..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/AnnotationState.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.Memento; -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.PageTree; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.BorderStyle; -import org.icepdf.ri.common.views.AnnotationComponent; - -import java.awt.*; -import java.awt.geom.Rectangle2D; - -/** - * Stores state paramaters for annotation objects to be used in conjuction - * with a care taker as part of the memento pattern. - * - * @since 4.0 - */ -public class AnnotationState implements Memento { - - // annotation bounding rectangle in user space. - protected Rectangle2D.Float userSpaceRectangle; - - // original rectangle reference. - protected AnnotationComponent annotationComponent; - - /** - * Stores the annotation state associated with the AnnotationComponents - * annotation object. When a new instance of this object is created - * the annotation's proeprties are saved. - * - * @param annotationComponent annotation component who's state will be stored. - */ - public AnnotationState(AnnotationComponent annotationComponent) { - // reference to component so we can apply the state parameters if - // restore() is called. - this.annotationComponent = annotationComponent; - } - - - public void apply(AnnotationState applyState) { - - // store user space rectangle SpaceRectangle. - Rectangle2D.Float rect = applyState.userSpaceRectangle; - if (rect != null) { - userSpaceRectangle = new Rectangle2D.Float(rect.x, rect.y, - rect.width, rect.height); - } - - // apply the new state to the annotation and schedule a sync - restore(); - - } - - /** - * Restores the AnnotationComponents state to the state stored during the - * construction of this object. - */ - public void restore() { - if (annotationComponent != null && - annotationComponent.getAnnotation() != null) { - // get reference to annotation - Annotation annotation = annotationComponent.getAnnotation(); - - restore(annotation); - - // update the document with current state. - synchronizeState(); - } - } - - /** - * Restores the annotation state in this instance to the Annotation - * specified as a param. This method is ment to bue used in - * - * @param annotation annotation to retore state to. - */ - public void restore(Annotation annotation) { - // create a new Border style entry as an inline dictionary - if (annotation.getBorderStyle() == null) { - annotation.setBorderStyle(new BorderStyle()); - } - - // apply old user rectangle - annotation.setUserSpaceRectangle(userSpaceRectangle); - } - - public void synchronizeState() { - // update the document with this change. - int pageIndex = annotationComponent.getPageIndex(); - Document document = annotationComponent.getDocument(); - Annotation annotation = annotationComponent.getAnnotation(); - PageTree pageTree = document.getPageTree(); - Page page = pageTree.getPage(pageIndex); - // state behind draw state. - if (!annotation.isDeleted()) { - page.updateAnnotation(annotation); - // refresh bounds for any resizes - annotationComponent.refreshDirtyBounds(); - } - // special case for an undelete as we need to to make the component - // visible again. - else { - // mark it as not deleted - annotation.setDeleted(false); - // re-add it to the page - page.addAnnotation(annotation); - // finally update the pageComponent so we can see it again. - ((Component) annotationComponent).setVisible(true); - // refresh bounds for any resizes - annotationComponent.refreshDirtyBounds(); - } - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/CircleAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/CircleAnnotationComponent.java deleted file mode 100644 index 1d5af6f721..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/CircleAnnotationComponent.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.CircleAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.event.MouseEvent; - -/** - * The CircleAnnotationComponent encapsulates a CircleAnnotation objects. It - * also provides basic editing functionality such as resizing, moving and change - * the border color and style as well as the fill color. - *

      - * The Viewer RI implementation contains a CircleAnnotationPanel class which - * can edit the various properties of this component. - * - * @see org.icepdf.ri.common.utility.annotation.CircleAnnotationPanel - * @since 5.0 - */ -@SuppressWarnings("serial") -public class CircleAnnotationComponent extends MarkupAnnotationComponent { - - - public CircleAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isShowInvisibleBorder = false; - } - - @Override - public void paintComponent(Graphics g) { - - } - - @Override - public void resetAppearanceShapes() { - refreshAnnotationRect(); - CircleAnnotation circleAnnotation = (CircleAnnotation) annotation; - circleAnnotation.resetAppearanceStream(getPageTransform()); - } - - @Override - public void mouseDragged(MouseEvent me) { - super.mouseDragged(me); - resetAppearanceShapes(); - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/FreeTextAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/FreeTextAnnotationComponent.java deleted file mode 100644 index 41e1d2405f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/FreeTextAnnotationComponent.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.BorderStyle; -import org.icepdf.core.pobjects.annotations.FreeTextAnnotation; -import org.icepdf.core.pobjects.fonts.FontFile; -import org.icepdf.core.pobjects.fonts.FontManager; -import org.icepdf.core.pobjects.graphics.TextSprite; -import org.icepdf.core.pobjects.graphics.commands.DrawCmd; -import org.icepdf.core.pobjects.graphics.commands.TextSpriteDrawCmd; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.AnnotationCallback; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import javax.swing.*; -import javax.swing.border.AbstractBorder; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.html.HTMLEditorKit; -import javax.swing.text.html.parser.ParserDelegator; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.Rectangle2D; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; -import java.util.logging.Logger; - -/** - * The FreeTextAnnotationComponent encapsulates a FreeTextAnnotation objects. It - * also provides basic editing functionality such as resizing, moving and change - * the border color and style as well as the fill color. - *

      - * The Viewer RI implementation contains a FreeTextAnnotationPanel class which - * can edit the various properties of this component. - *

      - * The FreeTextAnnotationComponent is slightly more complex then the other - * annotations components. Most annotations let the page pain the annotation - * but in this cse FreeTextAnnotationComponent paints itself by creating a - * JTextArea component that is made to look like the respective annotations - * appearance stream. - * - * @see org.icepdf.ri.common.utility.annotation.FreeTextAnnotationPanel - * @since 5.0 - */ -@SuppressWarnings("serial") -public class FreeTextAnnotationComponent extends MarkupAnnotationComponent - implements PropertyChangeListener { - - private static final Logger logger = - Logger.getLogger(FreeTextAnnotation.class.toString()); - // font file cache. - protected Font fontFile; - private ScalableTextArea freeTextPane; - private boolean contentTextChange; - private FreeTextAnnotation freeTextAnnotation; - - public FreeTextAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - final AbstractPageViewComponent pageViewComponent, - final DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isRollover = false; - isShowInvisibleBorder = false; - - freeTextAnnotation = (FreeTextAnnotation) annotation; - - // update the shapes array pruning any text glyphs as well as - // extra any useful font information for the editing of this annotation. - if (annotation.getShapes() != null) { - ArrayList shapes = annotation.getShapes().getShapes(); - DrawCmd cmd; - for (int i = 0; i < shapes.size(); i++) { - cmd = shapes.get(i); - if (cmd instanceof TextSpriteDrawCmd) { - // grab the font reference - TextSprite tmp = ((TextSpriteDrawCmd) cmd).getTextSprite(); - FontFile font = tmp.getFont(); - freeTextAnnotation.setFontSize((int) font.getSize()); - freeTextAnnotation.setFontColor(tmp.getStrokeColor()); - // remove all text. - shapes.remove(i); - } - } - ((FreeTextAnnotation) annotation).clearShapes(); - } - // create the textArea to display the text. - freeTextPane = new ScalableTextArea(documentViewModel); - // line wrap false to force users to add line breaks. - freeTextPane.setLineWrap(false); - freeTextPane.setBackground(new Color(0, 0, 0, 0)); - freeTextPane.setMargin(new Insets(0, 0, 0, 0)); - // lock the field until the correct tool selects it. - freeTextPane.setEditable(false); - // clean up the contents make sure we have \n instead of \r - String contents = freeTextAnnotation.getContents(); - if (contents != null) { - contents = contents.replace('\r', '\n'); - freeTextPane.setText(contents); - } - - // setup change listener so we now when to set the annotations AP stream - freeTextPane.getDocument().addDocumentListener(new DocumentListener() { - public void insertUpdate(DocumentEvent e) { - contentTextChange = true; - } - - public void removeUpdate(DocumentEvent e) { - contentTextChange = true; - } - - public void changedUpdate(DocumentEvent e) { - contentTextChange = true; - } - }); - - GridLayout grid = new GridLayout(1, 1, 0, 0); - this.setLayout(grid); - this.add(freeTextPane); - - // add a focus management listener. - KeyboardFocusManager focusManager = - KeyboardFocusManager.getCurrentKeyboardFocusManager(); - focusManager.addPropertyChangeListener(this); - - // set the default size hen building from external file - if (annotation.getBbox() != null) { - setBounds(annotation.getBbox().getBounds()); - } - resetAppearanceShapes(); - revalidate(); - } - - public void setAppearanceStream() { - // copy over annotation properties from the free text annotation. - if (fontFile == null || freeTextAnnotation.isFontPropertyChanged()) { - fontFile = FontManager.getInstance().initialize().getType1AWTFont( - freeTextAnnotation.getFontName(), freeTextAnnotation.getFontSize()); - } - freeTextPane.setFont(fontFile); - freeTextPane.setForeground(freeTextAnnotation.getFontColor()); - - if (freeTextAnnotation.isFillType()) { - freeTextPane.setOpaque(true); - freeTextPane.setBackground(freeTextAnnotation.getFillColor()); - } else { - freeTextPane.setOpaque(false); - } - if (freeTextAnnotation.isStrokeType()) { - if (freeTextAnnotation.getBorderStyle().isStyleSolid()) { - freeTextPane.setBorder(BorderFactory.createLineBorder( - freeTextAnnotation.getColor(), - (int) freeTextAnnotation.getBorderStyle().getStrokeWidth())); - } else if (freeTextAnnotation.getBorderStyle().isStyleDashed()) { - freeTextPane.setBorder( - new DashedBorder(freeTextAnnotation.getBorderStyle(), - freeTextAnnotation.getColor())); - } - } else { - freeTextPane.setBorder(BorderFactory.createEmptyBorder()); - } - - String content = null; - try { - content = freeTextPane.getDocument().getText(0, - freeTextPane.getDocument().getLength()); - } catch (BadLocationException e) { - logger.warning("Error getting rich text."); - } - Rectangle tBbox = convertToPageSpace(getBounds()); - - // generate the shapes - freeTextAnnotation.setBBox(tBbox); - freeTextAnnotation.setContents(content); - freeTextAnnotation.setRichText(freeTextPane.getText()); - freeTextPane.revalidate(); - } - - @Override - public void mouseDragged(MouseEvent me) { - super.mouseDragged(me); - resetAppearanceShapes(); - } - - public void propertyChange(PropertyChangeEvent evt) { - String prop = evt.getPropertyName(); - Object newValue = evt.getNewValue(); - Object oldValue = evt.getOldValue(); - - if ("focusOwner".equals(prop) && - oldValue instanceof JTextArea) { - JTextArea freeText = (JTextArea) oldValue; - if (freeText.equals(freeTextPane)) { - freeText.setEditable(false); - if (contentTextChange) { - contentTextChange = false; - resetAppearanceShapes(); - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - // notification that annotation was updated. - annotationCallback.updateAnnotation(this); - } - } - if (freeText instanceof ScalableTextArea) { - ((ScalableTextArea) freeText).setActive(false); - } - } - repaint(); - } else if ("focusOwner".equals(prop) && - newValue instanceof JTextArea) { - JTextArea freeText = (JTextArea) newValue; - if (freeText.equals(freeTextPane) && !annotation.getFlagReadOnly()) { - freeText.setEditable(true); - if (freeText instanceof ScalableTextArea) { - ((ScalableTextArea) freeText).setActive(true); - } - } - repaint(); - } - } - - @Override - public void mouseMoved(MouseEvent me) { - super.mouseMoved(me); - - } - - @Override - public void paintComponent(Graphics g) { - // show a light border when in edit mode so component is easier to see. - isShowInvisibleBorder = ((documentViewModel.getViewToolMode() == - DocumentViewModel.DISPLAY_TOOL_SELECTION || - documentViewModel.getViewToolMode() == - DocumentViewModel.DISPLAY_TOOL_FREE_TEXT_ANNOTATION) && - !(annotation.getFlagReadOnly() || annotation.getFlagLocked() || - annotation.getFlagInvisible() || annotation.getFlagHidden())); - } - - @Override - public void dispose() { - super.dispose(); - KeyboardFocusManager focusManager = - KeyboardFocusManager.getCurrentKeyboardFocusManager(); - focusManager.removePropertyChangeListener(this); - } - - @Override - public void resetAppearanceShapes() { - setAppearanceStream(); - annotation.resetAppearanceStream(getPageTransform()); - } - - public boolean isActive() { - return this.freeTextPane.isActive(); - } - - public String clearXMLHeader(String strXML) { - String regExp = "[<][?]\\s*[xml].*[?][>]"; - strXML = strXML.replaceFirst(regExp, ""); - return strXML; - } - - public class MyHtml2Text extends HTMLEditorKit.ParserCallback { - StringBuffer s; - - public MyHtml2Text() { - } - - public void parse(Reader in) throws IOException { - s = new StringBuffer(); - ParserDelegator delegator = new ParserDelegator(); - delegator.parse(in, this, Boolean.TRUE); - } - - public void handleText(char[] text, int pos) { - s.append(text); - s.append("\n"); - } - - public String getText() { - return s.toString(); - } - } - - - private class DashedBorder extends AbstractBorder { - private BasicStroke stroke; - private Color color; - - public DashedBorder(BorderStyle borderStyle, Color color) { - int thickness = (int) borderStyle.getStrokeWidth(); - this.stroke = new BasicStroke(thickness, - BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, - thickness * 2.0f, - freeTextAnnotation.getBorderStyle().getDashArray(), - 0.0f); - this.color = color; - } - - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - float size = this.stroke.getLineWidth(); - if (size > 0.0f) { - g = g.create(); - if (g instanceof Graphics2D) { - Graphics2D g2d = (Graphics2D) g; - g2d.setStroke(this.stroke); - g2d.setPaint(color != null ? color : c == null ? null : c.getForeground()); - g2d.draw(new Rectangle2D.Float(x + size / 2, y + size / 2, width - size, height - size)); - } - g.dispose(); - } - } - - public Insets getBorderInsets(Component c, Insets insets) { - insets.left = insets.top = insets.right = insets.bottom = - (int) this.stroke.getLineWidth(); - return insets; - } - - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/FreeTextArea.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/FreeTextArea.java deleted file mode 100644 index ca838d4df6..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/FreeTextArea.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.icepdf.ri.common.views.annotations; - -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -import org.icepdf.ri.util.jxlayer.JXLayer; -import org.icepdf.ri.util.jxlayer.plaf.LayerUI; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; - - -/** - * FreeTextArea extends JTextArea overriding key method need to insure that - * when the parent graphic context is scaled the FreeText area mouse events - * are also taken into account. - * - * @since 5.0.2 - */ -@SuppressWarnings("serial") -public class FreeTextArea extends JTextArea { - - public interface ZoomProvider { - public float getZoom(); - } - - private ZoomProvider zoomProvider; - private boolean active; - public FreeTextArea(final ZoomProvider zoomProvider) { - super(); - this.zoomProvider = zoomProvider; - // enable more precise painting of glyphs. - getDocument().putProperty("i18n", Boolean.TRUE.toString()); - putClientProperty("i18n", Boolean.TRUE.toString()); - LayerUI layerUI = new LayerUI() { - @SuppressWarnings("unchecked") - @Override - public void installUI(JComponent c) { - super.installUI(c); - // enable mouse motion events for the layer's sub components - ((JXLayer) c).setLayerEventMask( - AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); - } - - @SuppressWarnings("unchecked") - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - // reset the layer event mask - ((JXLayer) c).setLayerEventMask(0); - } - - @Override - public void eventDispatched(AWTEvent ae, JXLayer l) { - MouseEvent e = (MouseEvent) ae; - // transform the point in MouseEvent using the current zoom factor - float zoom = FreeTextArea.this.zoomProvider.getZoom(); - MouseEvent newEvent = new MouseEvent((Component) e.getSource(), - e.getID(), e.getWhen(), e.getModifiers(), - (int) (e.getX() / zoom), (int) (e.getY() / zoom), - e.getClickCount(), e.isPopupTrigger(), e.getButton()); - // consume the MouseEvent and then process the modified event - e.consume(); - FreeTextArea.this.processMouseEvent(newEvent); - FreeTextArea.this.processMouseMotionEvent(newEvent); - } - }; - new JXLayer(this, layerUI); - } - - @Override - protected void paintBorder(Graphics g) { - if (!active) { - return; - } - super.paintBorder(g); - } - - @Override - protected void paintComponent(Graphics g) { - if (!active) { - return; - } - float zoom = this.zoomProvider.getZoom(); - Graphics2D g2 = (Graphics2D) g; - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); - AffineTransform old = g2.getTransform(); - g2.scale(zoom, zoom); - // paint the component at the scale of the page. - super.paintComponent(g2); - g2.setTransform(old); - } - - public void repaint(int x, int y, int width, int height) { - super.repaint(0, 0, getWidth(), getHeight()); - } - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/InkAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/InkAnnotationComponent.java deleted file mode 100644 index c30b5b6e89..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/InkAnnotationComponent.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.InkAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.event.MouseEvent; - -/** - * The InkAnnotationComponent encapsulates a InkAnnotation objects. It - * also provides basic editing functionality such as resizing, moving and change - * the border color and style. - *

      - * The Viewer RI implementation contains a InkAnnotationPanel class which - * can edit the various properties of this component. - * - * @see org.icepdf.ri.common.utility.annotation.InkAnnotationPanel - * @since 5.0 - */ -@SuppressWarnings("serial") -public class InkAnnotationComponent extends MarkupAnnotationComponent { - - - public InkAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isShowInvisibleBorder = false; - isResizable = false; - } - - @Override - public void resetAppearanceShapes() { - refreshAnnotationRect(); - InkAnnotation inkAnnotation = (InkAnnotation) annotation; - inkAnnotation.resetAppearanceStream(dx, dy, getPageTransform()); - } - - @Override - public void mouseReleased(MouseEvent mouseEvent) { - wasResized = false; - super.mouseReleased(mouseEvent); - } - - @Override - public void mouseDragged(MouseEvent me) { - super.mouseDragged(me); - dy *= -1; - resetAppearanceShapes(); - } - - @Override - public void paintComponent(Graphics g) { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/LineAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/LineAnnotationComponent.java deleted file mode 100644 index 574da5da44..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/LineAnnotationComponent.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.LineAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.event.MouseEvent; - -/** - * The LineAnnotationComponent encapsulates a LineAnnotation objects. It - * also provides basic editing functionality such as resizing, moving and change - * the border color and style. The start and end line cab can also be changed - * to one of the name types defined in the LineAnnotation class. - *

      - * The Viewer RI implementation contains a LineAnnotationPanel class which - * can edit the various properties of this component. - * - * @see org.icepdf.ri.common.utility.annotation.LineAnnotationPanel - * @since 5.0 - */ -@SuppressWarnings("serial") -public class LineAnnotationComponent extends MarkupAnnotationComponent { - - - public LineAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isRollover = false; - isResizable = false; - isShowInvisibleBorder = false; - } - - @Override - public void paintComponent(Graphics g) { - - } - - @Override - public void mouseReleased(MouseEvent mouseEvent) { - wasResized = false; - super.mouseReleased(mouseEvent); - } - - @Override - public void resetAppearanceShapes() { - refreshAnnotationRect(); - LineAnnotation textMarkupAnnotation = (LineAnnotation) annotation; - textMarkupAnnotation.resetAppearanceStream(dx, dy, getPageTransform()); - } - - @Override - public void mouseDragged(MouseEvent me) { - super.mouseDragged(me); - dy *= -1; - resetAppearanceShapes(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/LinkAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/LinkAnnotationComponent.java deleted file mode 100644 index 7732048b7b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/LinkAnnotationComponent.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.Name; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.LinkAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.geom.Rectangle2D; - -/** - * The LinkAnnotationComponent encapsulates a LinkAnnotation objects. It - * also provides basic editing functionality such as resizing, moving and change - * the border color and style. The rollover effect can also be set to one - * of the named states defined in the LinkAnnotation object. . - *

      - * The Viewer RI implementation contains a LinkAnnotationPanel class which - * can edit the various properties of this component. - * - * @see org.icepdf.ri.common.utility.annotation.LinkAnnotationPanel - * @since 5.0 - */ -@SuppressWarnings("serial") -public class LinkAnnotationComponent extends MarkupAnnotationComponent { - - public LinkAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isShowInvisibleBorder = true; - } - - @Override - public void resetAppearanceShapes() { - - } - - public void paintComponent(Graphics g) { - // sniff out tool bar state to set correct annotation border - isEditable = ((documentViewModel.getViewToolMode() == - DocumentViewModel.DISPLAY_TOOL_SELECTION || - documentViewModel.getViewToolMode() == - DocumentViewModel.DISPLAY_TOOL_LINK_ANNOTATION) && - !(annotation.getFlagReadOnly() || annotation.getFlagLocked() || - annotation.getFlagInvisible() || annotation.getFlagHidden())); - - // paint rollover effects. - if (isMousePressed && !(documentViewModel.getViewToolMode() == - DocumentViewModel.DISPLAY_TOOL_SELECTION || - documentViewModel.getViewToolMode() == - DocumentViewModel.DISPLAY_TOOL_LINK_ANNOTATION)) { - Graphics2D gg2 = (Graphics2D) g; - - LinkAnnotation linkAnnotation = (LinkAnnotation) annotation; - Name highlightMode = linkAnnotation.getHighlightMode(); - Rectangle2D rect = new Rectangle(0, 0, getWidth(), getHeight()); - if (LinkAnnotation.HIGHLIGHT_INVERT.equals(highlightMode)) { - gg2.setColor(annotationHighlightColor); - gg2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - annotationHighlightAlpha)); - gg2.fillRect((int) rect.getX(), - (int) rect.getY(), - (int) rect.getWidth(), - (int) rect.getHeight()); - } else if (LinkAnnotation.HIGHLIGHT_OUTLINE.equals(highlightMode)) { - gg2.setColor(annotationHighlightColor); - gg2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - annotationHighlightAlpha)); - gg2.drawRect((int) rect.getX(), - (int) rect.getY(), - (int) rect.getWidth(), - (int) rect.getHeight()); - } else if (LinkAnnotation.HIGHLIGHT_PUSH.equals(highlightMode)) { - gg2.setColor(annotationHighlightColor); - gg2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - annotationHighlightAlpha)); - gg2.drawRect((int) rect.getX(), - (int) rect.getY(), - (int) rect.getWidth(), - (int) rect.getHeight()); - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/MarkupAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/MarkupAnnotationComponent.java deleted file mode 100644 index 67ea61c6a1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/MarkupAnnotationComponent.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.PDate; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.MarkupAnnotation; -import org.icepdf.core.pobjects.annotations.PopupAnnotation; -import org.icepdf.core.util.Defs; -import org.icepdf.ri.common.tools.TextAnnotationHandler; -import org.icepdf.ri.common.views.*; - -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.awt.geom.NoninvertibleTransformException; -import java.util.ArrayList; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * MarkupAnnotationComponent class encapsulates the component functionality - * needed to display an MarkupAnnotations PopupAnnnotaion component. When - * a MarkupAnnotationComponent is double clicked is child PopupAnnotation component - * will be displayed. - * - * @see CircleAnnotationComponent - * @see FreeTextAnnotationComponent - * @see InkAnnotationComponent - * @see LineAnnotationComponent - * @see LinkAnnotationComponent - * @see PolygonAnnotationComponent - * @see PolyLineAnnotationComponent - * @see SquareAnnotationComponent - * @see TextAnnotationComponent - * @see TextMarkupAnnotationComponent - * @since 5.0 - */ -@SuppressWarnings("serial") -public abstract class MarkupAnnotationComponent extends AbstractAnnotationComponent { - - private static final Logger logger = - Logger.getLogger(TextAnnotationComponent.class.toString()); - - protected static boolean isInteractivePopupAnnotationsEnabled; - - static { - isInteractivePopupAnnotationsEnabled = - Defs.sysPropertyBoolean( - "org.icepdf.core.annotations.interactive.popup.enabled", true); - } - - protected MarkupAnnotation markupAnnotation; - - public MarkupAnnotationComponent(Annotation annotation, - DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - - if (annotation instanceof MarkupAnnotation) { - markupAnnotation = (MarkupAnnotation) annotation; - } - } - - @Override - public void mouseClicked(MouseEvent e) { - super.mouseClicked(e); - // on double click toggle the visibility of the popup component. - if (isInteractivePopupAnnotationsEnabled && e.getClickCount() == 2) { - // we have an annotation so toggle it's visibility - if (markupAnnotation != null) { - PopupAnnotation popup = markupAnnotation.getPopupAnnotation(); - if (popup != null) { - // toggle the visibility of the popup - popup.setOpen(!popup.isOpen()); - // find the popup component - ArrayList annotationComponents = - pageViewComponent.getAnnotationComponents(); - Reference compReference; - Reference popupReference = popup.getPObjectReference(); - for (AnnotationComponent annotationComponent : annotationComponents) { - compReference = annotationComponent.getAnnotation().getPObjectReference(); - // find the component and toggle it's visibility, null check just encase compRef is direct. - if (compReference != null && compReference.equals(popupReference)) { - if (annotationComponent instanceof PopupAnnotationComponent) { - PopupAnnotationComponent popupComponent = ((PopupAnnotationComponent) annotationComponent); - popupComponent.setVisible(popup.isOpen()); - // make sure the popup is drawn on the page and - // not outside the page clip. - Rectangle popupBounds = popupComponent.getBounds(); - Rectangle pageBounds = pageViewComponent.getBounds(); - if (!pageBounds.contains(popupBounds.getX(), popupBounds.getY(), - popupBounds.getWidth(), popupBounds.getHeight())) { - int x = popupBounds.x; - int y = popupBounds.y; - if (x + popupBounds.width > pageBounds.width) { - x = x - (popupBounds.width - (pageBounds.width - popupBounds.x)); - } - if (y + popupBounds.height > pageBounds.height) { - y = y - (popupBounds.height - (pageBounds.height - popupBounds.y)); - } - popupBounds.setLocation(x, y); - popupComponent.setBounds(popupBounds); - } - } - break; - } - } - } - - // no markupAnnotation so we need to create one and display for - // the addition comments. - else { - // convert bbox and start and end line points. - Rectangle bounds = this.getBounds(); - Rectangle bBox = new Rectangle(bounds.x, bounds.y, 215, 150); - - Rectangle tBbox = convertToPageSpace(bBox).getBounds(); - - // apply creation date and title for the markup annotation - // so the popup has some content - if (markupAnnotation != null) { - markupAnnotation.setCreationDate(PDate.formatDateTime(new Date())); - markupAnnotation.setTitleText(System.getProperty("user.name")); - markupAnnotation.setContents(""); - } - - PopupAnnotation annotation = - TextAnnotationHandler.createPopupAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - tBbox, markupAnnotation, getPageTransform()); - - // create the annotation object. - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, - documentViewController, - pageViewComponent, documentViewModel); - // set the bounds and refresh the userSpace rectangle - comp.setBounds(bBox); - // resets user space rectangle to match bbox converted to page space - comp.refreshAnnotationRect(); - - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - pageViewComponent.revalidate(); - } - } - } - } - - /** - * Convert the shapes that make up the annotation to page space so that - * they will scale correctly at different zooms. - * - * @return transformed bbox. - */ - protected Shape convertToPageSpace(Shape shape) { - Page currentPage = pageViewComponent.getPage(); - AffineTransform at = currentPage.getPageTransform( - documentViewModel.getPageBoundary(), - documentViewModel.getViewRotation(), - documentViewModel.getViewZoom()); - try { - at = at.createInverse(); - } catch (NoninvertibleTransformException e) { - logger.log(Level.FINE, "Error converting to page space.", e); - } - - shape = at.createTransformedShape(shape); - - return shape; - - } - - public boolean isActive() { - return false; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/PolyLineAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/PolyLineAnnotationComponent.java deleted file mode 100644 index 6f0ec17850..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/PolyLineAnnotationComponent.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; - -/** - * The PolyLineAnnotationComponent encapsulates a PolyLineAnnotation objects. - *

      - * NOTE: this component is has no handler and can only be created if the parent - * Page object contains a PolygonLineAnnotation. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class PolyLineAnnotationComponent extends MarkupAnnotationComponent { - - public PolyLineAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isShowInvisibleBorder = true; - } - - @Override - public void resetAppearanceShapes() { - - } - - @Override - public void paintComponent(Graphics g) { - - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/PolygonAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/PolygonAnnotationComponent.java deleted file mode 100644 index 6c9fe43beb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/PolygonAnnotationComponent.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; - -/** - * The PolygonAnnotationComponent encapsulates a PolygonAnnotation objects. - *

      - * NOTE: this component is has no handler and can only be created if the parent - * Page object contains a PolygonAnnotation. - * - * @since 5.0 - */ -@SuppressWarnings("serial") -public class PolygonAnnotationComponent extends MarkupAnnotationComponent { - - - public PolygonAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isShowInvisibleBorder = true; - } - - @Override - public void resetAppearanceShapes() { - - } - - @Override - public void paintComponent(Graphics g) { - - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/PopupAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/PopupAnnotationComponent.java deleted file mode 100644 index 4e07fdcf34..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/PopupAnnotationComponent.java +++ /dev/null @@ -1,791 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.Reference; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.MarkupAnnotation; -import org.icepdf.core.pobjects.annotations.PopupAnnotation; -import org.icepdf.core.pobjects.annotations.TextAnnotation; -import org.icepdf.ri.common.tools.TextAnnotationHandler; -import org.icepdf.ri.common.views.*; -import org.icepdf.ri.util.PropertiesManager; - -import javax.swing.*; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.text.BadLocationException; -import javax.swing.text.Document; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.DefaultTreeModel; -import javax.swing.tree.TreeSelectionModel; -import java.awt.*; -import java.awt.event.*; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.ResourceBundle; -import java.util.logging.Level; - -/** - * The PopupAnnotationComponent encapsulates a PopupAnnotation objects. It - * also provides basic editing of the parent MarkupAnnotation's review state: - * accepted, rejected, cancelled, completed, none. The component can also add - * replyTo text annotations as well as delete comments. - *

      - * The PopupAnnotationComponent is slightly more complex then the other - * annotations components. Most annotations let the page pain the annotation - * but in this case PopupAnnotationComponent paints itself along with controls - * for editing, replying and deleting TextAnnotation comments. - * appearance stream. - * - * @see org.icepdf.ri.common.utility.annotation.FreeTextAnnotationPanel - * @since 5.0 - */ -@SuppressWarnings("serial") -public class PopupAnnotationComponent extends AbstractAnnotationComponent - implements TreeSelectionListener, ActionListener, DocumentListener { - - public static Color backgroundColor = new Color(252, 253, 227); - public static Color borderColor = new Color(153, 153, 153); - - protected PopupAnnotation popupAnnotation; - - // layouts constraint - private GridBagConstraints constraints; - - protected JPanel commentPanel; - protected JTextArea textArea; - protected JLabel creationLabel; - protected JButton minimizeButton; - protected JTree commentTree; - protected JScrollPane commentTreeScrollPane; - protected MarkupAnnotation selectedMarkupAnnotation; - // add and remove commands - protected JMenuItem replyMenuItem; - protected JMenuItem deleteMenuItem; - // status change commands. - protected JMenuItem statusNoneMenuItem; - protected JMenuItem statusAcceptedItem; - protected JMenuItem statusCancelledMenuItem; - protected JMenuItem statusCompletedMenuItem; - protected JMenuItem statusRejectedMenuItem; - // generic commands, open/minimize all - protected JMenuItem openAllMenuItem; - protected JMenuItem minimizeAllMenuItem; - protected JPopupMenu contextMenu; - - public PopupAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - - isEditable = true; - isRollover = false; - isMovable = true; - isResizable = true; - isShowInvisibleBorder = false; - - if (annotation instanceof PopupAnnotation) { - popupAnnotation = (PopupAnnotation) annotation; - try { - popupAnnotation.init(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Popup annotation component instance creation was interrupted"); - } - } - - boolean isVisible = popupAnnotation.isOpen(); - setVisible(isVisible); - - buildGUI(); - } - - public void mouseMoved(MouseEvent me) { - if (!(annotation.getFlagLocked() || annotation.getFlagReadOnly())) { - ResizableBorder border = (ResizableBorder) getBorder(); - setCursor(Cursor.getPredefinedCursor(border.getCursor(me))); - } - } - - @Override - public void mousePressed(MouseEvent e) { - - // setup visual effect when the mouse button is pressed or held down - // inside the active area of the annotation. - isMousePressed = true; - - if (isInteractiveAnnotationsEnabled && - !annotation.getFlagReadOnly()) { - initiateMouseMoved(e); - } - repaint(); - } - - @Override - public void mouseEntered(MouseEvent e) { - super.mouseEntered(e); - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - - private void buildGUI() { - - List annotations = pageViewComponent.getPage().getAnnotations(); - MarkupAnnotation parentAnnotation = popupAnnotation.getParent(); - - // check first if there are anny annotation that point to this one as - // an IRT. If there aren't any then the selectedAnnotation is the parent - // other wise we need to build out - DefaultMutableTreeNode root = - new DefaultMutableTreeNode("Root"); - boolean isIRT = buildCommentTree(parentAnnotation, annotations, root); - commentTree = new JTree(root); - commentTree.setRootVisible(true); - commentTree.setExpandsSelectedPaths(true); - commentTree.setShowsRootHandles(true); - commentTree.setScrollsOnExpand(true); - commentTree.setRootVisible(false); - commentTree.getSelectionModel().setSelectionMode( - TreeSelectionModel.SINGLE_TREE_SELECTION); - commentTree.addTreeSelectionListener(this); - // expand the tree - refreshTree(commentTree); - // set look and feel to match outline style - DefaultTreeCellRenderer renderer = new DefaultTreeCellRenderer(); - renderer.setOpenIcon(null); - renderer.setClosedIcon(null); - renderer.setLeafIcon(null); - commentTree.setCellRenderer(renderer); - commentTree.addMouseListener(new PopupTreeListener()); - commentTreeScrollPane = new JScrollPane(commentTree); - // make sure the root node is selected by default. - commentTree.setSelectionRow(0); - - // Set the - selectedMarkupAnnotation = parentAnnotation; - - // minimize button - minimizeButton = new JButton(" _ "); - minimizeButton.addActionListener(this); - minimizeButton.setBackground(backgroundColor); - minimizeButton.setOpaque(true); - minimizeButton.setContentAreaFilled(false); - minimizeButton.setBorder(BorderFactory.createLineBorder(borderColor)); - minimizeButton.setBorderPainted(true); - minimizeButton.addActionListener(this); - - // text area edited the selected annotation markup contents. - String contents = popupAnnotation.getParent() != null ? - popupAnnotation.getParent().getContents() : ""; - textArea = new JTextArea(contents != null ? contents : ""); - textArea.setFont(new JLabel().getFont()); - textArea.setBorder(BorderFactory.createLineBorder(borderColor)); - - textArea.setLineWrap(true); - textArea.getDocument().addDocumentListener(this); - - // creation date - creationLabel = new JLabel(); - if (selectedMarkupAnnotation != null && - selectedMarkupAnnotation.getCreationDate() != null) { - creationLabel.setText( - selectedMarkupAnnotation.getCreationDate().toString()); - } - - // main layout panel - GridBagLayout layout = new GridBagLayout(); - commentPanel = new JPanel(layout); - commentPanel.setBackground(backgroundColor); - commentPanel.setBorder(BorderFactory.createLineBorder(borderColor)); - this.setLayout(new BorderLayout()); - this.add(commentPanel); - - /** - * Build search GUI - */ - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.weighty = 0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(1, 5, 1, 5); - - // currently selected title - constraints.fill = GridBagConstraints.EAST; - constraints.weightx = 0; - String title = selectedMarkupAnnotation != null ? - selectedMarkupAnnotation.getTitleText() != null ? - selectedMarkupAnnotation.getTitleText() : "" : ""; - addGB(commentPanel, new JLabel(title), 0, 0, 1, 1); - - // add minimize button - constraints.fill = GridBagConstraints.REMAINDER; - constraints.weightx = 0; - addGB(commentPanel, minimizeButton, 2, 0, 1, 1); - - // add comment tree if there are any IRT's - constraints.fill = GridBagConstraints.BOTH; - constraints.insets = new Insets(1, 5, 1, 5); - constraints.weightx = 1.0; - constraints.weighty = .6; - commentTreeScrollPane.setVisible(isIRT); - addGB(commentPanel, commentTreeScrollPane, 0, 1, 3, 1); - - // creation date of selected comment - constraints.insets = new Insets(1, 5, 1, 5); - constraints.weightx = 1.0; - constraints.weighty = 0; - constraints.fill = GridBagConstraints.EAST; - addGB(commentPanel, - creationLabel, - 0, 2, 1, 1); - - // add the text area - constraints.fill = GridBagConstraints.BOTH; - constraints.insets = new Insets(1, 5, 5, 5); - constraints.weightx = 1.0; - constraints.weighty = .4; - addGB(commentPanel, textArea, 0, 3, 3, 1); - - // command test - buildContextMenu(); - } - - private void refreshTree(JTree tree) { - ((DefaultTreeModel) (tree.getModel())).reload(); - for (int i = 0; i < tree.getRowCount(); i++) { - tree.expandRow(i); - } - } - - public void buildContextMenu() { - - ResourceBundle messages = - documentViewController.getParentController().getMessageBundle(); - PropertiesManager propertiesManager = documentViewController.getParentController().getPropertiesManager(); - - //Create the popup menu. - contextMenu = new JPopupMenu(); - - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_ANNOTATION_MARKUP_REPLY_TO)) { - replyMenuItem = new JMenuItem( - messages.getString("viewer.annotation.popup.reply.label")); - // build out reply and delete - replyMenuItem.addActionListener(this); - contextMenu.add(replyMenuItem); - } - deleteMenuItem = new JMenuItem( - messages.getString("viewer.annotation.popup.delete.label")); - // status change commands. - statusNoneMenuItem = new JMenuItem( - messages.getString("viewer.annotation.popup.status.none.label")); - statusAcceptedItem = new JMenuItem( - messages.getString("viewer.annotation.popup.status.accepted.label")); - statusCancelledMenuItem = new JMenuItem( - messages.getString("viewer.annotation.popup.status.cancelled.label")); - statusCompletedMenuItem = new JMenuItem( - messages.getString("viewer.annotation.popup.status.completed.label")); - statusRejectedMenuItem = new JMenuItem( - messages.getString("viewer.annotation.popup.status.rejected.label")); - // generic commands, open/minimize all - openAllMenuItem = new JMenuItem( - messages.getString("viewer.annotation.popup.openAll.label")); - minimizeAllMenuItem = new JMenuItem( - messages.getString("viewer.annotation.popup.minimizeAll.label")); - - // build out delete - deleteMenuItem.addActionListener(this); - contextMenu.add(deleteMenuItem); - contextMenu.addSeparator(); - - if (PropertiesManager.checkAndStoreBooleanProperty(propertiesManager, - PropertiesManager.PROPERTY_SHOW_ANNOTATION_MARKUP_SET_STATUS)) { - // addition of set status menu - JMenu submenu = new JMenu( - messages.getString("viewer.annotation.popup.status.label")); -// ButtonGroup group = new ButtonGroup(); - statusNoneMenuItem.addActionListener(this); -// group.add(statusNoneMenuItem); - submenu.add(statusNoneMenuItem); - statusAcceptedItem.addActionListener(this); -// group.add(statusAcceptedItem); - submenu.add(statusAcceptedItem); - statusCancelledMenuItem.addActionListener(this); -// group.add(statusCancelledMenuItem); - submenu.add(statusCancelledMenuItem); - statusCompletedMenuItem.addActionListener(this); -// group.add(statusCompletedMenuItem); - submenu.add(statusCompletedMenuItem); - statusRejectedMenuItem.addActionListener(this); -// group.add(statusRejectedMenuItem); - submenu.add(statusRejectedMenuItem); - contextMenu.add(submenu); - contextMenu.addSeparator(); - } - - // generic commands, open/minimize all - openAllMenuItem.addActionListener(this); - contextMenu.add(openAllMenuItem); - minimizeAllMenuItem.addActionListener(this); - contextMenu.add(minimizeAllMenuItem); - - // Add listener to components that can bring up popup menus. - MouseListener popupListener = new PopupListener(); - textArea.addMouseListener(popupListener); - commentPanel.addMouseListener(popupListener); - } - - public void actionPerformed(ActionEvent e) { - Object source = e.getSource(); - if (source == null) - return; - // hide the window on minimize - if (source == minimizeButton) { - this.setVisible(false); - popupAnnotation.setOpen(false); - } else if (source == replyMenuItem) { - - // setup title message - Object[] argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.replyTo.label")); - String annotationTitle = formatter.format(argument); - - createNewTextAnnotation( - annotationTitle, - "", - TextAnnotation.STATE_MODEL_REVIEW, - TextAnnotation.STATE_REVIEW_NONE); - } else if (source == deleteMenuItem) { - // remove the annotation - AnnotationComponent annotationComponent = findAnnotationComponent(selectedMarkupAnnotation); - documentViewController.deleteAnnotation(annotationComponent); - // remove the annotations popup - annotationComponent = findAnnotationComponent(selectedMarkupAnnotation.getPopupAnnotation()); - documentViewController.deleteAnnotation(annotationComponent); - - // check if any annotations have an IRT reference and delete - // the markup component chain - removeMarkupInReplyTo(selectedMarkupAnnotation.getPObjectReference()); - - // rebuild the tree, which is easier then pruning at this point - List annotations = pageViewComponent.getPage().getAnnotations(); - MarkupAnnotation parentAnnotation = popupAnnotation.getParent(); - - // check first if there are anny annotation that point to this one as - // an IRT. If there aren't any then the selectedAnnotation is the parent - // other wise we need to build out - DefaultMutableTreeNode root = - new DefaultMutableTreeNode("Root"); - boolean isIRT = buildCommentTree(parentAnnotation, annotations, root); - commentTree.removeTreeSelectionListener(this); - ((DefaultTreeModel) (commentTree.getModel())).setRoot(root); - commentTree.addTreeSelectionListener(this); - // reload the tree model - refreshTree(commentTree); - if (!isIRT) { - commentTreeScrollPane.setVisible(false); - } - commentPanel.revalidate(); - - } else if (source == statusNoneMenuItem) { - // setup title message - Object[] argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.none.title")); - String title = formatter.format(argument); - // setup content message - argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.none.msg")); - String content = formatter.format(argument); - createNewTextAnnotation(title, content, - TextAnnotation.STATE_MODEL_REVIEW, - TextAnnotation.STATE_REVIEW_NONE); - } else if (source == statusAcceptedItem) { - // setup title message - Object[] argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.accepted.title")); - String title = formatter.format(argument); - // setup content message - argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.accepted.msg")); - String content = formatter.format(argument); - createNewTextAnnotation(title, content, - TextAnnotation.STATE_MODEL_REVIEW, - TextAnnotation.STATE_REVIEW_NONE); - } else if (source == statusCancelledMenuItem) { - // setup title message - Object[] argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.cancelled.title")); - String title = formatter.format(argument); - // setup content message - argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.cancelled.msg")); - String content = formatter.format(argument); - createNewTextAnnotation(title, content, - TextAnnotation.STATE_MODEL_REVIEW, - TextAnnotation.STATE_REVIEW_NONE); - } else if (source == statusCompletedMenuItem) { - // setup title message - Object[] argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.completed.title")); - String title = formatter.format(argument); - // setup content message - argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.completed.msg")); - String content = formatter.format(argument); - createNewTextAnnotation(title, content, - TextAnnotation.STATE_MODEL_REVIEW, - TextAnnotation.STATE_REVIEW_NONE); - } else if (source == statusRejectedMenuItem) { - // setup title message - Object[] argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.rejected.title")); - String title = formatter.format(argument); - // setup content message - argument = new Object[]{selectedMarkupAnnotation.getTitleText()}; - formatter = new MessageFormat( - messageBundle.getString("viewer.annotation.popup.status.rejected.msg")); - String content = formatter.format(argument); - createNewTextAnnotation(title, content, - TextAnnotation.STATE_MODEL_REVIEW, - TextAnnotation.STATE_REVIEW_NONE); - } else if (source == openAllMenuItem) { - showHidePopupAnnotations(true); - - } else if (source == minimizeAllMenuItem) { - showHidePopupAnnotations(false); - } - } - - private void showHidePopupAnnotations(boolean visible) { - ArrayList annotationComponents = - pageViewComponent.getAnnotationComponents(); - for (AnnotationComponent annotationComponent : annotationComponents) { - if (annotationComponent instanceof PopupAnnotationComponent) { - PopupAnnotationComponent popupAnnotationComponent = (PopupAnnotationComponent) annotationComponent; - if (popupAnnotationComponent.getAnnotation() != null) { - PopupAnnotation popupAnnotation = (PopupAnnotation) - popupAnnotationComponent.getAnnotation(); - if (popupAnnotation.getParent() != null && - popupAnnotation.getParent().getInReplyToAnnotation() == null) { - popupAnnotationComponent.setVisible(visible); - } - } - } - } - } - - private void createNewTextAnnotation(String title, String content, - String stateModel, String state) { - // on reply we need to create a new textAnnotation/popup combo - // and setup the IRT references for display - TextAnnotation markupAnnotation = - TextAnnotationHandler.createTextAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - selectedMarkupAnnotation.getUserSpaceRectangle().getBounds(), - getPageTransform()); - markupAnnotation.setTitleText(title); - markupAnnotation.setContents(content); - markupAnnotation.setState(state); - markupAnnotation.setStateModel(stateModel); - markupAnnotation.setInReplyToAnnotation(selectedMarkupAnnotation); - addAnnotationComponent(markupAnnotation); - - // create the new text and popup annotations - PopupAnnotation popupAnnotation = - TextAnnotationHandler.createPopupAnnotation( - documentViewModel.getDocument().getPageTree().getLibrary(), - this.popupAnnotation.getUserSpaceRectangle().getBounds(), - markupAnnotation, getPageTransform()); - popupAnnotation.setOpen(false); - addAnnotationComponent(popupAnnotation); - - // finally add the node as child to the selected node - DefaultMutableTreeNode node = (DefaultMutableTreeNode) - commentTree.getLastSelectedPathComponent(); - - DefaultMutableTreeNode replyToNode = - new DefaultMutableTreeNode(markupAnnotation); - if (node == null) { - node = ((DefaultMutableTreeNode) commentTree.getModel().getRoot()).getFirstLeaf(); - } - node.insert(replyToNode, node.getChildCount()); - - commentTree.expandRow(replyToNode.getDepth() - 1); - selectedMarkupAnnotation = markupAnnotation; - - // reload the tree model - refreshTree(commentTree); - - // finally check the view and make sure the treePanel is visible. - commentTreeScrollPane.setVisible(true); - commentPanel.revalidate(); - } - - public void insertUpdate(DocumentEvent e) { - updateContent(e); - } - - public void removeUpdate(DocumentEvent e) { - updateContent(e); - } - - public void changedUpdate(DocumentEvent e) { - updateContent(e); - } - - private void updateContent(DocumentEvent e) { - // get the next text and save it to the selected markup annotation. - Document document = e.getDocument(); - try { - if (document.getLength() > 0) { - selectedMarkupAnnotation.setContents( - document.getText(0, document.getLength())); - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - AnnotationComponent annotationComponent = findAnnotationComponent(popupAnnotation.getParent()); - annotationCallback.updateAnnotation(annotationComponent); - } - } - } catch (BadLocationException ex) { - logger.log(Level.FINE, "Error updating markup annotation content", ex); - } - } - - public void valueChanged(TreeSelectionEvent e) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) - commentTree.getLastSelectedPathComponent(); - - // Nothing is selected. - if (node == null) - return; - - Object userObject = node.getUserObject(); - if (userObject instanceof MarkupAnnotation) { - selectedMarkupAnnotation = (MarkupAnnotation) userObject; - if (textArea != null) { - textArea.getDocument().removeDocumentListener(this); - textArea.setText(selectedMarkupAnnotation.getContents()); - textArea.getDocument().addDocumentListener(this); - } - if (creationLabel != null) { - creationLabel.setText(selectedMarkupAnnotation.getCreationDate().toString()); - } - } - } - - public boolean isActive() { - return false; - } - - - /** - * Gridbag constructor helper - * - * @param panel parent adding component too. - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan rowspane of field - * @param colSpan colspane of field. - */ - private void addGB(JPanel panel, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - panel.add(component, constraints); - } - - private boolean buildCommentTree(MarkupAnnotation parentAnnotation, - List annotations, - DefaultMutableTreeNode root) { - boolean foundIRT = checkForIRT(parentAnnotation, annotations); - DefaultMutableTreeNode node = new DefaultMutableTreeNode(parentAnnotation); - root.add(node); - if (!foundIRT) { - // simple test add a new node for the parent annotation. - return false; - } else { - // find every IRT and add it to the tree. - buildRecursiveCommentTree(node, annotations); - return true; - } - - } - - private void buildRecursiveCommentTree(DefaultMutableTreeNode root, - List annotations) { - MarkupAnnotation currentMarkup = (MarkupAnnotation) root.getUserObject(); - Reference reference = currentMarkup.getPObjectReference(); - for (Annotation annotation : annotations) { - if (annotation != null && annotation instanceof MarkupAnnotation) { - MarkupAnnotation markupAnnotation = (MarkupAnnotation) annotation; - MarkupAnnotation inReplyToAnnotation = - markupAnnotation.getInReplyToAnnotation(); - if (inReplyToAnnotation != null && - inReplyToAnnotation.getPObjectReference().equals(reference)) { - // found one no were to attach it to. - root.add(new DefaultMutableTreeNode(markupAnnotation)); - } - } - } - int childCount = root.getChildCount(); - for (int i = 0; i < childCount; i++) { - buildRecursiveCommentTree((DefaultMutableTreeNode) root.getChildAt(i), - annotations); - } - - } - - private void removeMarkupInReplyTo(Reference reference) { - if (reference != null) { - ArrayList annotationComponents = - pageViewComponent.getAnnotationComponents(); - MarkupAnnotationComponent markupAnnotationComponent; - MarkupAnnotation markupAnnotation; - AnnotationComponent annotationComponent; - for (int i = 0; i < annotationComponents.size(); i++) { - annotationComponent = annotationComponents.get(i); - if (annotationComponent instanceof MarkupAnnotationComponent) { - markupAnnotationComponent = (MarkupAnnotationComponent) annotationComponent; - markupAnnotation = (MarkupAnnotation) - markupAnnotationComponent.getAnnotation(); - if (markupAnnotation.getInReplyToAnnotation() != null && - markupAnnotation.getInReplyToAnnotation() - .getPObjectReference().equals(reference)) { - // recursive check if there are any object that refer - // to this IRT annotation being deleted. - removeMarkupInReplyTo(markupAnnotation.getPObjectReference()); - documentViewController.deleteAnnotation(markupAnnotationComponent); - } - } - } - } - } - - private boolean checkForIRT(MarkupAnnotation parentAnnotation, - List annotations) { - if (parentAnnotation != null) { - Reference reference = parentAnnotation.getPObjectReference(); - for (Annotation annotation : annotations) { - if (annotation instanceof MarkupAnnotation) { - MarkupAnnotation markupAnnotation = (MarkupAnnotation) annotation; - MarkupAnnotation inReplyToAnnotation = - markupAnnotation.getInReplyToAnnotation(); - if (inReplyToAnnotation != null && - inReplyToAnnotation.getPObjectReference().equals(reference)) - return true; - } - } - } - return false; - } - - private void addAnnotationComponent(Annotation annotation) { - // draw them off screen - Rectangle bBox = new Rectangle(-20, -20, 20, 20); - // create the annotation object. - AbstractAnnotationComponent comp = - AnnotationComponentFactory.buildAnnotationComponent( - annotation, - documentViewController, - pageViewComponent, documentViewModel); - // set the bounds and refresh the userSpace rectangle - comp.setBounds(bBox); - // resets user space rectangle to match bbox converted to page space - comp.refreshAnnotationRect(); - - // add them to the container, using absolute positioning. - if (documentViewController.getAnnotationCallback() != null) { - AnnotationCallback annotationCallback = - documentViewController.getAnnotationCallback(); - annotationCallback.newAnnotation(pageViewComponent, comp); - } - } - - private AnnotationComponent findAnnotationComponent(Annotation annotation) { - ArrayList annotationComponents = - pageViewComponent.getAnnotationComponents(); - Reference compReference; - Reference annotationReference = annotation.getPObjectReference(); - for (AnnotationComponent annotationComponent : annotationComponents) { - compReference = annotationComponent.getAnnotation().getPObjectReference(); - // find the component and toggle it's visibility. - if (compReference != null && compReference.equals(annotationReference)) { - return annotationComponent; - } - } - return null; - } - - @Override - public void paintComponent(Graphics g) { - - } - - @Override - public void resetAppearanceShapes() { - - } - - class PopupTreeListener extends MouseAdapter { - @Override - public void mouseClicked(MouseEvent e) { - if (SwingUtilities.isRightMouseButton(e)) { - int row = commentTree.getClosestRowForLocation(e.getX(), e.getY()); - commentTree.setSelectionRow(row); - contextMenu.show(e.getComponent(), e.getX(), e.getY()); - } - } - } - - class PopupListener extends MouseAdapter { - - public void mousePressed(MouseEvent e) { - maybeShowPopup(e); - } - - public void mouseReleased(MouseEvent e) { - maybeShowPopup(e); - } - - private void maybeShowPopup(MouseEvent e) { - if (e.isPopupTrigger()) { - contextMenu.show(e.getComponent(), - e.getX(), e.getY()); - } - } - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableField.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableField.java deleted file mode 100644 index aa2e55055a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableField.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -/** - * Common interface for all scalable widgets. - * - * @since 5.1 - */ -public interface ScalableField { - - boolean isActive(); - - void setActive(boolean active); - - void setEditable(boolean editable); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableJComboBox.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableJComboBox.java deleted file mode 100644 index 701429626a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableJComboBox.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.util.jxlayer.JXLayer; -import org.icepdf.ri.util.jxlayer.plaf.LayerUI; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.util.Vector; - -/** - * Scalable JComboBox that scales as the document zoom is changed. - * - * @since 5.1 - */ -public class ScalableJComboBox extends JComboBox implements ScalableField { - - private static final long serialVersionUID = -353525405737762626L; - private DocumentViewModel documentViewModel; - private boolean active; - - public ScalableJComboBox(Vector items, final DocumentViewModel documentViewModel) { - super(items); - this.documentViewModel = documentViewModel; - // enable more precise painting of glyphs. - putClientProperty("i18n", Boolean.TRUE.toString()); - LayerUI layerUI = new LayerUI() { - private static final long serialVersionUID = 1152416379916442539L; - @SuppressWarnings("unchecked") - @Override - public void installUI(JComponent c) { - super.installUI(c); - // enable mouse motion events for the layer's sub components - ((JXLayer) c).setLayerEventMask( - AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); - } - - @SuppressWarnings("unchecked") - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - // reset the layer event mask - ((JXLayer) c).setLayerEventMask(0); - } - - @Override - public void eventDispatched(AWTEvent ae, JXLayer l) { - MouseEvent e = (MouseEvent) ae; - // transform the point in MouseEvent using the current zoom factor - float zoom = documentViewModel.getViewZoom(); - MouseEvent newEvent = new MouseEvent((Component) e.getSource(), - e.getID(), e.getWhen(), e.getModifiers(), - (int) (e.getX() / zoom), (int) (e.getY() / zoom), - e.getClickCount(), e.isPopupTrigger(), e.getButton()); - // consume the MouseEvent and then process the modified event - e.consume(); - ScalableJComboBox.this.processMouseEvent(newEvent); - ScalableJComboBox.this.processMouseMotionEvent(newEvent); - } - }; - new JXLayer(this, layerUI); - } - - @Override - protected void paintBorder(Graphics g) { - if (!active) { - return; - } - super.paintBorder(g); - } - - @Override - protected void paintComponent(Graphics g) { - if (!active) { - return; - } - super.paintComponent(g); - } - - public void repaint(int x, int y, int width, int height) { - super.repaint(); - } - - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableJList.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableJList.java deleted file mode 100644 index 7612fe8b95..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableJList.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.ri.common.views.DocumentViewModel; - -import javax.swing.*; -import java.awt.*; - -/** - * - */ -public class ScalableJList extends JList implements ScalableField { - - private static final long serialVersionUID = 1434627181898233990L; - private boolean active; - - public ScalableJList(ListModel dataModel, final DocumentViewModel documentViewModel) { - super(dataModel); - } - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } - - public void setEditable(boolean editable) { - super.setEnabled(editable); - } - - @Override - protected void paintBorder(Graphics g) { - if (!active) { - return; - } - super.paintBorder(g); - } - - @Override - protected void paintComponent(Graphics g) { - if (!active) { - return; - } - super.paintComponent(g); - } - - @Override - public void repaint(int x, int y, int width, int height) { - super.repaint(); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableJScrollPane.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableJScrollPane.java deleted file mode 100644 index 30ecf5a9f2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableJScrollPane.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.ri.common.views.DocumentViewModel; - -import javax.swing.*; -import java.awt.*; - -/** - * @since 5.1 - */ -public class ScalableJScrollPane extends JScrollPane implements ScalableField { - - - private static final long serialVersionUID = -7748761572295520052L; - private boolean active; - - public ScalableJScrollPane(Component view, final DocumentViewModel documentViewModel) { - super(view); - } - - public boolean isActive() { - return active; //To change body of implemented methods use File | Settings | File Templates. - } - - public void setActive(boolean active) { - this.active = active; - } - - public void setEditable(boolean editable) { -// this.setEditable(editable); - } - - @Override - protected void paintBorder(Graphics g) { - if (!active) { - return; - } - super.paintBorder(g); - } - - @Override - protected void paintComponent(Graphics g) { - if (!active) { - return; - } - super.paintComponent(g); - } - - // @Override - protected void paintChildren(Graphics g) { - if (!active) { - return; - } - super.paintChildren(g); - } - @Override - public void repaint(int x, int y, int width, int height) { - super.repaint(); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalablePasswordField.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalablePasswordField.java deleted file mode 100644 index 09eede9657..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalablePasswordField.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.util.jxlayer.JXLayer; -import org.icepdf.ri.util.jxlayer.plaf.LayerUI; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; - -/** - * Scalable JPassword that scales as the document zoom is changed. - * - * @since 5.1 - */ -public class ScalablePasswordField extends JPasswordField implements ScalableField { - - - private static final long serialVersionUID = 3832310978215996618L; - private DocumentViewModel documentViewModel; - private boolean active; - - public ScalablePasswordField(final DocumentViewModel documentViewModel) { - super(); - this.documentViewModel = documentViewModel; - // enable more precise painting of glyphs. - getDocument().putProperty("i18n", Boolean.TRUE.toString()); - putClientProperty("i18n", Boolean.TRUE.toString()); - LayerUI layerUI = new LayerUI() { - private static final long serialVersionUID = 1155416379916442519L; - @SuppressWarnings("unchecked") - @Override - public void installUI(JComponent c) { - super.installUI(c); - // enable mouse motion events for the layer's sub components - ((JXLayer) c).setLayerEventMask( - AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); - } - - @SuppressWarnings("unchecked") - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - // reset the layer event mask - ((JXLayer) c).setLayerEventMask(0); - } - - @Override - public void eventDispatched(AWTEvent ae, JXLayer l) { - MouseEvent e = (MouseEvent) ae; - // transform the point in MouseEvent using the current zoom factor - float zoom = documentViewModel.getViewZoom(); - MouseEvent newEvent = new MouseEvent((Component) e.getSource(), - e.getID(), e.getWhen(), e.getModifiers(), - (int) (e.getX() / zoom), (int) (e.getY() / zoom), - e.getClickCount(), e.isPopupTrigger(), e.getButton()); - // consume the MouseEvent and then process the modified event - e.consume(); - ScalablePasswordField.this.processMouseEvent(newEvent); - ScalablePasswordField.this.processMouseMotionEvent(newEvent); - } - }; - new JXLayer(this, layerUI); - } - - @Override - protected void paintBorder(Graphics g) { - if (!active) { - return; - } - super.paintBorder(g); - } - - @Override - protected void paintComponent(Graphics g) { - if (!active) { - return; - } - super.paintComponent(g); - } - - public void repaint(int x, int y, int width, int height) { - super.repaint(); - } - - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableTextArea.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableTextArea.java deleted file mode 100644 index 5e6aef7c52..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableTextArea.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.views.annotations; - - -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.util.jxlayer.JXLayer; -import org.icepdf.ri.util.jxlayer.plaf.LayerUI; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; - -/** - * ScalableTextArea extends JTextArea overriding key method need to insure that - * when the parent graphic context is scaled the FreeText area mouse events - * are also taken into account. - * - * @since 5.0.2 - */ -public class ScalableTextArea extends JTextArea implements ScalableField { - - private static final long serialVersionUID = 409696785049691125L; - private DocumentViewModel documentViewModel; - private boolean active; - - public ScalableTextArea(final DocumentViewModel documentViewModel) { - super(); - this.documentViewModel = documentViewModel; - - // enable more precise painting of glyphs. - getDocument().putProperty("i18n", Boolean.TRUE.toString()); - putClientProperty("i18n", Boolean.TRUE.toString()); - LayerUI layerUI = new LayerUI() { - private static final long serialVersionUID = 1155416379916342539L; - @SuppressWarnings("unchecked") - @Override - public void installUI(JComponent c) { - super.installUI(c); - // enable mouse motion events for the layer's sub components - ((JXLayer) c).setLayerEventMask( - AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); - } - - @SuppressWarnings("unchecked") - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - // reset the layer event mask - ((JXLayer) c).setLayerEventMask(0); - } - - @Override - public void eventDispatched(AWTEvent ae, JXLayer l) { - MouseEvent e = (MouseEvent) ae; - // transform the point in MouseEvent using the current zoom factor - float zoom = documentViewModel.getViewZoom(); - MouseEvent newEvent = new MouseEvent((Component) e.getSource(), - e.getID(), e.getWhen(), e.getModifiers(), - (int) (e.getX() / zoom), (int) (e.getY() / zoom), - e.getClickCount(), e.isPopupTrigger(), e.getButton()); - // consume the MouseEvent and then process the modified event - e.consume(); - ScalableTextArea.this.processMouseEvent(newEvent); - ScalableTextArea.this.processMouseMotionEvent(newEvent); - } - }; - new JXLayer(this, layerUI); - } - - @Override - protected void paintBorder(Graphics g) { - if (!active) { - return; - } - super.paintBorder(g); - } - - @Override - protected void paintComponent(Graphics g) { - if (!active) { - return; - } - float zoom = documentViewModel.getViewZoom(); - Graphics2D g2 = (Graphics2D) g; - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); - AffineTransform old = g2.getTransform(); - g2.scale(zoom, zoom); - // paint the component at the scale of the page. - super.paintComponent(g2); - g2.setTransform(old); - } - - public void repaint(int x, int y, int width, int height) { -// super.repaint(0, 0, getWidth(), getHeight()); - super.repaint(); - } - - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableTextField.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableTextField.java deleted file mode 100644 index 571f5496a2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/ScalableTextField.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.util.jxlayer.JXLayer; -import org.icepdf.ri.util.jxlayer.plaf.LayerUI; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseEvent; - -/** - * ScalableTextField extends JTextField overriding key method need to insure that - * when the parent graphic context is scaled the FreeText area mouse events - * are also taken into account. - * - * @since 5.0.2 - */ -public class ScalableTextField extends JTextField implements ScalableField { - - private static final long serialVersionUID = 1155416379916442539L; - private DocumentViewModel documentViewModel; - private boolean active; - - public ScalableTextField(final DocumentViewModel documentViewModel) { - super(); - this.documentViewModel = documentViewModel; - // enable more precise painting of glyphs. - getDocument().putProperty("i18n", Boolean.TRUE.toString()); - putClientProperty("i18n", Boolean.TRUE.toString()); - LayerUI layerUI = new LayerUI() { - private static final long serialVersionUID = 1155416372916442539L; - @SuppressWarnings("unchecked") - @Override - public void installUI(JComponent c) { - super.installUI(c); - // enable mouse motion events for the layer's sub components - ((JXLayer) c).setLayerEventMask( - AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); - } - - @SuppressWarnings("unchecked") - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - // reset the layer event mask - ((JXLayer) c).setLayerEventMask(0); - } - - @Override - public void eventDispatched(AWTEvent ae, JXLayer l) { - MouseEvent e = (MouseEvent) ae; - // transform the point in MouseEvent using the current zoom factor - float zoom = documentViewModel.getViewZoom(); - MouseEvent newEvent = new MouseEvent((Component) e.getSource(), - e.getID(), e.getWhen(), e.getModifiers(), - (int) (e.getX() / zoom), (int) (e.getY() / zoom), - e.getClickCount(), e.isPopupTrigger(), e.getButton()); - // consume the MouseEvent and then process the modified event - e.consume(); - ScalableTextField.this.processMouseEvent(newEvent); - ScalableTextField.this.processMouseMotionEvent(newEvent); - } - }; - new JXLayer(this, layerUI); - } - - @Override - protected void paintBorder(Graphics g) { - if (!active) { - return; - } - super.paintBorder(g); - } - - @Override - protected void paintComponent(Graphics g) { - if (!active) { - return; - } - // paint the component at the scale of the page. - super.paintComponent(g); - } - - public void repaint(int x, int y, int width, int height) { - super.repaint(); - } - - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/SignatureFieldComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/SignatureFieldComponent.java deleted file mode 100644 index 0bb81db81a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/SignatureFieldComponent.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - - -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.SignatureHandler; -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; -import org.icepdf.ri.common.views.annotations.signatures.CertificatePropertiesDialog; -import org.icepdf.ri.common.views.annotations.signatures.SignaturePropertiesDialog; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseEvent; -import java.util.logging.Logger; - -/** - * UI component that represents a Acroform signature widget in the interactive UI. - * Focus, mouse, validation and form submission is handled by this class. - * - * @since 6.1 - */ -public class SignatureFieldComponent extends WidgetAnnotationComponent { - - private static final Logger logger = - Logger.getLogger(SignatureFieldComponent.class.toString()); - - protected SignatureWidgetAnnotation signatureWidgetAnnotation; - protected JPopupMenu contextMenu; - protected SwingController controller; - - public SignatureFieldComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - - controller = (SwingController) documentViewController.getParentController(); - - isShowInvisibleBorder = true; - isResizable = false; - isMovable = false; - signatureWidgetAnnotation = getSignatureWidgetAnnotation(); - - // add context menu for quick access to validating and signature properties. - contextMenu = new JPopupMenu(); - JMenuItem validationMenu = new JMenuItem(messageBundle.getString( - "viewer.annotation.signature.menu.showCertificates.label")); - validationMenu.addActionListener(new CertificatePropertiesActionListener()); - contextMenu.add(validationMenu); - contextMenu.add(new JPopupMenu.Separator()); - JMenuItem signaturePropertiesMenu = new JMenuItem(messageBundle.getString( - "viewer.annotation.signature.menu.signatureProperties.label")); - signaturePropertiesMenu.addActionListener(new signerPropertiesActionListener()); - contextMenu.add(signaturePropertiesMenu); - } - - /** - * Utility for showing SignaturePropertiesDialog via a double click or the context menu. - */ - protected void showSignatureWidgetPropertiesDialog() { - SignatureFieldDictionary fieldDictionary = signatureWidgetAnnotation.getFieldDictionary(); - if (fieldDictionary != null) { - SignatureValidator signatureValidator = signatureWidgetAnnotation.getSignatureValidator(); - if (signatureValidator != null) { - try { - signatureValidator.validate(); - new SignaturePropertiesDialog(controller.getViewerFrame(), - messageBundle, signatureWidgetAnnotation).setVisible(true); - } catch (SignatureIntegrityException e1) { - logger.fine("Error validating annotation " + signatureWidgetAnnotation.toString()); - } - } - } - } - - /** - * Shows the CertificatePropertiesDialog. - */ - class CertificatePropertiesActionListener implements ActionListener { - public void actionPerformed(ActionEvent actionEvent) { - // validate the signature and show the summary dialog. - SignatureFieldDictionary fieldDictionary = signatureWidgetAnnotation.getFieldDictionary(); - if (fieldDictionary != null) { - SignatureHandler signatureHandler = fieldDictionary.getLibrary().getSignatureHandler(); - SignatureValidator signatureValidator = signatureHandler.validateSignature(fieldDictionary); - if (signatureValidator != null) { - try { - signatureValidator.validate(); - new CertificatePropertiesDialog(controller.getViewerFrame(), - messageBundle, signatureValidator.getCertificateChain()).setVisible(true); - } catch (SignatureIntegrityException e1) { - logger.fine("Error validating annotation " + signatureWidgetAnnotation.toString()); - } - } - } - } - } - - /** - * Opens the SignaturePropertiesDialog from a context menu. - */ - class signerPropertiesActionListener implements ActionListener { - public void actionPerformed(ActionEvent actionEvent) { - showSignatureWidgetPropertiesDialog(); - } - } - - @Override - public void mouseClicked(MouseEvent e) { - super.mouseClicked(e); - if (e.getClickCount() == 2) { - // show signature details dialog. - showSignatureWidgetPropertiesDialog(); - } - // pick up on the context menu display - else if (e.getButton() == MouseEvent.BUTTON3 || e.getButton() == MouseEvent.BUTTON2) { - contextMenu.show(e.getComponent(), e.getX(), e.getY()); - } - } - - /** - * Gets the associated widgit annotation. - * - * @return SignatureWidgetAnnotation for the instance annotation object. - */ - private SignatureWidgetAnnotation getSignatureWidgetAnnotation() { - SignatureWidgetAnnotation widget = null; - if (annotation instanceof SignatureWidgetAnnotation) { - widget = (SignatureWidgetAnnotation) annotation; - } else { - // corner case for PDF that aren't well formed - try { - widget = new SignatureWidgetAnnotation(annotation); - widget.init(); - annotation = widget; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.fine("Signature component annotation instance creation was interrupted"); - } - } - return widget; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/SquareAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/SquareAnnotationComponent.java deleted file mode 100644 index ca3c9e6178..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/SquareAnnotationComponent.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.SquareAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.awt.event.MouseEvent; - -/** - * The SquareAnnotationComponent encapsulates a SquareAnnotation objects. It - * also provides basic editing functionality such as resizing, moving and change - * the border color and style as well as the fill color. - *

      - * The Viewer RI implementation contains a SquareAnnotationPanel class which - * can edit the various properties of this component. - * - * @see org.icepdf.ri.common.utility.annotation.SquareAnnotationPanel - * @since 5.0 - */ -@SuppressWarnings("serial") -public class SquareAnnotationComponent extends MarkupAnnotationComponent { - - - public SquareAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isRollover = false; - isShowInvisibleBorder = false; - } - - @Override - public void resetAppearanceShapes() { - refreshAnnotationRect(); - SquareAnnotation squareAnnotation = (SquareAnnotation) annotation; - squareAnnotation.resetAppearanceStream(getPageTransform()); - } - - @Override - public void paintComponent(Graphics g) { - - } - - @Override - public void mouseDragged(MouseEvent me) { - super.mouseDragged(me); - resetAppearanceShapes(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/TextAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/TextAnnotationComponent.java deleted file mode 100644 index a3b3f26d39..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/TextAnnotationComponent.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.util.logging.Logger; - -/** - * The TextAnnotationComponent encapsulates a TextAnnotation objects. It - * also provides basic editing functionality such as resizing, moving and change - * the border color and style as well as the fill color. - *

      - * The Viewer RI implementation contains a TextAnnotationPanel class which - * can edit the various properties of this component. - * - * @see org.icepdf.ri.common.utility.annotation.TextAnnotationPanel - * @since 5.0 - */ -@SuppressWarnings("serial") -public class TextAnnotationComponent extends MarkupAnnotationComponent { - - private static final Logger logger = - Logger.getLogger(TextAnnotationComponent.class.toString()); - - public TextAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isRollover = false; - isMovable = true; - isResizable = false; - isShowInvisibleBorder = false; - - } - - @Override - public void resetAppearanceShapes() { - annotation.resetAppearanceStream(getPageTransform()); - } - - @Override - public void paintComponent(Graphics g) { - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/TextMarkupAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/TextMarkupAnnotationComponent.java deleted file mode 100644 index f257f30ba3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/TextMarkupAnnotationComponent.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.core.pobjects.annotations.TextMarkupAnnotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.util.logging.Logger; - -/** - * - */ -@SuppressWarnings("serial") -public class TextMarkupAnnotationComponent extends MarkupAnnotationComponent { - - private static final Logger logger = - Logger.getLogger(TextMarkupAnnotationComponent.class.toString()); - - public TextMarkupAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, - DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - isMovable = false; - isResizable = false; - isShowInvisibleBorder = false; - } - - @Override - public void resetAppearanceShapes() { - TextMarkupAnnotation textMarkupAnnotation = (TextMarkupAnnotation) annotation; - textMarkupAnnotation.resetAppearanceStream(getPageTransform()); - } - - public void paintComponent(Graphics g) { - - /** - * Initial try at getting each component to paint he annotation content. - * Not quite working but though it should be kept for future work. - */ - - // sniff out tool bar state to set correct annotation border -// isEditable = ( -// (documentViewModel.getViewToolMode() == DocumentViewModel.DISPLAY_TOOL_SELECTION) -// && -// !(annotation.getFlagReadOnly() || annotation.getFlagLocked() || -// annotation.getFlagInvisible() || annotation.getFlagHidden())); - - -// Graphics2D gg2 = (Graphics2D) g; -// AffineTransform oldTransform = gg2.getTransform(); -// -// Rectangle2D bounds = annotation.getUserSpaceRectangle();// getBounds(); - // apply page transform. -// AffineTransform at = currentPage.getPageTransform( -// documentViewModel.getPageBoundary(), -// documentViewModel.getViewRotation(), -// documentViewModel.getViewZoom()); -// PRectangle pageBoundary = currentPage.getPageBoundary(documentViewModel.getPageBoundary()); -// at.translate(pageBoundary.getX() -bounds.getX(), -// pageBoundary.getY() - bounds.getY() - bounds.getHeight()); -// gg2.transform(at); - - // get current tool state, we don't want to draw the highlight - // state if the selection tool is selected. -// boolean notSelectTool = -// documentViewModel.getViewToolMode() != -// DocumentViewModel.DISPLAY_TOOL_SELECTION; - - // paint all annotations on top of the content buffer -// annotation.render(gg2, -// GraphicsRenderingHints.SCREEN, -// documentViewModel.getViewRotation(), -// documentViewModel.getViewZoom(), -// hasFocus() && notSelectTool); - - // reset the graphics context so that the border will show up in the - // correct spot. -// gg2.setTransform(oldTransform); - - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/WidgetAnnotationComponent.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/WidgetAnnotationComponent.java deleted file mode 100644 index b2d50f72d3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/WidgetAnnotationComponent.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ - -package org.icepdf.ri.common.views.annotations; - -import org.icepdf.core.pobjects.annotations.Annotation; -import org.icepdf.ri.common.views.AbstractPageViewComponent; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewModel; - -import java.awt.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - -/** - * - */ -@SuppressWarnings("serial") -public class WidgetAnnotationComponent extends AbstractAnnotationComponent implements PropertyChangeListener { - - - public WidgetAnnotationComponent(Annotation annotation, DocumentViewController documentViewController, - AbstractPageViewComponent pageViewComponent, DocumentViewModel documentViewModel) { - super(annotation, documentViewController, pageViewComponent, documentViewModel); - if (annotation.allowScreenOrPrintRenderingOrInteraction()) { - isShowInvisibleBorder = true; - isResizable = true; - isMovable = true; - // assign property change listener so we can notification of annotation value change, via the - // edit panel or form reset action. - annotation.addPropertyChangeListener(this); - }else{ - // border state flags. - isEditable = false; - isRollover = false; - isMovable = false; - isResizable = false; - isShowInvisibleBorder = false; - } - isSelected = false; - - } - - @Override - public void resetAppearanceShapes() { - - } - - @Override - public void paintComponent(Graphics g) { - - } - - public boolean isActive() { - return false; - } - - public void propertyChange(PropertyChangeEvent evt) { - - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/CertificatePropertiesDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/CertificatePropertiesDialog.java deleted file mode 100644 index a71c48573d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/CertificatePropertiesDialog.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations.signatures; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x500.style.BCStyle; -import org.icepdf.core.util.HexDumper; -import org.icepdf.ri.common.EscapeJDialog; -import org.icepdf.ri.common.utility.signatures.SignatureUtilities; -import org.icepdf.ri.images.Images; - -import javax.swing.*; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.table.DefaultTableModel; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeCellRenderer; -import javax.swing.tree.TreeSelectionModel; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.security.MessageDigest; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.text.MessageFormat; -import java.util.Collection; -import java.util.ResourceBundle; - -/** - * CertificatePropertiesDialog takes a certificate chain and displays each certificate in a summery view. Certificates - * can be easily viewed and selected via a jTree component hierarchy. - */ -public class CertificatePropertiesDialog extends EscapeJDialog { - - protected static ResourceBundle messageBundle; - private Collection certs; - - public CertificatePropertiesDialog(Frame parent, ResourceBundle messageBundle, Collection certs) { - super(parent, true); - CertificatePropertiesDialog.messageBundle = messageBundle; - this.certs = certs; - buildUI(); - } - - public CertificatePropertiesDialog(JDialog parent, ResourceBundle messageBundle, Collection certs) { - super(parent, true); - CertificatePropertiesDialog.messageBundle = messageBundle; - this.certs = certs; - buildUI(); - } - - private void buildUI() { - setTitle(messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.title")); - - getContentPane().setLayout(new BorderLayout()); - Certificate[] certArray = new Certificate[certs.size()]; - int i = 0; - for (Certificate certificate : certs) { - certArray[i] = certificate; - i++; - } - getContentPane().add(getComponents(certArray), - BorderLayout.CENTER); - - JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING)); - JButton closeButton = new JButton(messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.closeButton.label")); - closeButton.setMnemonic("viewer.utilityPane.signatures.cert.dialog.closeButton.mnemonic".charAt(0)); - closeButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - setVisible(false); - } - }); - buttonPanel.add(closeButton); - getContentPane().add(buttonPanel, BorderLayout.SOUTH); - setSize(new Dimension(760, 450)); - setLocationRelativeTo(getParent()); - setResizable(true); - } - - /** - * builds out the dialog components, mainly the tree and info panel. - */ - private JComponent getComponents(Certificate[] certificateChain) { - - if (certificateChain.length > 0) { - final JTable certificateInfoTable = new JTable(); - final JTextArea propteryValueTextAea = new JTextArea(); - // Build certificate chain into a tree hierarchy. - final JTree certChainTree = buildCertChainTree(certificateChain); - certChainTree.addTreeSelectionListener(new TreeSelectionListener() { - public void valueChanged(TreeSelectionEvent e) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode) certChainTree.getLastSelectedPathComponent(); - if (node != null) { - CertificateInfo certInfo = (CertificateInfo) node.getUserObject(); - // Show certificate in the cert info panel - showCertificateInfo(certInfo.getCertificate(), certificateInfoTable, propteryValueTextAea); - } - } - }); - // Build certificate info table - showCertificateInfo((X509Certificate) certificateChain[0], certificateInfoTable, propteryValueTextAea); - certificateInfoTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - ListSelectionModel selectionModel = certificateInfoTable.getSelectionModel(); - selectionModel.addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { - int row = certificateInfoTable.getSelectedRow(); - if (row >= 0) { - String value = (String) certificateInfoTable.getValueAt(row, 1); - // Update text area when selection changes - propteryValueTextAea.setText(value); - propteryValueTextAea.repaint(); - } - } - }); - - // main properties view. - propteryValueTextAea.setLineWrap(false); - propteryValueTextAea.setEditable(false); - propteryValueTextAea.setRows(10); - propteryValueTextAea.setColumns(40); - // Get font from ResourceManager, and create new font - Font fixedWidthFont = new java.awt.Font("Monospaced", java.awt.Font.PLAIN, 12); - propteryValueTextAea.setFont(fixedWidthFont); - - // Select last row by default - certificateInfoTable.setRowSelectionInterval(8, 8); - - // Create cert info panel - JScrollPane scrollPane = new JScrollPane(certificateInfoTable); - JSplitPane panelInfo = new JSplitPane(JSplitPane.VERTICAL_SPLIT); - panelInfo.setDividerLocation(175); - panelInfo.setTopComponent(scrollPane); - panelInfo.setBottomComponent(new JScrollPane(propteryValueTextAea)); - - JSplitPane panel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); - panel.setBorder(BorderFactory.createCompoundBorder( - BorderFactory.createEmptyBorder(5, 5, 5, 5), - scrollPane.getBorder())); - panel.setDividerLocation(200); - scrollPane = new JScrollPane(certChainTree); - - panel.setLeftComponent(scrollPane); - panel.setRightComponent(panelInfo); - - return panel; - } - return new JPanel(); - } - - /** - * Break down DN string into an array used for message format. - * Organization: {0}\n Organization Unit :{1}\n Common Name: {2}\n Local: {3}\n State: {4}\n Country:{5}\n Email: {6} - */ - private Object[] formatDNString(X500Name rdName) { - Object[] output = new Object[7]; - output[0] = parseRelativeDistinguishedName(rdName, BCStyle.O); - output[1] = parseRelativeDistinguishedName(rdName, BCStyle.OU); - output[2] = parseRelativeDistinguishedName(rdName, BCStyle.CN); - output[3] = parseRelativeDistinguishedName(rdName, BCStyle.L); - output[4] = parseRelativeDistinguishedName(rdName, BCStyle.ST); - output[5] = parseRelativeDistinguishedName(rdName, BCStyle.C); - output[6] = parseRelativeDistinguishedName(rdName, BCStyle.EmailAddress); - return output; - } - - protected static String parseRelativeDistinguishedName(X500Name rdName, ASN1ObjectIdentifier commonCode) { - String rdn = SignatureUtilities.parseRelativeDistinguishedName(rdName, commonCode); - if (rdn != null) { - return rdn; - } - return messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.notAvailable.label"); - } - - /** - * Method to reflect certificate chain in the tree view - */ - private JTree buildCertChainTree(Certificate cert[]) { - DefaultMutableTreeNode root = null; - DefaultMutableTreeNode currentNode = null; - for (Certificate aCert : cert) { - DefaultMutableTreeNode childNode = new DefaultMutableTreeNode( - new CertificateInfo((X509Certificate) aCert, messageBundle)); - if (root == null) { - root = childNode; - currentNode = childNode; - } else { - currentNode.add(childNode); - currentNode = childNode; - } - } - JTree tree = new JTree(root); - // Disable HTML to disable anchor click out. - DefaultTreeCellRenderer customCellRenderer = new DefaultTreeCellRenderer(); - customCellRenderer.putClientProperty("html.disable", Boolean.TRUE); - customCellRenderer.setOpenIcon(new ImageIcon(Images.get("page.gif"))); - customCellRenderer.setClosedIcon(new ImageIcon(Images.get("page.gif"))); - customCellRenderer.setLeafIcon(new ImageIcon(Images.get("page.gif"))); - tree.setCellRenderer(customCellRenderer); - - // Allow single node selection only - tree.getSelectionModel().setSelectionMode( - TreeSelectionModel.SINGLE_TREE_SELECTION); - tree.setRootVisible(true); - tree.setShowsRootHandles(true); - tree.setScrollsOnExpand(true); - - return tree; - } - - /** - * Converts a byte to hex digit and writes to the supplied buffer - */ - private void byte2hex(byte b, StringBuffer buf) { - char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - int high = ((b & 0xf0) >> 4); - int low = (b & 0x0f); - buf.append(hexChars[high]); - buf.append(hexChars[low]); - } - - /** - * Converts a byte array to hex string - */ - private String toHexString(byte[] block) { - StringBuffer buf = new StringBuffer(); - int len = block.length; - for (int i = 0; i < len; i++) { - byte2hex(block[i], buf); - if (i < len - 1) { - buf.append(":"); - } - } - return buf.toString(); - } - - /** - * Gets the requested finger print of the certificate. - */ - private String getCertFingerPrint(String mdAlg, X509Certificate cert) - throws Exception { - byte[] encCertInfo = cert.getEncoded(); - MessageDigest md = MessageDigest.getInstance(mdAlg); - byte[] digest = md.digest(encCertInfo); - return toHexString(digest); - } - - /** - * Method to reflect table data based on the certificate - */ - private void showCertificateInfo(X509Certificate cert, - JTable certInfoTable, JTextArea textArea) { - MessageFormat formatter = new MessageFormat(messageBundle.getString( - "viewer.utilityPane.signatures.cert.dialog.info.version.value")); - String certVersion = formatter.format(new Object[]{String.valueOf(cert.getVersion())}); - - formatter.applyPattern(messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.serialNumber.value")); - String serialNumber = formatter.format(new Object[]{String.valueOf(cert.getSerialNumber())}); - - formatter.applyPattern(messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.signatureAlgorithm.value")); - String signatureAlgorithm = formatter.format(new Object[]{cert.getSigAlgName()}); - - formatter.applyPattern(messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.issuer.value")); - String issuer = formatter.format(formatDNString(new X500Name(cert.getIssuerDN().toString()))); - - formatter.applyPattern(messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.validity.value")); - String validity = formatter.format(new Object[]{cert.getNotBefore(), cert.getNotAfter()}); - - formatter.applyPattern(messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.subject.value")); - String subject = formatter.format(formatDNString(new X500Name(cert.getSubjectDN().toString()))); - - String signature = new HexDumper().dump(cert.getSignature()); - String md5 = null; - String sha1 = null; - try { - formatter.applyPattern(messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.md5.value")); - md5 = formatter.format(new Object[]{getCertFingerPrint("MD5", cert)}); - formatter.applyPattern(messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.sha1.value")); - sha1 = formatter.format(new Object[]{getCertFingerPrint("SHA1", cert)}); - } catch (Throwable e) { - // eat any errors. - } - Object[][] data = { - {messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.version.label"), certVersion}, - {messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.serialNumber.label"), serialNumber}, - {messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.signatureAlgorithm.label"), signatureAlgorithm}, - {messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.issuer.label"), issuer}, - {messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.validity.label"), validity}, - {messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.subject.label"), subject}, - {messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.signature.label"), signature}, - {messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.md5.label"), md5}, - {messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.sha1.label"), sha1}}; - - String[] columnNames = { - messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.column1.label"), - messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.column2.label")}; - - certInfoTable.setModel(new DefaultTableModel(data, columnNames) { - public boolean isCellEditable(int row, int col) { - return false; - } - }); - - // Select last row by default - certInfoTable.setRowSelectionInterval(8, 8); - certInfoTable.repaint(); - textArea.repaint(); - } -} - -class CertificateInfo { - private X509Certificate cert; - private ResourceBundle messageBundle; - - CertificateInfo(X509Certificate cert, ResourceBundle messageBundle) { - this.cert = cert; - this.messageBundle = messageBundle; - } - - public X509Certificate getCertificate() { - return cert; - } - - /** - * Extrace CN from DN in the certificate. - * - * @param cert X509 certificate - * @return CN - */ - private String extractAliasName(X509Certificate cert) { - String subjectName = messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.unknownSubject.label"); - String issuerName = messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.unknownIssuer.label"); - // Extract CN from the DN for each certificate - try { - X500Name principal = new X500Name(cert.getSubjectDN().toString()); - X500Name principalIssuer = new X500Name(cert.getIssuerDN().toString()); - - // Extract subject name - subjectName = CertificatePropertiesDialog.parseRelativeDistinguishedName(principal, BCStyle.CN); - if (subjectName == null) { - subjectName = CertificatePropertiesDialog.parseRelativeDistinguishedName(principal, BCStyle.O); - } - if (subjectName == null) { - subjectName = messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.unknownSubject.label"); - } - // Extract issuer name - issuerName = CertificatePropertiesDialog.parseRelativeDistinguishedName(principalIssuer, BCStyle.CN); - if (issuerName == null) { - issuerName = CertificatePropertiesDialog.parseRelativeDistinguishedName(principalIssuer, BCStyle.O); - } - if (issuerName == null) { - issuerName = messageBundle.getString("viewer.utilityPane.signatures.cert.dialog.info.unknownIssuer.label"); - } - } catch (Exception e) { - e.printStackTrace(); - } - - // Add Subject name and Issuer name in the return string - MessageFormat messageFormat = new MessageFormat(messageBundle.getString( - "viewer.utilityPane.signatures.cert.dialog.info.certificateInfo.label")); - Object[] args = {subjectName, issuerName}; - return messageFormat.format(args); - } - - - public String toString() { - return extractAliasName(cert); - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignaturePropertiesDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignaturePropertiesDialog.java deleted file mode 100644 index ea897ff469..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignaturePropertiesDialog.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations.signatures; - -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; -import org.icepdf.ri.common.EscapeJDialog; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ResourceBundle; -import java.util.logging.Logger; - -/** - * The SignaturePropertiesDialog shows a signatures basic information; validation, signer info and a summary panel. - */ -public class SignaturePropertiesDialog extends EscapeJDialog { - - private static final Logger logger = - Logger.getLogger(SignaturePropertiesDialog.class.toString()); - - // layouts constraint - private GridBagConstraints constraints; - - private SignatureValidator signatureValidator; - protected static ResourceBundle messageBundle; - protected SignatureWidgetAnnotation signatureWidgetAnnotation; - - public SignaturePropertiesDialog(Dialog parent, ResourceBundle messageBundle, - SignatureWidgetAnnotation signatureWidgetAnnotation) { - super(parent, true); - SignaturePropertiesDialog.messageBundle = messageBundle; - this.signatureValidator = signatureWidgetAnnotation.getSignatureValidator(); - this.signatureWidgetAnnotation = signatureWidgetAnnotation; - buildUI(); - } - - public SignaturePropertiesDialog(Frame parent, ResourceBundle messageBundle, - SignatureWidgetAnnotation signatureWidgetAnnotation) { - super(parent, true); - SignaturePropertiesDialog.messageBundle = messageBundle; - this.signatureValidator = signatureWidgetAnnotation.getSignatureValidator(); - this.signatureWidgetAnnotation = signatureWidgetAnnotation; - buildUI(); - } - - private void buildUI() { - - SignatureValidationStatus signatureValidationStatus = - new SignatureValidationStatus(messageBundle, signatureWidgetAnnotation, signatureValidator); - - JPanel annotationPanel = new JPanel(new GridBagLayout()); - add(annotationPanel, BorderLayout.NORTH); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.HORIZONTAL; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.WEST; - constraints.insets = new Insets(5, 10, 10, 10); - - // basic signer information - SignerSummaryPanel signerSummaryPanel = - new SignerSummaryPanel(signatureValidationStatus, messageBundle, signatureWidgetAnnotation, signatureValidator, true); - addGB(annotationPanel, signerSummaryPanel, 0, 0, 2, 1); - - // Validity summary - SignatureValidationPanel validityPanel = - new SignatureValidationPanel(signatureValidationStatus, messageBundle, signatureWidgetAnnotation, - signatureValidator, false, true); - addGB(annotationPanel, validityPanel, 0, 1, 2, 1); - - - // SignatureSigner info - SignerInfoPanel signerInfoPanel = new SignerInfoPanel(signatureValidationStatus, messageBundle, signatureWidgetAnnotation, signatureValidator); - addGB(annotationPanel, signerInfoPanel, 0, 2, 2, 1); - - // close buttons. - // simple close - final JButton closeButton = new JButton(messageBundle.getString( - "viewer.annotation.signature.validation.dialog.close.button.label")); - closeButton.setMnemonic(messageBundle.getString("viewer.button.cancel.mnemonic").charAt(0)); - closeButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - setVisible(false); - dispose(); - } - }); - final JButton certPropertiesButton = new JButton(messageBundle.getString( - "viewer.annotation.signature.properties.dialog.showCertificates.label")); - final JDialog parent = this; - certPropertiesButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - new CertificatePropertiesDialog(parent, messageBundle, - signatureValidator.getCertificateChain()) - .setVisible(true); - } - }); - - constraints.anchor = GridBagConstraints.WEST; - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - addGB(annotationPanel, certPropertiesButton, 0, 3, 1, 1); - - constraints.anchor = GridBagConstraints.EAST; - constraints.weightx = 1.0; - addGB(annotationPanel, closeButton, 1, 3, 1, 1); - - // pack it up and go. - getContentPane().add(annotationPanel); - pack(); - setLocationRelativeTo(getOwner()); - setResizable(false); - } - - private void addGB(JPanel layout, Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - layout.add(component, constraints); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignatureValidationDialog.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignatureValidationDialog.java deleted file mode 100644 index 49661eccdc..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignatureValidationDialog.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations.signatures; - -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.SignatureHandler; -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; -import org.icepdf.ri.common.EscapeJDialog; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ResourceBundle; -import java.util.logging.Logger; - -/** - * The SignatureValidationDialog shows a summary of the validation status of a signature. This - * is very similar to the signature tree view in the Signature utility tab. - */ -public class SignatureValidationDialog extends EscapeJDialog { - - private static final Logger logger = - Logger.getLogger(SignatureValidationDialog.class.toString()); - - private SignatureValidator signatureValidator; - protected static ResourceBundle messageBundle; - protected SignatureWidgetAnnotation signatureWidgetAnnotation; - - public SignatureValidationDialog(Frame parent, ResourceBundle messageBundle, - SignatureWidgetAnnotation signatureWidgetAnnotation, SignatureValidator signatureValidator) { - super(parent, true); - this.messageBundle = messageBundle; - this.signatureValidator = signatureValidator; - this.signatureWidgetAnnotation = signatureWidgetAnnotation; - buildUI(); - } - - protected void buildUI() { - SignatureValidationStatus signatureValidationStatus = - new SignatureValidationStatus(messageBundle, signatureWidgetAnnotation, signatureValidator); - - setTitle(messageBundle.getString("viewer.annotation.signature.validation.dialog.title")); - // simple close - final JButton closeButton = new JButton(messageBundle.getString( - "viewer.annotation.signature.validation.dialog.close.button.label")); - closeButton.setMnemonic(messageBundle.getString("viewer.button.cancel.mnemonic").charAt(0)); - closeButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - setVisible(false); - dispose(); - } - }); - - // launch properties dialog showing all signature info. - final JButton propertiesButton = new JButton(messageBundle.getString( - "viewer.annotation.signature.validation.dialog.signerProperties.button.label")); - final Dialog parent = this; - propertiesButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - SignatureFieldDictionary fieldDictionary = signatureWidgetAnnotation.getFieldDictionary(); - if (fieldDictionary != null) { - SignatureHandler signatureHandler = fieldDictionary.getLibrary().getSignatureHandler(); - SignatureValidator signatureValidator = signatureHandler.validateSignature(fieldDictionary); - if (signatureValidator != null) { - new SignaturePropertiesDialog(parent, messageBundle, signatureWidgetAnnotation) - .setVisible(true); - } - } - } - }); - - // put it all together. - SignatureValidationPanel validityPanel = - new SignatureValidationPanel(signatureValidationStatus, messageBundle, signatureWidgetAnnotation, - signatureValidator, true, false); - GridBagConstraints constraints = validityPanel.getConstraints(); - - constraints.insets = new Insets(15, 5, 5, 5); - constraints.anchor = GridBagConstraints.WEST; - validityPanel.addGB(propertiesButton, 0, 5, 1, 1); - - constraints.anchor = GridBagConstraints.EAST; - validityPanel.addGB(closeButton, 1, 5, 1, 1); - - getContentPane().add(validityPanel); - pack(); - setLocationRelativeTo(getOwner()); - setResizable(false); - } - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignatureValidationPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignatureValidationPanel.java deleted file mode 100644 index 68a6aded46..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignatureValidationPanel.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations.signatures; - -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import java.awt.*; -import java.util.ResourceBundle; - -/** - * SignatureValidationPanel shows a summary of the the validation results. - */ -public class SignatureValidationPanel extends JPanel { - // layouts constraint - private GridBagConstraints constraints; - - - public SignatureValidationPanel(SignatureValidationStatus signatureValidationStatus, ResourceBundle messageBundle, - SignatureWidgetAnnotation signatureWidgetAnnotation, SignatureValidator signatureValidator, - boolean showIcon, boolean showBorder) { - if (showBorder) { - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.annotation.signature.properties.dialog.validity.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - } - - // get the respective image. - JLabel validityIconLabel = new JLabel(new ImageIcon(signatureValidationStatus.getValidityIconPath())); - - // put it all together. - setAlignmentY(JPanel.TOP_ALIGNMENT); - GridBagLayout layout = new GridBagLayout(); - setLayout(layout); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.CENTER; - constraints.insets = new Insets(5, 5, 5, 5); - if (showIcon) { - addGB(validityIconLabel, 0, 0, 1, 4); - } - - constraints.anchor = GridBagConstraints.WEST; - addGB(new JLabel(signatureValidationStatus.getValidity()), 1, 0, 1, 1); - addGB(new JLabel(signatureValidationStatus.getSingedBy()), 1, 1, 1, 1); - addGB(new JLabel(signatureValidationStatus.getDocumentModified()), 1, 2, 1, 1); - addGB(new JLabel(signatureValidationStatus.getCertificateTrusted()), 1, 3, 1, 1); - addGB(new JLabel(signatureValidationStatus.getSignatureTime()), 1, 4, 1, 1); - - } - - /** - * Gridbag constructor helper - * - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan - * @param colSpan - */ - public void addGB(Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - this.add(component, constraints); - } - - public GridBagConstraints getConstraints() { - return constraints; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignatureValidationStatus.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignatureValidationStatus.java deleted file mode 100644 index 1c26bf3520..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignatureValidationStatus.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations.signatures; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.asn1.x500.style.BCStyle; -import org.icepdf.core.pobjects.acroform.SignatureDictionary; -import org.icepdf.core.pobjects.acroform.SignatureFieldDictionary; -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.acroform.signature.exceptions.SignatureIntegrityException; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; -import org.icepdf.ri.common.utility.signatures.SignatureUtilities; -import org.icepdf.ri.images.Images; - -import javax.security.auth.x500.X500Principal; -import java.net.URL; -import java.security.cert.X509Certificate; -import java.text.MessageFormat; -import java.util.ResourceBundle; - -/** - * Common panel construct for show validation status of a given signature and validator. - */ -public class SignatureValidationStatus { - - private String validity; - private String singedBy; - private String documentModified; - private String certificateTrusted; - private String signatureTime; - private String emailAddress; - private String organization; - private String commonName; - private URL validityIconPath; - - private String dictionaryName; - private String dictionaryLocation; - private String dictionaryReason; - private String dictionaryContact; - private String dictionaryDate; - - public SignatureValidationStatus(ResourceBundle messageBundle, - SignatureWidgetAnnotation signatureWidgetAnnotation, SignatureValidator signatureValidator) { - - // build out the string that we need to display - validity = "viewer.annotation.signature.validation.common.invalid.label"; - if (!signatureValidator.isSignedDataModified() && signatureValidator.isCertificateChainTrusted()) { - validity = "viewer.annotation.signature.validation.common.unknown.label"; - } else if (!signatureValidator.isSignedDataModified() && !signatureValidator.isCertificateChainTrusted()) { - validity = "viewer.annotation.signature.validation.common.valid.label"; - } - validity = messageBundle.getString(validity); - - // signed by - singedBy = messageBundle.getString("viewer.annotation.signature.validation.common.notAvailable.label"); - try { - validateSignatureNode(signatureWidgetAnnotation, signatureValidator); - MessageFormat formatter = new MessageFormat(messageBundle.getString( - "viewer.annotation.signature.validation.common.signedBy.label")); - singedBy = formatter.format(new Object[]{(commonName != null ? commonName + " " : " "), - (emailAddress != null ? "<" + emailAddress + ">" : "")}); - } catch (SignatureIntegrityException e) { - e.printStackTrace(); - } - - // document modification - documentModified = "viewer.annotation.signature.validation.common.doc.modified.label"; - if (!signatureValidator.isSignedDataModified() && !signatureValidator.isDocumentDataModified()) { - documentModified = "viewer.annotation.signature.validation.common.doc.unmodified.label"; - } else if (!signatureValidator.isSignedDataModified() && signatureValidator.isDocumentDataModified() && signatureValidator.isSignaturesCoverDocumentLength()) { - documentModified = "viewer.annotation.signature.validation.common.doc.modified.label"; - } else if (!signatureValidator.isSignaturesCoverDocumentLength()) { - documentModified = "viewer.annotation.signature.validation.common.doc.major.label"; - } - documentModified = messageBundle.getString(documentModified); - - // trusted certification - certificateTrusted = "viewer.annotation.signature.validation.common.identity.unknown.label"; - if (signatureValidator.isCertificateChainTrusted()) { - if (signatureValidator.isRevocation()) { - certificateTrusted = "viewer.annotation.signature.validation.common.identity.unchecked.label"; - } else { - certificateTrusted = "viewer.annotation.signature.validation.common.identity.valid.label"; - } - } - certificateTrusted = messageBundle.getString(certificateTrusted); - - // signature time. - signatureTime = "viewer.annotation.signature.validation.common.time.local.label"; - if (signatureValidator.isSignerTimeValid()) { - signatureTime = "viewer.annotation.signature.validation.common.time.embedded.label"; - } - signatureTime = messageBundle.getString(signatureTime); - - validityIconPath = getLargeValidityIcon(signatureValidator); - - // signature dictionary common names. - SignatureDictionary signatureDictionary = signatureWidgetAnnotation.getSignatureDictionary(); - // grab some signer properties right from the annotations dictionary. - dictionaryName = signatureDictionary.getName(); - dictionaryLocation = signatureDictionary.getLocation(); - dictionaryReason = signatureDictionary.getReason(); - dictionaryContact = signatureDictionary.getContactInfo(); - dictionaryDate = signatureDictionary.getDate(); - } - - private void validateSignatureNode(SignatureWidgetAnnotation signatureWidgetAnnotation, SignatureValidator signatureValidator) - throws SignatureIntegrityException { - SignatureFieldDictionary fieldDictionary = signatureWidgetAnnotation.getFieldDictionary(); - - if (fieldDictionary != null) { - // try and parse out the signer info. - X509Certificate certificate = signatureValidator.getSignerCertificate(); - X500Principal principal = certificate.getIssuerX500Principal(); - X500Name x500name = new X500Name(principal.getName()); - if (x500name.getRDNs() != null) { - commonName = SignatureUtilities.parseRelativeDistinguishedName(x500name, BCStyle.CN); - organization = SignatureUtilities.parseRelativeDistinguishedName(x500name, BCStyle.O); - emailAddress = SignatureUtilities.parseRelativeDistinguishedName(x500name, BCStyle.EmailAddress); - } - } - } - - // set one of the three icon's to represent the validity status of the signature node. - protected URL getLargeValidityIcon(SignatureValidator signatureValidator) { - if (!signatureValidator.isSignedDataModified() && signatureValidator.isCertificateChainTrusted() - && signatureValidator.isSignaturesCoverDocumentLength()) { - return Images.get("signature_valid_lg.png"); - } else if (!signatureValidator.isSignedDataModified() && signatureValidator.isSignaturesCoverDocumentLength()) { - return Images.get("signature_caution_lg.png"); - } else { - return Images.get("signature_invalid_lg.png"); - } - } - - public URL getValidityIconPath() { - return validityIconPath; - } - - public String getValidity() { - return validity; - } - - public String getSingedBy() { - return singedBy; - } - - public String getDocumentModified() { - return documentModified; - } - - public String getCertificateTrusted() { - return certificateTrusted; - } - - public String getSignatureTime() { - return signatureTime; - } - - public String getEmailAddress() { - return emailAddress; - } - - public String getCommonName() { - return commonName; - } - - public String getOrganization() { - return organization; - } - - public String getDictionaryName() { - return dictionaryName; - } - - public String getDictionaryLocation() { - return dictionaryLocation; - } - - public String getDictionaryReason() { - return dictionaryReason; - } - - public String getDictionaryContact() { - return dictionaryContact; - } - - public String getDictionaryDate() { - return dictionaryDate; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignerInfoPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignerInfoPanel.java deleted file mode 100644 index 5e22cb613a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignerInfoPanel.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations.signatures; - -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; - -import javax.swing.*; -import javax.swing.border.EtchedBorder; -import javax.swing.border.TitledBorder; -import java.awt.*; -import java.util.ResourceBundle; - -/** - * Displays a summary info of the signer properties. - */ -public class SignerInfoPanel extends JPanel { - // layouts constraint - private GridBagConstraints constraints; - - - public SignerInfoPanel(SignatureValidationStatus signatureValidationStatus, ResourceBundle messageBundle, - SignatureWidgetAnnotation signatureWidgetAnnotation, SignatureValidator signatureValidator) { - - setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.LOWERED), - messageBundle.getString("viewer.annotation.signature.properties.dialog.signerInfo.title"), - TitledBorder.LEFT, - TitledBorder.DEFAULT_POSITION)); - - // put it all together. - setAlignmentY(JPanel.TOP_ALIGNMENT); - GridBagLayout layout = new GridBagLayout(); - setLayout(layout); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.CENTER; - constraints.insets = new Insets(5, 5, 5, 5); - - String validationMessage = "viewer.annotation.signature.properties.dialog.pathValidation.failure"; - if (signatureValidator.isCertificateChainTrusted()) { - validationMessage = "viewer.annotation.signature.properties.dialog.pathValidation.success"; - } - validationMessage = messageBundle.getString(validationMessage); - String revocationsMessage = "viewer.annotation.signature.properties.dialog.revocation.success"; - if (!signatureValidator.isCertificateChainTrusted() || signatureValidator.isRevocation()) { - revocationsMessage = "viewer.annotation.signature.properties.dialog.revocation.failure"; - } - revocationsMessage = messageBundle.getString(revocationsMessage); - String expiryMessage = null; - if (!signatureValidator.isCertificateDateValid()) { - expiryMessage = messageBundle.getString("viewer.annotation.signature.properties.dialog.certificateExpired.failure"); - } - constraints.anchor = GridBagConstraints.WEST; - addGB(new JLabel(validationMessage), 1, 0, 1, 1); - addGB(new JLabel(revocationsMessage), 1, 1, 1, 1); - if (!signatureValidator.isCertificateDateValid()) { - addGB(new JLabel(expiryMessage), 1, 2, 1, 1); - } - } - - /** - * Gridbag constructor helper - * - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan - * @param colSpan - */ - public void addGB(Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - this.add(component, constraints); - } - - public GridBagConstraints getConstraints() { - return constraints; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignerSummaryPanel.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignerSummaryPanel.java deleted file mode 100644 index 60b824b326..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/annotations/signatures/SignerSummaryPanel.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.annotations.signatures; - -import org.icepdf.core.pobjects.PDate; -import org.icepdf.core.pobjects.acroform.signature.SignatureValidator; -import org.icepdf.core.pobjects.annotations.SignatureWidgetAnnotation; - -import javax.swing.*; -import java.awt.*; -import java.text.MessageFormat; -import java.util.ResourceBundle; - -/** - * Simple panel that shows a summary of signature data. - */ -public class SignerSummaryPanel extends JPanel { - // layouts constraint - private GridBagConstraints constraints; - - public SignerSummaryPanel(SignatureValidationStatus signatureValidationStatus, ResourceBundle messageBundle, - SignatureWidgetAnnotation signatureWidgetAnnotation, SignatureValidator signatureValidator, - boolean showIcon) { - - String validity = signatureValidationStatus.getValidity(); - MessageFormat formatter = new MessageFormat(messageBundle.getString( - "viewer.annotation.signature.properties.dialog.signingTime.label")); - String signingDate = signatureValidationStatus.getDictionaryDate(); - signingDate = formatter.format(new Object[]{ - new PDate(signatureWidgetAnnotation.getLibrary().getSecurityManager(), signingDate).toString()}); - formatter.applyPattern(messageBundle.getString("viewer.annotation.signature.properties.dialog.reason.label")); - String reason = formatter.format(new Object[]{signatureValidationStatus.getDictionaryReason()}); - formatter.applyPattern(messageBundle.getString("viewer.annotation.signature.properties.dialog.location.label")); - String location = formatter.format(new Object[]{signatureValidationStatus.getDictionaryLocation()}); - - // get the respective image. - JLabel validityIconLabel = new JLabel(new ImageIcon(signatureValidationStatus.getValidityIconPath())); - - // put it all together. - setAlignmentY(JPanel.TOP_ALIGNMENT); - GridBagLayout layout = new GridBagLayout(); - setLayout(layout); - - constraints = new GridBagConstraints(); - constraints.fill = GridBagConstraints.NONE; - constraints.weightx = 1.0; - constraints.anchor = GridBagConstraints.NORTH; - constraints.anchor = GridBagConstraints.EAST; - constraints.insets = new Insets(5, 5, 5, 5); - if (showIcon) { - addGB(validityIconLabel, 0, 0, 1, 4); - } - - constraints.anchor = GridBagConstraints.WEST; - addGB(new JLabel(validity), 1, 0, 1, 1); - addGB(new JLabel(signingDate), 1, 1, 1, 1); - addGB(new JLabel(reason), 1, 2, 1, 1); - addGB(new JLabel(location), 1, 3, 1, 1); - ; - - } - - /** - * Gridbag constructor helper - * - * @param component component to add to grid - * @param x row - * @param y col - * @param rowSpan - * @param colSpan - */ - public void addGB(Component component, - int x, int y, - int rowSpan, int colSpan) { - constraints.gridx = x; - constraints.gridy = y; - constraints.gridwidth = rowSpan; - constraints.gridheight = colSpan; - this.add(component, constraints); - } - - public GridBagConstraints getConstraints() { - return constraints; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/listeners/DefaultPageViewLoadingListener.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/listeners/DefaultPageViewLoadingListener.java deleted file mode 100644 index 62581cb4f3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/listeners/DefaultPageViewLoadingListener.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.icepdf.ri.common.views.listeners; - -import org.icepdf.core.events.PageImageEvent; -import org.icepdf.core.events.PageInitializingEvent; -import org.icepdf.core.events.PageLoadingEvent; -import org.icepdf.core.events.PagePaintingEvent; -import org.icepdf.ri.common.views.DocumentViewController; - -import javax.swing.*; - -/** - * DefaultPageViewLoadingListener takes advantage of the PageLoadingListener - * interface to set the current page cursor to a wait symbol during page load. - * - * @since 5.1.0 - */ -public class DefaultPageViewLoadingListener extends PageViewLoadingListener { - - private JComponent pageComponent; - private DocumentViewController documentViewController; - - public DefaultPageViewLoadingListener(JComponent pageComponent, - DocumentViewController documentViewController) { - this.pageComponent = pageComponent; - this.documentViewController = documentViewController; - } - - public void setDocumentViewController(DocumentViewController documentViewController) { - this.documentViewController = documentViewController; - } - - public void pageLoadingStarted(PageLoadingEvent event) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - if (documentViewController != null) - pageComponent.setCursor(documentViewController.getViewCursor( - DocumentViewController.CURSOR_WAIT)); - } - }); - } - - public void pageInitializationStarted(PageInitializingEvent event) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - if (documentViewController != null) - pageComponent.setCursor(documentViewController.getViewCursor( - DocumentViewController.CURSOR_WAIT)); - } - }); - } - - public void pagePaintingStarted(PagePaintingEvent event) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - if (documentViewController != null) - pageComponent.setCursor(documentViewController.getViewCursor( - DocumentViewController.CURSOR_WAIT)); - } - }); - } - - @Override - public void pageInitializationEnded(PageInitializingEvent event) { - // null will make the parent view icon be the default. - - SwingUtilities.invokeLater(new Runnable() { - public void run() { - pageComponent.setCursor(null); - } - }); - } - - @Override - public void pageImageLoaded(PageImageEvent event) { - super.pageImageLoaded(event); - } - - @Override - public void pagePaintingEnded(PagePaintingEvent event) { - // null will make the parent view icon be the default. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - pageComponent.setCursor(null); - } - }); - } - - public void pageLoadingEnded(PageLoadingEvent event) { - // null will make the parent view icon be the default. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - pageComponent.setCursor(null); - } - }); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/listeners/MetricsPageLoadingListener.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/listeners/MetricsPageLoadingListener.java deleted file mode 100644 index 73143480bb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/listeners/MetricsPageLoadingListener.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.common.views.listeners; - -import org.icepdf.core.events.*; -import org.icepdf.core.pobjects.Page; - -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.Locale; -import java.util.logging.Logger; - -/** - * MetricsPageLoadingListener is an example of how the PageLoadingListener - * interface can be used to page loading metrics information. - * - * @since 5.1.0 - */ -public class MetricsPageLoadingListener implements PageLoadingListener { - - private static final Logger logger = - Logger.getLogger(MetricsPageLoadingListener.class.toString()); - - public static final DecimalFormat formatter = new DecimalFormat("#.###"); - public static final DecimalFormat percentFormatter = new DecimalFormat("#"); - private int pageIndex; - private int pageCount; - - private long startLoading; - private long endLoading; - - private long startInit; - private long endInit; - - private long imageCount; - private long imageLoadDuration; - - private long startPaint; - private long endPaint; - private long paintCount; - - public MetricsPageLoadingListener(int pageCount) { - this.pageCount = pageCount; - } - - public void pageLoadingStarted(PageLoadingEvent event) { - startLoading = System.nanoTime(); - pageIndex = ((Page) event.getSource()).getPageIndex(); - imageCount = event.getImageResourceCount(); - } - - public void pageInitializationStarted(PageInitializingEvent event) { - startInit = System.nanoTime(); - } - - public void pageInitializationEnded(PageInitializingEvent event) { - endInit = System.nanoTime(); - } - - public void pageImageLoaded(PageImageEvent event) { - imageLoadDuration += event.getDuration(); - } - - public void pagePaintingStarted(PagePaintingEvent event) { - startPaint = System.nanoTime(); - paintCount = event.getShapesCount(); - } - - public void pagePaintingEnded(PagePaintingEvent event) { - endPaint = System.nanoTime(); - } - - public void pageLoadingEnded(PageLoadingEvent event) { - endLoading = System.nanoTime(); - displayConsoleMetrics(); - } - - private void displayConsoleMetrics() { - System.out.println("Loading page: " + (pageIndex + 1) + "/" + pageCount); - double totalTime = convert(endLoading - startLoading); - double initTime = convert(endInit - startInit); - double paintTime = convert(endPaint - startPaint); - double imageTime = convert(imageLoadDuration); - System.out.println(" init time: " + formatter.format(initTime) + - "ms (" + percentFormatter.format((initTime / totalTime) * 100) + "%)"); - - System.out.println(" paint time: " + formatter.format(paintTime) + - "ms (" + percentFormatter.format((paintTime / totalTime) * 100) + "%) " + - paintCount + " shapes"); - System.out.println(" image time: " + formatter.format(imageTime) + "ms"); - System.out.println(" avg. image time: " + formatter.format(imageTime / imageCount) + "ms for " - + NumberFormat.getNumberInstance(Locale.US).format(imageCount) + " image(s)"); - System.out.println(" total time: " + formatter.format(totalTime)); - } - - private double convert(long duration) { - return duration / 1.0E09; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/listeners/PageViewLoadingListener.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/listeners/PageViewLoadingListener.java deleted file mode 100644 index b2791f5ec8..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/common/views/listeners/PageViewLoadingListener.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.icepdf.ri.common.views.listeners; - -import org.icepdf.core.events.PageLoadingAdapter; -import org.icepdf.ri.common.views.DocumentViewController; - -/** - * PageViewLoadingListener allows for multiple implementation of a - * PageViewLoading Listener. - * - * @since 5.1.0 - */ -public abstract class PageViewLoadingListener extends PageLoadingAdapter { - - /** - * Sets the ne document view controller set when a view type changes. - * - * @param documentViewController currently selected document view controller. - */ - public abstract void setDocumentViewController(DocumentViewController documentViewController); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/images/Images.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/images/Images.java deleted file mode 100644 index 13eb2034c4..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/images/Images.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.images; - -import java.net.URL; - -/** - *

      Utility class to allow easy access to image resources in the - * package com.icesoft.pdf.ri.images. - * Used as an accessor to the images. Just call:

      - *
        - * Images.get(".gif") - *
      - * - * @author Mark Collette - * @since 2.0 - */ -public class Images { - - public static final String SIZE_LARGE = "_32"; - public static final String SIZE_MEDIUM = "_24"; - public static final String SIZE_SMALL = "_16"; - - public static URL get(String name) { - return Images.class.getResource(name); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/BareBonesBrowserLaunch.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/BareBonesBrowserLaunch.java deleted file mode 100644 index ef79590c30..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/BareBonesBrowserLaunch.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - -import javax.swing.*; -import java.lang.reflect.Method; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Bare Bones Browser Launch for Java
      Utility class to open a web page from - * a Swing application in the user's default browser.
      Supports: Mac OS X, - * GNU/Linux, Unix, Windows XP
      Example Usage:
          String - * url = "http://www.google.com/";
          BareBonesBrowserLaunch.openURL(url);
      - * Latest Version: http://www.centerkey.com/java/browser
      - * Author: Dem Pilafian
      Public Domain Software -- Free to Use as You Like - * - * @version 1.5, December 10, 2005 - */ -public class BareBonesBrowserLaunch { - - private static final Logger logger = - Logger.getLogger(BareBonesBrowserLaunch.class.toString()); - private static final String errMsg = - "Error attempting to launch web browser"; - - public static final String FILE_PREFIX = "file://"; - - private static String os; - - static { - os = System.getProperty("os.name").toLowerCase(); - } - - /** - * Opens the specified web page in a web browser - * - * @param url An absolute URL of a web page (ex: "http://www.google.com/") - */ - public static void openURL(String url) { - try { - if (logger.isLoggable(Level.FINE)) { - logger.fine("Opening URL: " + url); - } - - if (isMac()) { - Class fileMgr = Class.forName("com.apple.eio.FileManager"); - Method openURL = fileMgr.getDeclaredMethod("openURL", - new Class[]{ - String.class}); - openURL.invoke(null, url); - } else if (isWindows()) - Runtime.getRuntime() - .exec("rundll32 url.dll,FileProtocolHandler " + url); - else if (isUnix()) { - String[] browsers = { - "firefox", "opera", "konqueror", "epiphany", "mozilla", - "netscape"}; - String browser = null; - for (int count = 0; count < browsers.length && browser == null; - count++) - if (Runtime.getRuntime().exec( - new String[]{"which", browsers[count]}).waitFor() == - 0) - browser = browsers[count]; - if (browser == null) - throw new Exception("Could not find web browser"); - else - Runtime.getRuntime().exec(new String[]{browser, url}); - } else { - JOptionPane.showMessageDialog(null, errMsg); - } - } catch (Exception e) { - JOptionPane.showMessageDialog(null, errMsg + ":\n" + - e.getLocalizedMessage()); - } - } - - - /** - * Opens the specified file path using the OS's preferred application binding - * - * @param filePath to open on host OS. - */ - public static void openFile(String filePath) { - openURL(FILE_PREFIX + filePath); - } - - public static boolean isWindows() { - //windows - return (os.contains("win")); - - } - - public static boolean isMac() { - //Mac - return (os.contains("mac")); - } - - public static boolean isUnix() { - //linux or unix - return (os.contains("nix") || os.contains("nux")); - } - - -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/FontPropertiesManager.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/FontPropertiesManager.java deleted file mode 100644 index 65133e63d1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/FontPropertiesManager.java +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - -import org.icepdf.core.pobjects.fonts.FontManager; - -import javax.swing.*; -import java.io.*; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - - -/** - *

      This class provides a very basic Font Properties Management system. When this - * class is initiated, the properites file "pdfviewerfontcache.properties" is - * read from the default application file path. If the file cannot be found then - * all system fonts are read from the operating system and are written to the - * "pdfviewerfontcache.properties" file.

      - *

      - *

      This class is designed to speed up the load time of the viewer application - * by reading already parsed font information from the properties file. If new - * fonts are added to the system, the "pdfviewerfontcache.properties" file can - * be deleted to trigger this class to re-read the System fonts and re-create - * a new "pdfviewerfontcache.properties" properites file. - * - * // read/store the font cache. - * ResourceBundle messageBundle = ResourceBundle.getBundle( - * PropertiesManager.DEFAULT_MESSAGE_BUNDLE); - * PropertiesManager properties = new PropertiesManager(System.getProperties(), - * ResourceBundle.getBundle(PropertiesManager.DEFAULT_MESSAGE_BUNDLE)); - * new FontPropertiesManager(properties, System.getProperties(), messageBundle); - * - * @since 2.0 - */ -public class FontPropertiesManager { - - private static final Logger logger = - Logger.getLogger(FontPropertiesManager.class.toString()); - - private static final String DEFAULT_HOME_DIR = ".icesoft/icepdf_viewer"; - private static final String LOCK_FILE = "_syslock"; - private final static String USER_FILENAME = "pdfviewerfontcache.properties"; - - // format version number - private final static String FORMAT_VERSION = "6.0"; - - private FontManager fontManager; - - private Properties sysProps; - private PropertiesManager props; - - private File userHome; - - //the swingri home directory - private File dataDir; - - //not to save the bookmarks and properties if lockDir == null, that is - //when we do not own the lock - private File lockDir; - - private File propertyFile; - - private ResourceBundle messageBundle; - - /** - * Create a new instance of the FontPropertiesManager class. This constructor will - * automatically scan the system for the available fonts. - *

      - * Typical usage would look like this:
      - *

        - * // read/store the font cache. - * ResourceBundle messageBundle = ResourceBundle.getBundle( - * PropertiesManager.DEFAULT_MESSAGE_BUNDLE); - * PropertiesManager properties = new PropertiesManager(System.getProperties(), - * ResourceBundle.getBundle(PropertiesManager.DEFAULT_MESSAGE_BUNDLE)); - *

        - * // creates a new cache properties file, does not read system fonts. - * FontPropertiesManager fontPropertiesManager = - * new FontPropertiesManager(properties, System.getProperties(), messageBundle, false); - *

      - * - * @param appProps properties manager reference - * @param sysProps system properties. - * @param messageBundle application message bundle. - */ - public FontPropertiesManager(PropertiesManager appProps, Properties sysProps, - ResourceBundle messageBundle) { - this.sysProps = sysProps; - this.props = appProps; - this.messageBundle = messageBundle; - // create a new Font Manager. - this.fontManager = FontManager.getInstance(); - - setupHomeDir(null); - - recordMofifTime(); - - setupLock(); - // create the properties file and scan for font sif the - propertyFile = new File(dataDir, USER_FILENAME); - if (!propertyFile.exists()) { - // scan the system for know font locations. - readDefaulFontPaths(null); - // save the file - saveProperties(); - }else{ - loadProperties(); - } - - } - - /** - * Create a new instance of the FontPropertiesManager class. This constructor will not scan - * the system for fonts. The users must call one of the following methods to scan for fonts; - * {@link #readFontPaths} or {@link #readDefaulFontPaths(String[])} - * - *

      - * Typical usage would look like this:
      - *

        - * // read/store the font cache. - * ResourceBundle messageBundle = ResourceBundle.getBundle( - * PropertiesManager.DEFAULT_MESSAGE_BUNDLE); - * PropertiesManager properties = new PropertiesManager(System.getProperties(), - * ResourceBundle.getBundle(PropertiesManager.DEFAULT_MESSAGE_BUNDLE)); - *

        - * // creates a new cache properties file, does not read system fonts. - * FontPropertiesManager fontPropertiesManager = new FontPropertiesManager(properties, messageBundle, false); - * fontPropertiesManager.readFontPaths(null); - *

      - * - * @param appProps properties manager reference - * @param messageBundle application message bundle. - */ - public FontPropertiesManager(PropertiesManager appProps, ResourceBundle messageBundle) { - this.sysProps = appProps.getSystemProperties(); - this.props = appProps; - this.messageBundle = messageBundle; - // create a new Font Manager. - this.fontManager = FontManager.getInstance(); - - setupHomeDir(null); - - recordMofifTime(); - - setupLock(); - // create the properties file - if (ownLock()) { - propertyFile = new File(dataDir, USER_FILENAME); - } - } - - /** - * Removes the the properties file from the file system. - */ - public synchronized void removeFontCacheFile() { - if (ownLock()) { - propertyFile = new File(dataDir, USER_FILENAME); - // load font properties from last invocation - boolean deleted = false; - if (propertyFile.exists()) { - try { - deleted = propertyFile.delete(); - } catch (SecurityException ex) { - // log the error - if (!deleted && logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error removing font properties file.", ex); - } - } - } - } - } - - /** - * Clears any font references from the font managers internal cache. - */ - public synchronized void clearProperties() { - fontManager.clearFontList(); - } - - /** - * Loads the properties file and loads any font data that it contains. If no font - * cache file is found then a new one is created and false is returned. If a file - * is found the properties in it are loaded and added to the fontManager class, true is - * returned. - * - * @return true if font file has been found and loaded, false otherwise. - */ - public synchronized boolean loadProperties() { - - if (ownLock()) { - // load font properties from last invocation - if (propertyFile != null && propertyFile.exists()) { - try { - InputStream in = new FileInputStream(propertyFile); - try { - Properties fontProps = fontManager.getFontProperties(); - fontProps.load(in); - fontManager.setFontProperties(fontProps); - } finally { - in.close(); - } - } catch (IOException ex) { - // check to make sure the storage relate dialogs can be shown - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "fontManager.properties.title", - "manager.properties.session.readError", - ex); - } - // log the error - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error loading font properties cache", ex); - } - return false; - } catch (IllegalArgumentException e) { - return false; - } - return true; - } - // If no font data, then read font data and save the new file. - else { - return false; - } - } else { - return false; - } - } - - /** - * Reads the specified file paths and loads any found font fonts in the font Manager. - * In order to persist the results a call to {@link #saveProperties()} needs to be called. - * - * @param fontPaths array of paths containing folders - */ - public void readFontPaths(String[] fontPaths) { - // create program properties with default - try { - // If you application needs to look at other font directories - // they can be added via the readSystemFonts method. - fontManager.readFonts(fontPaths); - } catch (Exception ex) { - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error reading system paths:", ex); - } - } - } - - /** - * Touches the properties file, writing out any font properties. - */ - public synchronized void saveProperties() { - if (ownLock()) { - try { - FileOutputStream out = new FileOutputStream(propertyFile); - try { - Properties fontProps = fontManager.getFontProperties(); - fontProps.store(out, "-- ICEpdf Font properties --\n " + FORMAT_VERSION); - } finally { - out.close(); - } - recordMofifTime(); - } catch (IOException ex) { - // check to make sure the storage relate dialogs can be shown - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "fontManager.properties.title", - "manager.properties.saveError", ex); - } - // log the error - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error saving font properties cache", ex); - } - } - } - } - - private boolean ownLock() { - return lockDir != null; - } - - private void recordMofifTime() { - Calendar c = new GregorianCalendar(); - c.setTime(new Date()); - c.set(Calendar.MINUTE, c.get(Calendar.MINUTE) + 1); - c.set(Calendar.SECOND, 0); - } - - private void setupLock() { - if (dataDir == null) { - lockDir = null; - } else { - File dir = new File(dataDir, LOCK_FILE); - if (!dir.mkdir()) { - - dir.delete(); - if (!dir.mkdir()) { - dir = null; - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "fontManager.properties.title", - "manager.properties.session.nolock", LOCK_FILE); - } - } - - } - lockDir = dir; - } - } - - /** - * Sets the default font properties files by readying available system font paths. - * - * @param extraFontPaths extra font paths to load on top of the default paths. - * @return true if system font search returned without error, otherwise false. - */ - public boolean readDefaulFontPaths(String[] extraFontPaths) { - // create program properties with default - try { - // If you application needs to look at other font directories - // they can be added via the readSystemFonts method. - fontManager.readSystemFonts(extraFontPaths); - } catch (Exception ex) { - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "fontManager.properties.title", - "manager.properties.session.readError", - ex); - }// log the error - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error loading default properties", ex); - } - return false; - } - return true; - } - - private void setupHomeDir(String homeString) { - if (homeString == null) { - homeString = sysProps.getProperty("swingri.home"); - } - - if (homeString != null) { - dataDir = new File(homeString); - } else { - userHome = new File(sysProps.getProperty("user.home")); - String dataDirStr = props.getString("application.datadir", DEFAULT_HOME_DIR); - dataDir = new File(userHome, dataDirStr); - } - - if (!dataDir.isDirectory()) { - String path = dataDir.getAbsolutePath(); - boolean create; - if (props.hasUserRejectedCreatingLocalDataDir()) { - create = false; - } else if (getBoolean("application.showLocalStorageDialogs", true)) { - create = Resources.showConfirmDialog(null, - messageBundle, "fontManager.properties.title", - "manager.properties.createNewDirectory", path); - if (!create) - props.setUserRejectedCreatingLocalDataDir(); - } else { - // Always create local-storage directory if show user prompt dialog setting is false. - create = true; - } - - if (!create) { - dataDir = null; - } else { - dataDir.mkdirs(); - if (!dataDir.isDirectory()) { - // check to make sure that dialog should be shown on the error. - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "fontManager.properties.title", - "manager.properties.failedCreation", - dataDir.getAbsolutePath()); - } - dataDir = null; - } - } - } - } - - public boolean getBoolean(String propertyName, boolean defaultValue) { - Boolean result = getBooleanImpl(propertyName); - if (result == null) { - return defaultValue; - } - return result == Boolean.TRUE; - } - - private Boolean getBooleanImpl(String propertyName) { - String value = props.getString(propertyName); - if (value != null) { - Boolean result = Parse.parseBoolean(value, messageBundle); - if (result != null) { - return result; - } - props.remove(propertyName); - } - value = props.getString(propertyName); - if (value != null) { - Boolean result = Parse.parseBoolean(value, null); - if (result != null) { - return result; - } - throwBrokenDefault(propertyName, value); - } - return null; - } - - private void throwBrokenDefault(String propertyName, String value) { - throw new IllegalStateException("Broken default property '" + propertyName + "' value: '" + value + "'"); - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/Parse.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/Parse.java deleted file mode 100644 index 8690f8cd4d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/Parse.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - -import javax.swing.*; -import java.util.ResourceBundle; - - -/** - * Utility class for parsing Strings to alternative types. Errors are represented - * with internationalized dialogs and corresponding error messages. - * - * @since 1.0 - */ -final class Parse { - - private final static String[] booleanNames = {"yes", "no", "true", "false"}; - private final static boolean[] booleans = {true, false, true, false}; - - public static Integer parseInteger(String s, ResourceBundle messageBundle) { - s = s.trim(); - try { - return new Integer(s); - } catch (NumberFormatException ex) { - if (messageBundle != null) { - Resources.showMessageDialog(null, - JOptionPane.INFORMATION_MESSAGE, messageBundle, - "parse.title", - "parse.integer", - s); - } - } - return null; - } - - public static Long parseLong(String s, ResourceBundle messageBundle) { - s = s.trim(); - try { - return new Long(s); - } catch (NumberFormatException ex) { - if (messageBundle != null) { - Resources.showMessageDialog(null, - JOptionPane.INFORMATION_MESSAGE, messageBundle, - "parse.title", - "parse.float", - s); - } - } - return null; - } - - public static Float parseFloat(String s, ResourceBundle messageBundle) { - s = s.trim(); - try { - return new Float(s); - } catch (NumberFormatException ex) { - if (messageBundle != null) { - Resources.showMessageDialog(null, - JOptionPane.INFORMATION_MESSAGE, messageBundle, - "parse.title", - "parse.float", - s); - } - } - return null; - } - - /** - * Parse a string into a double number. Error is added to errorShower. - * - * @param s string to be coverted to double if possible - * @return a null if the string could not be converted to double, otherwise - * return the Double value of the string. - */ - public static Double parseDouble(String s, ResourceBundle messageBundle) { - s = s.trim(); - try { - return new Double(s); - } catch (NumberFormatException ex) { - if (messageBundle != null) { - Resources.showMessageDialog(null, - JOptionPane.INFORMATION_MESSAGE, messageBundle, - "parse.title", - "parse.double", - s); - } - } - return null; - } - - public static Boolean parseBoolean(String s, ResourceBundle messageBundle) { - s = s.trim(); - for (int i = 0; i < booleanNames.length; i++) { - if (s.equalsIgnoreCase(booleanNames[i])) { - return booleans[i] ? Boolean.TRUE : Boolean.FALSE; - } - } - if (messageBundle != null) { - Resources.showMessageDialog(null, - JOptionPane.INFORMATION_MESSAGE, messageBundle, - "parse.title", - "parse.choice", - s); - } - return null; - } - - public static String parseLookAndFeel(String s, ResourceBundle messageBundle) { - s = s.trim(); - UIManager.LookAndFeelInfo[] looks = UIManager.getInstalledLookAndFeels(); - for (UIManager.LookAndFeelInfo look : looks) { - if (s.equalsIgnoreCase(look.getName())) { - return look.getClassName(); - } - } - if (messageBundle != null) { - Resources.showMessageDialog(null, - JOptionPane.INFORMATION_MESSAGE, messageBundle, - "parse.title", - "parse.laf", - s); - } - return null; - } - -} - - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/PropertiesManager.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/PropertiesManager.java deleted file mode 100644 index 7f06a65a70..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/PropertiesManager.java +++ /dev/null @@ -1,1046 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - -import org.icepdf.core.pobjects.Document; - -import javax.swing.*; -import java.io.*; -import java.net.URL; -import java.util.*; -import java.util.logging.Level; -import java.util.logging.Logger; - - -/** - *

      This class provides a very basic Properties Management system for the - * viewer application. Settings such as window location and temporary file - * information is managed by this class.

      - * - * @since 1.0 - */ -public class PropertiesManager { - - private static final Logger logger = - Logger.getLogger(PropertiesManager.class.toString()); - - private static final String DEFAULT_HOME_DIR = ".icesoft/icepdf_viewer"; - private static final String LOCK_FILE = "_syslock"; - private final static String USER_FILENAME = "pdfviewerri.properties"; - private final static String BACKUP_FILENAME = "old_pdfviewerri.properties"; - - //default file for all not specified properties - private static final String DEFAULT_PROP_FILE = "ICEpdfDefault.properties"; - private static final String DEFAULT_PROP_FILE_PATH = "org/icepdf/ri/viewer/res/"; - public static final String DEFAULT_MESSAGE_BUNDLE = "org.icepdf.ri.resources.MessageBundle"; - - private static final String PROPERTY_DEFAULT_FILE_PATH = "application.defaultFilePath"; - private static final String PROPERTY_DEFAULT_URL = "application.defaultURL"; - - // window properties - public static final String PROPERTY_DIVIDER_LOCATION = "application.divider.location"; - // default page fit mode - public static final String PROPERTY_DEFAULT_PAGEFIT = "document.pagefitMode"; - // default print media size. - public static final String PROPERTY_PRINT_MEDIA_SIZE_WIDTH = "document.print.mediaSize.width"; - public static final String PROPERTY_PRINT_MEDIA_SIZE_HEIGHT = "document.print.mediaSize.height"; - public static final String PROPERTY_PRINT_MEDIA_SIZE_UNIT = "document.print.mediaSize.unit"; - // system properties - public static final String SYSPROPERTY_HIGHLIGHT_COLOR = "org.icepdf.core.views.page.text.highlightColor"; - // properties used to hide/show toolbars - public static final String PROPERTY_SHOW_TOOLBAR_UTILITY = "application.toolbar.show.utility"; - public static final String PROPERTY_SHOW_TOOLBAR_PAGENAV = "application.toolbar.show.pagenav"; - public static final String PROPERTY_SHOW_TOOLBAR_ZOOM = "application.toolbar.show.zoom"; - public static final String PROPERTY_SHOW_TOOLBAR_FIT = "application.toolbar.show.fit"; - public static final String PROPERTY_SHOW_TOOLBAR_ROTATE = "application.toolbar.show.rotate"; - public static final String PROPERTY_SHOW_TOOLBAR_TOOL = "application.toolbar.show.tool"; - public static final String PROPERTY_SHOW_TOOLBAR_ANNOTATION = "application.toolbar.show.annotation"; - public static final String PROPERTY_SHOW_TOOLBAR_FORMS = "application.toolbar.show.forms"; - // properties used to hide/show status bar buttons - public static final String PROPERTY_SHOW_STATUSBAR = "application.statusbar"; - // properties used to hide/show status bar status label - public static final String PROPERTY_SHOW_STATUSBAR_STATUSLABEL = "application.statusbar.show.statuslabel"; - // properties used to hide/show status bar buttons - public static final String PROPERTY_SHOW_STATUSBAR_VIEWMODE = "application.statusbar.show.viewmode"; - public static final String PROPERTY_SHOW_STATUSBAR_VIEWMODE_SINGLE = "application.statusbar.show.viewmode.singlePage"; - public static final String PROPERTY_SHOW_STATUSBAR_VIEWMODE_SINGLE_CONTINUOUS = "application.statusbar.show.viewmode.singlePageContinuous"; - public static final String PROPERTY_SHOW_STATUSBAR_VIEWMODE_DOUBLE = "application.statusbar.show.viewmode.doublePage"; - public static final String PROPERTY_SHOW_STATUSBAR_VIEWMODE_DOUBLE_CONTINUOUS = "application.statusbar.show.viewmode.doublePageContinuous"; - // properties used to hide/show the utility buttons (open, print, etc.) - public static final String PROPERTY_SHOW_UTILITY_OPEN = "application.toolbar.show.utility.open"; - public static final String PROPERTY_SHOW_UTILITY_SAVE = "application.toolbar.show.utility.save"; - public static final String PROPERTY_SHOW_UTILITY_PRINT = "application.toolbar.show.utility.print"; - public static final String PROPERTY_SHOW_UTILITY_SEARCH = "application.toolbar.show.utility.search"; - public static final String PROPERTY_SHOW_UTILITY_UPANE = "application.toolbar.show.utility.upane"; - // properties used to hide/show utility pane tabs - public static final String PROPERTY_HIDE_UTILITYPANE = "application.utilitypane.hide"; - public static final String PROPERTY_SHOW_UTILITYPANE_BOOKMARKS = "application.utilitypane.show.bookmarks"; - public static final String PROPERTY_SHOW_UTILITYPANE_ATTACHMENTS = "application.utilitypane.show.attachments"; - public static final String PROPERTY_SHOW_UTILITYPANE_SEARCH = "application.utilitypane.show.search"; - public static final String PROPERTY_SHOW_UTILITYPANE_THUMBNAILS = "application.utilitypane.show.thumbs"; - public static final String PROPERTY_SHOW_UTILITYPANE_LAYERS = "application.utilitypane.show.layers"; - public static final String PROPERTY_SHOW_UTILITYPANE_ANNOTATION = "application.utilitypane.show.annotation"; - public static final String PROPERTY_SHOW_UTILITYPANE_ANNOTATION_FLAGS = "application.utilitypane.show.annotation.flags"; - public static final String PROPERTY_SHOW_UTILITYPANE_SIGNATURES = "application.utilitypane.show.signatures"; - // default utility pane thumbnail zoom size for non-embedded files - public static final String PROPERTY_UTILITYPANE_THUMBNAILS_ZOOM = "application.utilitypane.thumbnail.zoom"; - // properties used for default zoom levels - public static final String PROPERTY_DEFAULT_ZOOM_LEVEL = "application.zoom.factor.default"; - public static final String PROPERTY_ZOOM_RANGES = "application.zoom.range.default"; - // property to hide/show menu keyboard accelerator shortcuts - public static final String PROPERTY_SHOW_KEYBOARD_SHORTCUTS = "application.menuitem.show.keyboard.shortcuts"; - // properties used for overriding ViewerPreferences pulled from the document - public static final String PROPERTY_VIEWPREF_HIDETOOLBAR = "application.viewerpreferences.hidetoolbar"; - public static final String PROPERTY_VIEWPREF_HIDEMENUBAR = "application.viewerpreferences.hidemenubar"; - public static final String PROPERTY_VIEWPREF_FITWINDOW = "application.viewerpreferences.fitwindow"; - public static final String PROPERTY_VIEWPREF_FORM_HIGHLIGHT = "application.viewerpreferences.form.highlight"; - - // properties used to control visibility of annotation controls on main utility panel. - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_HIGHLIGHT = "application.toolbar.annotation.show.highlight"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_UNDERLINE = "application.toolbar.annotation.show.underline"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_STRIKE_OUT = "application.toolbar.annotation.show.strikeOut"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_LINE = "application.toolbar.annotation.show.line"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_LINK = "application.toolbar.annotation.show.link"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_ARROW = "application.toolbar.annotation.show.arrow"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_RECTANGLE = "application.toolbar.annotation.show.rectangle"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_CIRCLE = "application.toolbar.annotation.show.circle"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_INK = "application.toolbar.annotation.show.ink"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_FREE_TEXT = "application.toolbar.annotation.show.freeText"; - public static final String PROPERTY_SHOW_UTILITY_ANNOTATION_TEXT = "application.toolbar.annotation.show.text"; - // Individual controls for the annotation toolbar button commands - public static final String PROPERTY_SHOW_TOOLBAR_ANNOTATION_SELECTION = "application.toolbar.show.annotation.selection"; - public static final String PROPERTY_SHOW_TOOLBAR_ANNOTATION_HIGHLIGHT = "application.toolbar.show.annotation.highlight"; - public static final String PROPERTY_SHOW_TOOLBAR_ANNOTATION_TEXT = "application.toolbar.show.annotation.text"; - // Individual control of the markup annotation context menu - public static final String PROPERTY_SHOW_ANNOTATION_MARKUP_REPLY_TO = "application.annotation.show.markup.replyTo"; - public static final String PROPERTY_SHOW_ANNOTATION_MARKUP_SET_STATUS = "application.annotation.show.markup.setStatus"; - - //the version name, used in about dialog and start-up message - String versionName = Document.getLibraryVersion(); - - private boolean unrecoverableError; - - Properties sysProps; - - private ResourceBundle messageBundle; - - File userHome; - - //the swingri home directory - private File dataDir; - - //not to save the bookmarks and properties if lockDir == null, that is - //when we do not own the lock - private File lockDir; - - private File propertyFile; - private Date myLastModif = new Date(); - - private Properties props; - private Properties defaultProps; - - private boolean userRejectedCreatingLocalDataDir; - private boolean thisExecutionTriedCreatingLocalDataDir; - - public PropertiesManager(Properties sysProps, ResourceBundle messageBundle) { - this(sysProps, new Properties(), messageBundle); - } - - /** - * New instance of properties manager with properties overrides defined - * in props. - * - * @param sysProps system properties - * @param props Properties object containing properties that will be applied - * over the default properties have been setup. - * @param messageBundle message bundle for i8n that allows dialogs in this - * class to correct display the associated language - */ - public PropertiesManager(Properties sysProps, Properties props, ResourceBundle messageBundle) { - unrecoverableError = true; - this.sysProps = sysProps; - - this.messageBundle = messageBundle; - - // load default properties from viewer jar and assigned to defaultProps. - if (!setupDefaultProperties()) { - return; - } - - // copy over any properties defined in props. - if (props != null) { - Enumeration keys = props.keys(); - String key; - while (keys.hasMoreElements()) { - key = (String) keys.nextElement(); - this.props.setProperty(key, props.getProperty(key)); - } - } - - // create default home directory - setupHomeDir(null); - - // load persisted properties saved in users home directory. - loadProperties(); - - recordMofifTime(); - - setupLock(); - - unrecoverableError = false; - - } - - /** - * New instance of properties manager with properties overrides defined - * in an external file defined by propPath. - * - * @param sysProps system properties - * @param propPath Properties file containing properties that will be applied - * over the default properties have been setup. - * @param messageBundle message bundle for i8n that allows dialogs in this - * class to correct display the associated language - */ - public PropertiesManager(Properties sysProps, String propPath, ResourceBundle messageBundle) { - unrecoverableError = true; - this.sysProps = sysProps; - - this.messageBundle = messageBundle; - - if (!setupDefaultProperties()) { - return; - } - - // Set and load the property file if we have one - if (propPath != null) { - propertyFile = new File(propPath); - loadProperties(); - } - - setupHomeDir(null); - - recordMofifTime(); - - setupLock(); - - // Ensure at least the default properties get loaded if we haven't already - if (propPath == null) { - loadProperties(); - } - - unrecoverableError = false; - } - - public Properties getSystemProperties() { - return sysProps; - } - - private boolean setupDefaultProperties() { - defaultProps = new Properties(); - - // create program properties with default - try { - - InputStream in = getResourceAsStream(DEFAULT_PROP_FILE_PATH, DEFAULT_PROP_FILE); - try { - defaultProps.load(in); - } finally { - in.close(); - } - } catch (IOException ex) { - // check to make sure the storage relate dialogs can be shown - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.session.readError", - DEFAULT_PROP_FILE); - } - // log the error - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error loading default properties cache", ex); - } - return false; - } - - props = defaultProps; - return true; - } - - boolean hasUserRejectedCreatingLocalDataDir() { - return userRejectedCreatingLocalDataDir; - } - - void setUserRejectedCreatingLocalDataDir() { - userRejectedCreatingLocalDataDir = true; - } - - boolean unrecoverableError() { - return unrecoverableError; - } - - private boolean ownLock() { - return lockDir != null; - } - - private void setupHomeDir(String homeString) { - if (homeString == null) { - homeString = sysProps.getProperty("swingri.home"); - } - - if (homeString != null) { - dataDir = new File(homeString); - } else { - userHome = new File(sysProps.getProperty("user.home")); - String dataDirStr = props.getProperty("application.datadir", DEFAULT_HOME_DIR); - dataDir = new File(userHome, dataDirStr); - } - - if (!dataDir.isDirectory()) { - String path = dataDir.getAbsolutePath(); - boolean create; - if (hasUserRejectedCreatingLocalDataDir()) { - create = false; - } else if ((getBoolean("application.showLocalStorageDialogs", true))) { - create = Resources.showConfirmDialog(null, - messageBundle, "manager.properties.title", - "manager.properties.createNewDirectory", path); - if (!create) - setUserRejectedCreatingLocalDataDir(); - } else { - // Always create local-storage directory if show user prompt dialog setting is false. - create = true; - } - - if (!create) { - dataDir = null; - } else { - dataDir.mkdirs(); - if (!dataDir.isDirectory()) { - // check to make sure that dialog should be shown on the error. - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.failedCreation", - dataDir.getAbsolutePath()); - } - dataDir = null; - } - thisExecutionTriedCreatingLocalDataDir = true; - } - } - } - - private void setupLock() { - if (dataDir == null) { - lockDir = null; - } else { - File dir = new File(dataDir, LOCK_FILE); - if (!dir.mkdir()) { - // Removed dialog window, always assume we can remove another lock - 12/04/2003 - kfyten - // boolean removeIt = res.displayYesOrNo("session.anotherlock", session_date); - - dir.delete(); - if (!dir.mkdir()) { - dir = null; - // check to make sure that dialog should be shown on the error. - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.session.nolock", LOCK_FILE); - } - } - - } - lockDir = dir; - } - } - - private boolean checkPropertyFileValid(File toCheck) { - return ((toCheck != null) && (toCheck.exists()) && (toCheck.canRead())); - } - - public synchronized void loadProperties() { - // Check if we already have a properties file - // This can happen if we had one specified by a command line switch - // Otherwise default to the default directory - if (!checkPropertyFileValid(propertyFile)) { - if (dataDir != null) { - propertyFile = new File(dataDir, USER_FILENAME); - } - } - - // load properties from last invocation - if (checkPropertyFileValid(propertyFile)) { - try { - InputStream in = new FileInputStream(propertyFile); - try { - props.load(in); - } finally { - in.close(); - } - } catch (IOException ex) { - // check to make sure the storage relate dialogs can be shown - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.session.readError", propertyFile.getAbsolutePath()); - } - // log the error - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error loading properties cache", ex); - } - } - } - } - - public synchronized void saveAndEnd() { - if (dataDir != null) { - saveProperties(); - lockDir.delete(); - } - } - - public synchronized void saveProperties() { - if (ownLock()) { - - long lastModified = propertyFile.lastModified(); - boolean saveIt = true; - - if (thisExecutionTriedCreatingLocalDataDir) { - saveIt = true; - } else if (getBoolean("application.showLocalStorageDialogs", true)) { - if (lastModified == 0L) {//file does not exist - saveIt = Resources.showConfirmDialog(null, - messageBundle, - "manager.properties.title", - "manager.properties.deleted", propertyFile.getAbsolutePath()); - } else if (myLastModif.before(new Date(lastModified))) { - saveIt = Resources.showConfirmDialog(null, - messageBundle, - "manager.properties.title", - "manager.properties.modified", myLastModif); - } - } - - if (!saveIt) { - return; - } - - try { - FileOutputStream out = new FileOutputStream(propertyFile); - try { - props.store(out, "-- ICEpdf properties --"); - } finally { - out.close(); - } - recordMofifTime(); - } catch (IOException ex) { - // check to make sure the storage relate dialogs can be shown - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.saveError", ex); - } - // log the error - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error saving properties cache", ex); - } - } - } - } - - private void recordMofifTime() { - Calendar c = new GregorianCalendar(); - c.setTime(new Date()); - c.set(Calendar.MINUTE, c.get(Calendar.MINUTE) + 1); - c.set(Calendar.SECOND, 0); - myLastModif = new Date((c.getTime().getTime() / 1000) * 1000); - } - - public boolean backupProperties() { - boolean result = false; - if (ownLock()) { - File backupFile = new File(dataDir, BACKUP_FILENAME); - try { - FileOutputStream out = new FileOutputStream(backupFile); - try { - props.store(out, "-- ICEbrowser properties backup --"); - result = true; - } finally { - out.close(); - } - } catch (IOException ex) { - // check to make sure the storage relate dialogs can be shown - if (getBoolean("application.showLocalStorageDialogs", true)) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.saveError", ex); - } - // log the error - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Error saving properties cache", ex); - } - } - } - return result; - } - - public void set(String propertyName, String value) { - props.put(propertyName, value); - } - - public void remove(String propertyName) { - props.remove(propertyName); - } - - public String getString(String propertyName, String defaultValue) { - String value = (String) props.get(propertyName); - if (value != null) { - return value.trim(); - } - value = (String) defaultProps.get(propertyName); - if (value != null) { - return value.trim(); - } - return defaultValue; - } - - public String getString(String propertyName) { - String value = getString(propertyName, null); - if (value == null) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.missingProperty", propertyName, value); - } - return value; - } - - public int getInt(String propertyName, int defaultValue) { - Integer result = getIntImpl(propertyName); - if (result == null) { - return defaultValue; - } - return result.intValue(); - } - - public int getInt(String propertyName) { - Integer result = getIntImpl(propertyName); - if (result == null) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.missingProperty", propertyName, result); - return 0; - } - return result.intValue(); - } - - private Integer getIntImpl(String propertyName) { - String value = (String) props.get(propertyName); - if (value != null) { - Integer result = Parse.parseInteger(value, messageBundle); - if (result != null) { - return result; - } - props.remove(propertyName); - } - value = (String) defaultProps.get(propertyName); - if (value != null) { - Integer result = Parse.parseInteger(value, null); - if (result != null) { - return result; - } - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.brokenProperty ", propertyName, value); - } - return null; - } - - public void setInt(String propertyName, int value) { - set(propertyName, Integer.toString(value)); - } - - /** - * Return a double value for the respective propertyName. - * If there is no propertyName then return the - * defaultValue. - * - * @param propertyName Name of property from the ICEdefault.properties file. - * @param defaultValue default value if the propertyNamecan not be found. - * @return double value of the propertyName. - * @since 6.0 - */ - public double getDouble(String propertyName, double defaultValue) { - Double result = getDoubleImpl(propertyName); - if (result == null) { - return defaultValue; - } - return result.doubleValue(); - } - - /** - * Return a double value for the respective propertyName. - * - * @param propertyName Name of property from the ICEdefault.properties file. - * @return double value of the propertyName - * @since 6.0 - */ - public double getDouble(String propertyName) { - Double result = getDoubleImpl(propertyName); - if (result == null) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.missingProperty", propertyName, result); - return 0; - } - return result.doubleValue(); - } - - /** - * Return a float value for the respective propertyName. - * - * @param propertyName Name of property from the ICEdefault.properties file. - * @return double value of the propertyName - * @since 6.0 - */ - public float getFloat(String propertyName) { - Float result = getFloatImpl(propertyName); - if (result == null) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.missingProperty", propertyName, result); - return 0; - } - return result.floatValue(); - } - - /** - * Return the a double value for the respective propertyName. - * If the property value is null then the propertyName is removed - * from the properties object. - * - * @param propertyName Name of propertie from the ICEdefault.properites file. - * @return double value of the propertyName - * @since 6.0 - */ - private Double getDoubleImpl(String propertyName) { - String value = (String) props.get(propertyName); - if (value != null) { - Double result = Parse.parseDouble(value, messageBundle); - if (result != null) { - return result; - } - props.remove(propertyName); - } - value = (String) defaultProps.get(propertyName); - if (value != null) { - Double result = Parse.parseDouble(value, messageBundle); - if (result != null) { - return result; - } - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.brokenProperty ", propertyName, value); - } - return null; - } - - /** - * Return the a double value for the respective propertyName. - * If the property value is null then the propertyName is removed - * from the properties object. - * - * @param propertyName Name of propertie from the ICEdefault.properites file. - * @return double value of the propertyName - * @since 6.0 - */ - private Float getFloatImpl(String propertyName) { - String value = (String) props.get(propertyName); - if (value != null) { - Float result = Parse.parseFloat(value, messageBundle); - if (result != null) { - return result; - } - props.remove(propertyName); - } - value = (String) defaultProps.get(propertyName); - if (value != null) { - Float result = Parse.parseFloat(value, messageBundle); - if (result != null) { - return result; - } - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.brokenProperty ", propertyName, value); - } - return null; - } - - public void setDouble(String propertyName, double value) { - set(propertyName, Double.toString(value)); - } - - public void setFloat(String propertyName, float value) { - set(propertyName, Float.toString(value)); - } - - public long getLong(String propertyName, long defaultValue) { - Long result = getLongImpl(propertyName); - if (result == null) { - return defaultValue; - } - return result.longValue(); - } - - public long getLong(String propertyName) { - Long result = getLongImpl(propertyName); - if (result == null) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.missingProperty", propertyName, result); - return 0; - } - return result.longValue(); - } - - private Long getLongImpl(String propertyName) { - String value = (String) props.get(propertyName); - if (value != null) { - Long result = Parse.parseLong(value, messageBundle); - if (result != null) { - return result; - } - props.remove(propertyName); - } - value = (String) defaultProps.get(propertyName); - if (value != null) { - Long result = Parse.parseLong(value, null); - if (result != null) { - return result; - } - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.brokenProperty ", propertyName, value); - } - return null; - } - - public void setLong(String propertyName, long value) { - set(propertyName, Long.toString(value)); - } - - public boolean getBoolean(String propertyName, boolean defaultValue) { - Boolean result = getBooleanImpl(propertyName); - if (result == null) { - return defaultValue; - } - return result == Boolean.TRUE; - } - - public boolean getBoolean(String propertyName) { - Boolean result = getBooleanImpl(propertyName); - if (result == null) { - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.missingProperty", propertyName, result); - } - return result == Boolean.TRUE; - } - - private Boolean getBooleanImpl(String propertyName) { - String value = (String) props.get(propertyName); - if (value != null) { - Boolean result = Parse.parseBoolean(value, messageBundle); - if (result != null) { - return result; - } - props.remove(propertyName); - } - value = (String) defaultProps.get(propertyName); - if (value != null) { - Boolean result = Parse.parseBoolean(value, null); - if (result != null) { - return result; - } - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.brokenProperty ", propertyName, value); - } - return null; - } - - public void setBoolean(String propertyName, boolean value) { - set(propertyName, value ? "true" : "false"); - } - - public String getSystemEncoding() { - return (new OutputStreamWriter(new ByteArrayOutputStream())).getEncoding(); - } - - public String getLookAndFeel(String propertyName, String defaultValue) { - String value = (String) props.get(propertyName); - if (value != null) { - String result = Parse.parseLookAndFeel(value, messageBundle); - if (result != null) { - return result; - } - props.remove(propertyName); - } - value = (String) defaultProps.get(propertyName); - if (value != null) { - String result = Parse.parseLookAndFeel(value, null); - if (result != null) { - return result; - } - defaultProps.remove(propertyName); - Resources.showMessageDialog(null, - JOptionPane.ERROR_MESSAGE, messageBundle, - "manager.properties.title", - "manager.properties.lafError", value); - } - return defaultValue; - } - - public String getDefaultFilePath() { - return getString(PROPERTY_DEFAULT_FILE_PATH, null); - } - - public String getDefaultURL() { - return getString(PROPERTY_DEFAULT_URL, null); - } - - public void setDefaultFilePath(String defaultFilePath) { - if (defaultFilePath == null) - remove(PROPERTY_DEFAULT_FILE_PATH); - else - set(PROPERTY_DEFAULT_FILE_PATH, defaultFilePath); - } - - public void setDefaultURL(String defaultURL) { - if (defaultURL == null) - remove(PROPERTY_DEFAULT_URL); - else - set(PROPERTY_DEFAULT_URL, defaultURL); - } - - public InputStream getResourceAsStream(String prefix, String resourcePath) { - int colon = resourcePath.indexOf(':'); - if (colon >= 0) { - if (resourcePath.lastIndexOf(colon - 1, '/') < 0) { - try { - return (new URL(resourcePath)).openStream(); - } catch (IOException e) { - // eat the exception - } - return null; - } - } - resourcePath = makeResPath(prefix, resourcePath); - ClassLoader cl = getClass().getClassLoader(); - if (cl != null) { - InputStream result = cl.getResourceAsStream(resourcePath); - if (result != null) { - return result; - } - } - return ClassLoader.getSystemResourceAsStream(resourcePath); - } - - public static String makeResPath(String prefix, String base_name) { - if (base_name.length() != 0 && base_name.charAt(0) == '/') { - return base_name.substring(1, base_name.length()); - } else if (prefix == null) { - return base_name; - } else { - return prefix + base_name; - } - } - - public static boolean checkAndStoreBooleanProperty(PropertiesManager properties, String propertyName) { - return checkAndStoreBooleanProperty(properties, propertyName, true); - } - - /** - * Method to check the value of a boolean property - * This is meant to be used for configuration via the properties file - * After the property has been checked, it will be stored back into the Properties - * object (using a default value if none was found) - * - * @param properties to check with - * @param propertyName to check for - * @param defaultVal to default to if no value is found on a property - * @return true if property is true, otherwise false - */ - public static boolean checkAndStoreBooleanProperty(PropertiesManager properties, String propertyName, boolean defaultVal) { - // If we don't have a valid PropertiesManager just return the default value - if (properties == null) { - return defaultVal; - } - - // Get the desired property, defaulting to the defaultVal parameter - boolean returnValue = properties.getBoolean(propertyName, defaultVal); - - // Set the property back into the manager - // This is necessary in the cases where a property didn't exist, but needs to be added to the file - properties.setBoolean(propertyName, returnValue); - - return returnValue; - } - - public static double checkAndStoreDoubleProperty(PropertiesManager properties, String propertyName) { - return checkAndStoreDoubleProperty(properties, propertyName, 1.0f); - } - - /** - * Method to check the value of a double property - * This is meant to be used for configuration via the properties file - * After the property has been checked, it will be stored back into the Properties - * object (using a default value if none was found) - * - * @param properties to check with - * @param propertyName to check for - * @param defaultVal to default to if no value is found on a property - * @return double property value - */ - public static double checkAndStoreDoubleProperty(PropertiesManager properties, String propertyName, double defaultVal) { - // If we don't have a valid PropertiesManager just return the default value - if (properties == null) { - return defaultVal; - } - - // Get the desired property, defaulting to the defaultVal parameter - double returnValue = properties.getDouble(propertyName, defaultVal); - - // Set the property back into the manager - // This is necessary in the cases where a property didn't exist, but needs to be added to the file - properties.setDouble(propertyName, returnValue); - - return returnValue; - } - - public static int checkAndStoreIntegerProperty(PropertiesManager properties, String propertyName) { - return checkAndStoreIntegerProperty(properties, propertyName, 1); - } - - /** - * Method to check the value of an int property - * This is meant to be used for configuration via the properties file - * After the property has been checked, it will be stored back into the Properties - * object (using a default value if none was found) - * - * @param properties to check with - * @param propertyName to check for - * @param defaultVal to default to if no value is found on a property - * @return int value of property - */ - public static int checkAndStoreIntegerProperty(PropertiesManager properties, String propertyName, int defaultVal) { - // If we don't have a valid PropertiesManager just return the default value - if (properties == null) { - return defaultVal; - } - - // Get the desired property, defaulting to the defaultVal parameter - int returnValue = properties.getInt(propertyName, defaultVal); - - // Set the property back into the manager - // This is necessary in the cases where a property didn't exist, but needs to be added to the file - properties.setInt(propertyName, returnValue); - - return returnValue; - } - - /** - * Method to check the value of a comma separate list of floats property - * For example we will convert "0.4f, 0.5f, 0.6f" to a size 3 array with the values as floats - * This is meant to be used for configuration via the properties file - * After the property has been checked, it will be stored back into the Properties - * object (using a default value if none was found) - * - * @param properties to check with - * @param propertyName to check for - * @param defaultVal to default to if no value is found on a property - * @return array of floats from the property - */ - public static float[] checkAndStoreFloatArrayProperty(PropertiesManager properties, String propertyName, float[] defaultVal) { - // If we don't have a valid PropertiesManager just return the default value - if ((properties == null) || (properties.props == null)) { - return defaultVal; - } - - // Get the desired property, defaulting to the defaultVal parameter - String propertyString = properties.props.getProperty(propertyName); - - float[] toReturn = defaultVal; - - try { - // Ensure we have a property string to parse - // Then we'll conver the comma separated property to a list of floats - if ((propertyString != null) && - (propertyString.trim().length() > 0)) { - String[] split = propertyString.split(","); - toReturn = new float[split.length]; - - for (int i = 0; i < split.length; i++) { - try { - toReturn[i] = Float.parseFloat(split[i]); - } catch (NumberFormatException failedValue) { - /* ignore as we'll just automatically put a '0' in the invalid space */ - } - } - } - // Otherwise convert the defaultVal into a comma separated list - // This is done so it can be stored back into the properties file - else { - StringBuilder commaBuffer = new StringBuilder(defaultVal.length * 2); - - for (int i = 0; i < defaultVal.length; i++) { - commaBuffer.append(defaultVal[i]); - - // Check whether we need a comma - if ((i + 1) < defaultVal.length) { - commaBuffer.append(","); - } - } - - // Set the property back into the manager - // This is necessary in the cases where a property didn't exist, but needs to be added to the file - properties.set(propertyName, commaBuffer.toString()); - } - } catch (Exception failedProperty) { - /* ignore on failure as we'll just return defaultVal */ - } - - return toReturn; - } -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/Resources.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/Resources.java deleted file mode 100644 index 794a2dded2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/Resources.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - - -import javax.swing.*; -import java.awt.*; -import java.text.MessageFormat; -import java.util.ResourceBundle; - -/** - * This is a utility class for ldisplaying internationalized dialogs. - * - * @since 1.0 - */ -public final class Resources extends StringResource { - - public static void showMessageDialog(Component parent, - final int dialogType, - ResourceBundle messageBundle, - String titleKey, - String messageKey) { - - showMessageDialog(parent, dialogType, messageBundle, titleKey, messageKey, - null, null, null, null); - } - - public static void showMessageDialog(Component parent, - final int dialogType, - ResourceBundle messageBundle, - String titleKey, - String messageKey, - Object messageArg1) { - - showMessageDialog(parent, dialogType, messageBundle, titleKey, messageKey, - messageArg1, null, null, null); - } - - public static void showMessageDialog(Component parent, - final int dialogType, - ResourceBundle messageBundle, - String titleKey, - String messageKey, - Object messageArg1, - Object messageArg2) { - - showMessageDialog(parent, dialogType, messageBundle, titleKey, messageKey, - messageArg1, messageArg2, null, null); - } - - public static void showMessageDialog(Component parent, - final int dialogType, - ResourceBundle messageBundle, - String titleKey, - String messageKey, - Object messageArg1, - Object messageArg2, - Object messageArg3) { - - showMessageDialog(parent, dialogType, messageBundle, titleKey, messageKey, - messageArg1, messageArg2, messageArg3, null); - } - - public static void showMessageDialog(Component parent, - final int dialogType, - ResourceBundle messageBundle, - String titleKey, - String messageKey, - Object messageArg1, - Object messageArg2, - Object messageArg3, - Object messageArg4) { - // setup a patterned message - Object[] messageArguments = {messageArg1, messageArg2, messageArg3, - messageArg4 - }; - - MessageFormat formatter = new MessageFormat( - messageBundle.getString(messageKey)); - - JOptionPane.showMessageDialog( - parent, - formatter.format(messageArguments), - messageBundle.getString(titleKey), - dialogType); - } - - public static boolean showConfirmDialog(Component parent, - ResourceBundle messageBundle, - String titleKey, - String messageKey) { - - return showConfirmDialog(parent, messageBundle, titleKey, messageKey, - null, null, null, null); - } - - public static boolean showConfirmDialog(Component parent, - ResourceBundle messageBundle, - String titleKey, - String messageKey, - Object messageArg1) { - - return showConfirmDialog(parent, messageBundle, titleKey, messageKey, - messageArg1, null, null, null); - } - - public static boolean showConfirmDialog(Component parent, - ResourceBundle messageBundle, - String titleKey, - String messageKey, - Object messageArg1, - Object messageArg2) { - - return showConfirmDialog(parent, messageBundle, titleKey, messageKey, - messageArg1, messageArg2, null, null); - } - - public static boolean showConfirmDialog(Component parent, - ResourceBundle messageBundle, - String titleKey, - String messageKey, - Object messageArg1, - Object messageArg2, - Object messageArg3) { - - return showConfirmDialog(parent, messageBundle, titleKey, messageKey, - messageArg1, messageArg2, messageArg3, null); - } - - public static boolean showConfirmDialog(Component parent, - ResourceBundle messageBundle, - String titleKey, - String messageKey, - Object messageArg1, - Object messageArg2, - Object messageArg3, - Object messageArg4) { - // setup a patterned message - Object[] messageArguments = {messageArg1, messageArg2, messageArg3, - messageArg4 - }; - - MessageFormat formatter = new MessageFormat( - messageBundle.getString(messageKey)); - - return (JOptionPane.showConfirmDialog( - parent, - formatter.format(messageArguments), - messageBundle.getString(titleKey), - JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION); - } - - -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/SVG.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/SVG.java deleted file mode 100644 index a977199e7f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/SVG.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - -import org.apache.batik.dom.GenericDOMImplementation; -import org.apache.batik.svggen.SVGGraphics2D; -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.PDimension; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.util.GraphicsRenderingHints; -import org.w3c.dom.DOMImplementation; - -import java.io.Writer; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * The SVG class is a utility for writing PDF content to SVG - * format. - * - * @since 1.0 - */ -public class SVG { - - private static final Logger logger = - Logger.getLogger(SVG.class.toString()); - - /** - * Creates a SVG character stream for the given Document and - * PageNumber. - * - * @param pdfDocument Document containing the PDF data - * @param pageNumber page number of PDF content that will be rendered to SVG. - * Zero-based index - * @param out character stream that the SVG data will be written to - */ - public static void createSVG(Document pdfDocument, int pageNumber, Writer out) { - try { - - if (pdfDocument != null && - (pageNumber >= 0 && pageNumber < pdfDocument.getNumberOfPages())) { - // Get a DOMImplementation - DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); - // Create an instance of org.w3c.dom.Document - org.w3c.dom.Document document = domImpl.createDocument(null, "svg", - null); - // Create an instance of the SVG Generator - SVGGraphics2D svgGenerator = new SVGGraphics2D(document); - // Ask the test to render into the SVG Graphics2D implementation - - float userRotation = 0; - float userZoom = 1; - PDimension pdfDimension = pdfDocument.getPageDimension(pageNumber, userRotation, userZoom); - svgGenerator.setSVGCanvasSize(pdfDimension.toDimension()); - - pdfDocument.paintPage(pageNumber, svgGenerator, - GraphicsRenderingHints.PRINT, - Page.BOUNDARY_CROPBOX, - userRotation, userZoom); - - // Finally, stream out SVG to the standard output using UTF-8 - // character to byte encoding - boolean useCSS = true; // we want to use CSS style attribute - // File f=new File("a.svg"); - // Writer out = new OutputStreamWriter(new FileOutputStream(f), "UTF-8"); - svgGenerator.stream(out, useCSS); - } - } catch (org.apache.batik.svggen.SVGGraphics2DIOException e) { - logger.log(Level.SEVERE, "Error creating svg document.", e); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - logger.log(Level.SEVERE, "Error creating svg document.", e); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/SearchTextTask.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/SearchTextTask.java deleted file mode 100644 index 7f9ec34ada..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/SearchTextTask.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.graphics.text.LineText; -import org.icepdf.core.search.DocumentSearchController; -import org.icepdf.ri.common.SwingController; -import org.icepdf.ri.common.SwingWorker; -import org.icepdf.ri.common.utility.search.SearchPanel; - -import javax.swing.*; -import java.awt.*; -import java.text.MessageFormat; -import java.util.List; -import java.util.ResourceBundle; - -/** - * This class is a utility for searching text in a PDF document. This is only - * a reference implementation; there is currently no support for regular - * expression and other advanced search features. - * - * @since 1.1 - */ -public class SearchTextTask { - - // total length of task (total page count), used for progress bar - private int lengthOfTask; - // current progress, used for the progress bar - private int current = 0; - // message displayed on progress bar - private String dialogMessage; - // canned internationalized messages. - private MessageFormat searchingMessageForm; - private MessageFormat searchResultMessageForm; - private MessageFormat searchCompletionMessageForm; - // flags for threading - private boolean done = false; - private boolean canceled = false; - // keep track of total hits - private int totalHitCount = 0; - // String to search for and parameters from gui - private String pattern = ""; - private boolean wholeWord; - private boolean caseSensitive; - private boolean cumulative; - private boolean showPages; - private boolean r2L; - - // parent swing controller - SwingController controller; - - // append nodes for found text. - private SearchPanel searchPanel; - - // message bundle for internationalization - private ResourceBundle messageBundle; - - private boolean currentlySearching; - - private Container viewContainer; - - /** - * Creates a new instance of the SearchTextTask. - * - * @param searchPanel parent search panel that start this task via an action - * @param controller root controller object - * @param pattern pattern to search for - * @param wholeWord ture inticates whole word search - * @param caseSensitive case sensitive indicates cases sensitive search - * @param r2L right left earch, not currently implemented. - * @param messageBundle message bundle used for dialog text. - */ - public SearchTextTask(SearchPanel searchPanel, - SwingController controller, - String pattern, - boolean wholeWord, - boolean caseSensitive, - boolean cumulative, - boolean showPages, - boolean r2L, - ResourceBundle messageBundle) { - this.controller = controller; - this.pattern = pattern; - this.searchPanel = searchPanel; - lengthOfTask = controller.getDocument().getNumberOfPages(); - this.messageBundle = messageBundle; - this.viewContainer = controller.getDocumentViewController().getViewContainer(); - this.wholeWord = wholeWord; - this.caseSensitive = caseSensitive; - this.cumulative = cumulative; - this.showPages = showPages; - this.r2L = r2L; - - // setup searching format format. - if (searchPanel != null) { - searchingMessageForm = searchPanel.setupSearchingMessageForm(); - searchResultMessageForm = searchPanel.setupSearchResultMessageForm(); - searchCompletionMessageForm = searchPanel.setupSearchCompletionMessageForm(); - } - } - - /** - * Start the task, start searching the document for the pattern. - */ - public void go() { - final SwingWorker worker = new SwingWorker() { - public Object construct() { - current = 0; - done = false; - canceled = false; - dialogMessage = null; - return new ActualTask(); - } - }; - worker.setThreadPriority(Thread.NORM_PRIORITY); - worker.start(); - } - - /** - * Number pages that search task has to iterate over. - * - * @return returns max number of pages in document being search. - */ - public int getLengthOfTask() { - return lengthOfTask; - } - - /** - * Gets the page that is currently being searched by this task. - * - * @return current page being processed. - */ - public int getCurrent() { - return current; - } - - /** - * Stop the task. - */ - public void stop() { - canceled = true; - dialogMessage = null; - } - - /** - * Find out if the task has completed. - * - * @return true if task is done, false otherwise. - */ - public boolean isDone() { - return done; - } - - public boolean isCurrentlySearching() { - return currentlySearching; - } - - /** - * Returns the most recent dialog message, or null - * if there is no current dialog message. - * - * @return current message dialog text. - */ - public String getMessage() { - return dialogMessage; - } - - /** - * The actual long running task. This runs in a SwingWorker thread. - */ - class ActualTask { - ActualTask() { - - // break on bad input - if ("".equals(pattern) || " ".equals(pattern)) { - return; - } - - try { - currentlySearching = true; - // Extraction of text from pdf procedure - totalHitCount = 0; - current = 0; - - // get instance of the search controller - DocumentSearchController searchController = - controller.getDocumentSearchController(); - if (!cumulative) { - searchController.clearAllSearchHighlight(); - } - searchController.addSearchTerm(pattern, - caseSensitive, wholeWord); - - Document document = controller.getDocument(); - // iterate over each page in the document - for (int i = 0; i < document.getNumberOfPages(); i++) { - // break if needed - if (canceled || done) { - setDialogMessage(); - break; - } - // Update task information - current = i; - - // update search message in search pane. - Object[] messageArguments = {String.valueOf((current + 1)), - lengthOfTask, lengthOfTask}; - dialogMessage = searchingMessageForm.format(messageArguments); - - // hits per page count - final List lineItems = - searchController.searchHighlightPage(current, 6); - int hitCount = lineItems.size(); - - // update total hit count - totalHitCount += hitCount; - if (hitCount > 0) { - // update search dialog - messageArguments = new Object[]{ - String.valueOf((current + 1)), - hitCount, hitCount}; - final String nodeText = - searchResultMessageForm.format(messageArguments); - final int currentPage = i; - // add the node to the search panel tree but on the - // awt thread. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - // add the node - searchPanel.addFoundEntry( - nodeText, - currentPage, - lineItems, - showPages); - // try repainting the container - viewContainer.repaint(); - } - }); - } - Thread.yield(); - } - // update the dialog and end the task - setDialogMessage(); - - done = true; - } finally { - currentlySearching = false; - } - - // repaint the view container - SwingUtilities.invokeLater(new Runnable() { - public void run() { - viewContainer.validate(); - } - }); - } - } - - /** - * Gets the message that should be displayed when the task has completed. - * - * @return search completed or stoped final message. - */ - public String getFinalMessage() { - setDialogMessage(); - return dialogMessage; - } - - /** - * Utility method for setting the dialog message. - */ - private void setDialogMessage() { - - // Build Internationalized plural phrase. - - Object[] messageArguments = {String.valueOf((current + 1)), - (current + 1), totalHitCount}; - - dialogMessage = searchCompletionMessageForm.format(messageArguments); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/StringResource.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/StringResource.java deleted file mode 100644 index b663d64ed0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/StringResource.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - -class StringResource { - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/TextExtractionTask.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/TextExtractionTask.java deleted file mode 100644 index aaf7f5cf87..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/TextExtractionTask.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.pobjects.Page; -import org.icepdf.core.pobjects.graphics.text.LineText; -import org.icepdf.core.pobjects.graphics.text.WordText; -import org.icepdf.ri.common.SwingWorker; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStreamWriter; -import java.text.ChoiceFormat; -import java.text.Format; -import java.text.MessageFormat; -import java.util.List; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * This class is a utility for extracting text from a PDF document. - * - * @since 1.1 - */ -public class TextExtractionTask { - - private static final Logger logger = - Logger.getLogger(TextExtractionTask.class.toString()); - - // total length of task (total page count), used for progress bar - private int lengthOfTask; - - // current progress, used for the progress bar - private int current = 0; - - // message displayed on progress bar - private String dialogMessage; - - // flags for threading - private boolean done = false; - private boolean canceled = false; - - // internationalization - private ResourceBundle messageBundle; - - // PDF document pointer - private Document document = null; - - // File used for text export - private File file = null; - - /** - * Create a new instance of the TextExtraction object. - * - * @param document document whose text will be extracted. - * @param file output file for extracted text. - */ - public TextExtractionTask(Document document, File file, ResourceBundle messageBundle) { - this.document = document; - this.file = file; - lengthOfTask = document.getNumberOfPages(); - this.messageBundle = messageBundle; - } - - /** - * Start the task, created a new SwingWorker for the text extraction - * process. - */ - public void go() { - final SwingWorker worker = new SwingWorker() { - // reset all instance variables - public Object construct() { - current = 0; - done = false; - canceled = false; - dialogMessage = null; - return new ActualTask(); - } - }; - worker.setThreadPriority(Thread.MIN_PRIORITY); - worker.start(); - } - - /** - * Find out how much work needs to be done. - */ - public int getLengthOfTask() { - return lengthOfTask; - } - - /** - * Find out how much has been done. - */ - public int getCurrent() { - return current; - } - - /** - * Stop the task. - */ - public void stop() { - canceled = true; - dialogMessage = null; - } - - /** - * Find out if the task has completed. - */ - public boolean isDone() { - return done; - } - - /** - * Returns the most recent dialog message, or null - * if there is no current dialog message. - */ - public String getMessage() { - return dialogMessage; - } - - /** - * The actual long running task. This runs in a SwingWorker thread. - */ - class ActualTask { - ActualTask() { - // Extraction of text from pdf procedure - try { - // create file output stream - BufferedWriter fileOutputStream = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(file), "UTF8")); - // Print document information - String pageNumber = - messageBundle.getString("viewer.exportText.fileStamp.msg"); - - fileOutputStream.write(pageNumber); - fileOutputStream.write(10); // line break - - for (int i = 0; i < document.getNumberOfPages(); i++) { - // break if needed - if (canceled || done) { - break; - } - - // Update task information - current = i; - - // Build Internationalized plural phrase. - MessageFormat messageForm = - new MessageFormat(messageBundle.getString( - "viewer.exportText.fileStamp.progress.msg")); - double[] fileLimits = {0, 1, 2}; - String[] fileStrings = { - messageBundle.getString( - "viewer.exportText.fileStamp.progress.moreFile.msg"), - messageBundle.getString( - "viewer.exportText.fileStamp.progress.oneFile.msg"), - messageBundle.getString( - "viewer.exportText.fileStamp.progress.moreFile.msg"), - }; - ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, - fileStrings); - Format[] formats = {null, choiceForm, null}; - messageForm.setFormats(formats); - Object[] messageArguments = {String.valueOf((current + 1)), - lengthOfTask, lengthOfTask}; - - dialogMessage = messageForm.format(messageArguments); - - messageForm = - new MessageFormat(messageBundle.getString( - "viewer.exportText.pageStamp.msg")); - messageArguments = new Object[]{String.valueOf((current + 1))}; - - pageNumber = messageForm.format(messageArguments); - - fileOutputStream.write(pageNumber); - fileOutputStream.write(10); // line break - - Page page = document.getPageTree().getPage(i); - List pageLines; - if (page.isInitiated()) { - // get a pages already initialized text. - pageLines = document.getPageViewText(i).getPageLines(); - } else { - // grap the text the fastest way possible. - pageLines = document.getPageText(i).getPageLines(); - } - StringBuilder extractedText; - for (LineText lineText : pageLines) { - extractedText = new StringBuilder(); - for (WordText wordText : lineText.getWords()) { - extractedText.append(wordText.getText()); - } - extractedText.append('\n'); - fileOutputStream.write(extractedText.toString()); - } - - Thread.yield(); - - } - - done = true; - current = 0; - fileOutputStream.flush(); - fileOutputStream.close(); - } catch (Throwable e) { - logger.log(Level.FINE, "Malformed URL Exception ", e); - } - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/URLAccess.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/URLAccess.java deleted file mode 100644 index bfe533199b..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/URLAccess.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.util; - -import java.io.*; -import java.net.ConnectException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.UnknownHostException; - -/** - * This utility class simplifies the process of loading URLs. - * - * @since 1.3 - */ -public class URLAccess { - /** - * Simple utility method to check if a URL is valid. - * If it is invalid, then urlAccess.errorMessage will say why. - * If it is valid, then urlAccess.url will be a valid URL object, - * and urlAccess.inputStream will be opened to access the data from the URL. - * - * @param urlLocation - * @return URLAccess urlAccess - */ - public static URLAccess doURLAccess(String urlLocation) { - URLAccess res = new URLAccess(); - res.urlLocation = urlLocation; - try { - res.url = new URL(urlLocation); - // check to make sure stream is good - // If url is http, then we might just get a 404 web page - PushbackInputStream in = new PushbackInputStream( - new BufferedInputStream(res.url.openStream()), - 1); - int b = in.read(); - in.unread(b); - res.inputStream = in; - } catch (MalformedURLException e) { - res.errorMessage = "Malformed URL"; - } catch (FileNotFoundException e) { - res.errorMessage = "File Not Found"; - } catch (UnknownHostException e) { - res.errorMessage = "Unknown Host"; - } catch (ConnectException e) { - res.errorMessage = "Connection Timed Out"; - } catch (IOException e) { - res.errorMessage = "IO exception"; - } - return res; - } - - - /** - * The given URL string given to doURLAccess(). - */ - public String urlLocation; - - /** - * The resolved URL, if urlLocation was valid. - */ - public URL url; - - /** - * Access to the data at the URL, if the URL was valid. - */ - public InputStream inputStream; - - /** - * The reason why the URL was invalid. - */ - public String errorMessage; - - private URLAccess() { - } - - /** - * Free up any resources used, immediately. - */ - public void dispose() { - urlLocation = null; - url = null; - errorMessage = null; - closeConnection(); - } - - /** - * Close the connection, but keep all the String - * information about the connection. - */ - public void closeConnection() { - if (inputStream != null) { - try { - inputStream.close(); - } catch (Exception e) { - } - inputStream = null; - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/jxlayer/JXLayer.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/jxlayer/JXLayer.java deleted file mode 100644 index 16eeaa150e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/jxlayer/JXLayer.java +++ /dev/null @@ -1,813 +0,0 @@ -/** - * Copyright (c) 2006-2009, Alexander Potochkin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the JXLayer project nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icepdf.ri.util.jxlayer; - -import org.icepdf.ri.util.jxlayer.plaf.LayerUI; - -import javax.accessibility.Accessible; -import javax.accessibility.AccessibleContext; -import javax.accessibility.AccessibleRole; -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.lang.ref.WeakReference; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Iterator; - -/** - * The universal decorator for Swing components - * with which you can implement various advanced painting effects - * as well as receive notification of all {@code MouseEvent}s, - * {@code KeyEvent}s and {@code FocusEvent}s which generated within its borders. - *

      - * {@code JXLayer} delegates its painting and input events handling - * to its {@link LayerUI} object which performs the actual decoration. - *

      - * The custom painting and events notification automatically work - * for {@code JXLayer} itself and all its subcomponents. - * This powerful combination makes it possible to enrich existing components - * with new advanced functionality such as temporary locking of a hierarchy, - * data tips for compound components, enhanced mouse scrolling etc... - *

      - * {@code JXLayer} is a great solution if you just need to do custom painting - * over compound component or catch input events of its subcomponents. - *

      - *

      - *         // create a component to be decorated with the layer
      - *        JPanel panel = new JPanel();
      - *        panel.add(new JButton("JButton"));
      - *
      - *        // This custom layerUI will fill the layer with translucent green
      - *        // and print out all mouseMotion events generated within its borders
      - *        AbstractLayerUI<JPanel> layerUI = new AbstractLayerUI<JPanel>() {
      - *
      - *            protected void paintLayer(Graphics2D g2, JXLayer<JPanel> l) {
      - *                // this paints the layer as is
      - *                super.paintLayer(g2, l);
      - *                // fill it with the translucent green
      - *                g2.setColor(new Color(0, 128, 0, 128));
      - *                g2.fillRect(0, 0, l.getWidth(), l.getHeight());
      - *            }
      - *
      - *            // overridden method which catches MouseMotion events
      - *            protected void processMouseMotionEvent(MouseEvent e) {
      - *                System.out.println("MouseMotionEvent detected: "
      - *                        + e.getX() + " " + e.getY());
      - *            }
      - *        };
      - *
      - *        // create the layer for the panel using our custom layerUI
      - *        JXLayer<JPanel> layer = new JXLayer<JPanel>(panel, layerUI);
      - *
      - *        // work with the layer as with any other Swing component
      - *        frame.add(layer);
      - * 
      - *

      - * Note: When a {@code LayerUI} instance is disabled or not set, - * its {@code JXLayer}s temporary lose all their decorations. - * Note: {@code JXLayer} is very friendly to your application, - * it uses only public Swing API and doesn't rely on any global settings - * like custom {@code RepaintManager} or {@code AWTEventListener}. - * It neither change the opaque state of its subcomponents - * nor use the glassPane of its parent frame. - *

      - * {@code JXLayer} can be used under restricted environment - * (e.g. unsigned applets) - * - * @see #setUI(LayerUI) - * @see LayerUI - */ -@SuppressWarnings("serial") -public final class JXLayer extends JComponent - implements Scrollable, PropertyChangeListener, Accessible { - private V view; - // this field is necessary because JComponent.ui is transient - // when layerUI is serializable - private LayerUI layerUI; - private JPanel glassPane; - private boolean isPainting; - private static final DefaultLayerLayout sharedLayoutInstance = - new DefaultLayerLayout(); - private long eventMask; - - private static final LayerEventController eventController = - new LayerEventController(); - private static final long ACCEPTED_EVENTS = - AWTEvent.COMPONENT_EVENT_MASK | - AWTEvent.CONTAINER_EVENT_MASK | - AWTEvent.FOCUS_EVENT_MASK | - AWTEvent.KEY_EVENT_MASK | - AWTEvent.MOUSE_WHEEL_EVENT_MASK | - AWTEvent.MOUSE_MOTION_EVENT_MASK | - AWTEvent.MOUSE_EVENT_MASK | - AWTEvent.INPUT_METHOD_EVENT_MASK | - AWTEvent.HIERARCHY_EVENT_MASK | - AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK; - - /** - * Creates a new {@code JXLayer} object with empty view component - * and empty {@link LayerUI}. - * - * @see #setView - * @see #setUI - */ - public JXLayer() { - this(null); - } - - /** - * Creates a new {@code JXLayer} object with empty {@link LayerUI}. - * - * @param view the component to be decorated with this {@code JXLayer} - * @see #setUI - */ - public JXLayer(V view) { - this(view, null); - } - - /** - * Creates a new {@code JXLayer} object with provided view component - * and {@link LayerUI} object. - * - * @param view the component to be decorated - * @param ui the {@link LayerUI} delegate - * to be used by this {@code JXLayer} - */ - public JXLayer(V view, LayerUI ui) { - super.setLayout(sharedLayoutInstance); - setGlassPane(createGlassPane()); - setView(view); - setUI(ui); - } - - /** - * Returns the {@code JXLayer}'s view component or {@code null}. - *
      This is a bound property. - * - * @return the {@code JXLayer}'s view component - * or {@code null} if none exists - * @see #setView(Component) - */ - public V getView() { - return view; - } - - /** - * Sets the {@code JXLayer}'s view component, which can be {@code null}. - *
      This is a bound property. - * - * @param view the view component for this {@code JXLayer} - * @see #getView() - */ - public void setView(V view) { - Component oldView = getView(); - if (oldView != null) { - super.remove(oldView); - } - if (view != null) { - super.addImpl(view, null, getComponentCount()); - } - this.view = view; - firePropertyChange("view", oldView, view); - revalidate(); - repaint(); - } - - /** - * Sets the {@link LayerUI} which will perform painting - * and receive input events for this {@code JXLayer}. - * - * @param ui the {@link LayerUI} for this {@code JXLayer} - */ - public void setUI(LayerUI ui) { - this.layerUI = ui; - super.setUI(ui); - } - - /** - * Returns the {@link LayerUI} for this {@code JXLayer}. - * - * @return the {@code LayerUI} for this {@code JXLayer} - */ - public LayerUI getUI() { - return layerUI; - } - - /** - * Returns the {@code JXLayer}'s glassPane component or {@code null}. - *
      This is a bound property. - * - * @return the {@code JXLayer}'s glassPane component - * or {@code null} if none exists - * @see #setGlassPane(JPanel) - */ - public JPanel getGlassPane() { - return glassPane; - } - - /** - * Sets the {@code JXLayer}'s glassPane component, which can be {@code null}. - *
      This is a bound property. - * - * @param glassPane the glassPane component of this {@code JXLayer} - * @see #getGlassPane() - */ - public void setGlassPane(JPanel glassPane) { - Container oldGlassPane = getGlassPane(); - if (oldGlassPane != null) { - super.remove(oldGlassPane); - } - if (glassPane != null) { - super.addImpl(glassPane, null, 0); - } - this.glassPane = glassPane; - firePropertyChange("glassPane", oldGlassPane, glassPane); - revalidate(); - repaint(); - } - - /** - * Called by the constructor methods to create the default - * {@code glassPane}. - * By default this method creates a new {@code JPanel} - * with visibility set to {@code true} and opacity set to {@code false}. - * - * @return the default {@code glassPane} - */ - public JPanel createGlassPane() { - return new DefaultLayerGlassPane(); - } - - /** - * This method is not supported by {@code JXLayer} - * and always throws {@code UnsupportedOperationException} - * - * @throws UnsupportedOperationException this method is not supported - * @see #setView(Component) - * @see #setGlassPane(JPanel) - */ - protected void addImpl(Component comp, Object constraints, int index) { - throw new UnsupportedOperationException( - "Adding components to JXLayer is not supported, " + - "use setView() or setGlassPane() instead"); - } - - /** - * {@inheritDoc} - */ - public void remove(Component comp) { - if (comp == getView()) { - setView(null); - } else if (comp == getGlassPane()) { - setGlassPane(null); - } else { - super.remove(comp); - } - } - - /** - * {@inheritDoc} - */ - public void removeAll() { - setView(null); - setGlassPane(null); - } - - /** - * Delegates all painting to the {@link LayerUI} object. - * - * @param g the {@code Graphics} to render to - */ - public void paint(Graphics g) { - if (!isPainting && getUI() != null) { - isPainting = true; - super.paintComponent(g); - isPainting = false; - } else { - super.paint(g); - } - } - - /** - * This method is empty, because all painting is done by - * {@link #paint(Graphics)} and - * {@link LayerUI#update(Graphics, JComponent)} methods - */ - protected void paintComponent(Graphics g) { - } - - /** - * To enable the correct painting of the glassPane and view component, - * the {@code JXLayer} overrides the default implementation of - * this method to return {@code false} when the glassPane is visible. - * - * @return false if {@code JXLayer}'s glassPane is visible - */ - public boolean isOptimizedDrawingEnabled() { - return !glassPane.isVisible(); - } - - /** - * {@inheritDoc} - */ - public void propertyChange(PropertyChangeEvent evt) { - if (getUI() != null) { - getUI().handlePropertyChangeEvent(evt, this); - } - } - - /** - * Sets the bitmask of event types to receive by this {@code JXLayer}. - * Here is the list of the supported event types: - *

        - *
      • AWTEvent.COMPONENT_EVENT_MASK
      • - *
      • AWTEvent.CONTAINER_EVENT_MASK
      • - *
      • AWTEvent.FOCUS_EVENT_MASK
      • - *
      • AWTEvent.KEY_EVENT_MASK
      • - *
      • AWTEvent.MOUSE_WHEEL_EVENT_MASK
      • - *
      • AWTEvent.MOUSE_MOTION_EVENT_MASK
      • - *
      • AWTEvent.MOUSE_EVENT_MASK
      • - *
      • AWTEvent.INPUT_METHOD_EVENT_MASK
      • - *
      • AWTEvent.HIERARCHY_EVENT_MASK
      • - *
      • AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK
      • - *
      - *

      - * If {@code LayerUI} is installed, - * {@link LayerUI#eventDispatched(AWTEvent, JXLayer)} method - * will only receive events that match the event mask. - *

      - * Here is an example how to correclty use this method - * in the {@code LayerUI} implementations: - *

      -     *    public void installUI(JComponent c) {
      -     *       super.installUI(c);
      -     *       JXLayer l = (JXLayer) c;
      -     *       // this LayerUI will receive only key and focus events
      -     *       l.setLayerEventMask(AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
      -     *    }
      -     *
      -     *    public void uninstallUI(JComponent c) {
      -     *       super.uninstallUI(c);
      -     *       JXLayer l = (JXLayer) c;
      -     *       // JXLayer must be returned to its initial state
      -     *       l.setLayerEventMask(0);
      -     *    }
      -     * 
      - *

      - * By default {@code JXLayer} receives no events. - * - * @param layerEventMask the bitmask of event types to receive - * @throws IllegalArgumentException if the {@code layerEventMask} parameter - * contains unsupported event types - * @see #getLayerEventMask() - */ - public void setLayerEventMask(long layerEventMask) { - if (layerEventMask != (layerEventMask & ACCEPTED_EVENTS)) { - throw new IllegalArgumentException( - "The event bitmask contains unsupported event types"); - } - long oldEventMask = getLayerEventMask(); - this.eventMask = layerEventMask; - firePropertyChange("layerEventMask", oldEventMask, layerEventMask); - if (layerEventMask != oldEventMask) { - disableEvents(oldEventMask); - enableEvents(eventMask); - eventController.updateAWTEventListener(this); - } - } - - /** - * Returns the bitmap of event mask to receive by this {@code JXLayer} - * and its {@code LayerUI}. - *

      - * It means that {@link LayerUI#eventDispatched(AWTEvent, JXLayer)} method - * will only receive events that match the event mask. - *

      - * By default {@code JXLayer} receives no events. - * - * @return the bitmask of event types to receive for this {@code JXLayer} - */ - public long getLayerEventMask() { - return eventMask; - } - - /** - * Delegates its functionality to the {@link LayerUI#updateUI(JXLayer)} method, - * if {@code LayerUI} is set. - */ - public void updateUI() { - if (getUI() != null) { - getUI().updateUI(this); - } - } - - /** - * Returns the preferred size of the viewport for a view component. - *

      - * If the ui delegate of this layer is not null, this method delegates its - * implementation to the {@code LayerUI.getPreferredScrollableViewportSize(JXLayer)} - * - * @return the preferred size of the viewport for a view component - * @see Scrollable - * @see org.icepdf.ri.util.jxlayer.plaf.LayerUI#getPreferredScrollableViewportSize(JXLayer) - */ - public Dimension getPreferredScrollableViewportSize() { - if (getUI() != null) { - return getUI().getPreferredScrollableViewportSize(this); - } - return getPreferredSize(); - } - - /** - * Components that display logical rows or columns should compute - * the scroll increment that will completely expose one block - * of rows or columns, depending on the value of orientation. - *

      - * If the ui delegate of this layer is not null, this method delegates its - * implementation to the {@code LayerUI.getScrollableBlockIncrement(JXLayer, Rectangle, int, int)} - * - * @return the "block" increment for scrolling in the specified direction - * @see Scrollable - * @see LayerUI#getScrollableBlockIncrement(JXLayer, Rectangle, int, int) - */ - public int getScrollableBlockIncrement(Rectangle visibleRect, - int orientation, int direction) { - if (getUI() != null) { - return getUI().getScrollableBlockIncrement(this, visibleRect, - orientation, direction); - } - return (orientation == SwingConstants.VERTICAL) ? visibleRect.height : - visibleRect.width; - } - - /** - * Returns false to indicate that the height of the viewport does not - * determine the height of the layer, unless the preferred height - * of the layer is smaller than the viewports height. - *

      - * If the ui delegate of this layer is not null, this method delegates its - * implementation to the {@code LayerUI.getScrollableTracksViewportHeight(JXLayer)} - * - * @return whether the layer should track the height of the viewport - * @see Scrollable - * @see LayerUI#getScrollableTracksViewportHeight(JXLayer) - */ - public boolean getScrollableTracksViewportHeight() { - if (getUI() != null) { - return getUI().getScrollableTracksViewportHeight(this); - } - if (getParent() instanceof JViewport) { - return ((getParent()).getHeight() > getPreferredSize().height); - } - return false; - } - - /** - * Returns false to indicate that the width of the viewport does not - * determine the width of the layer, unless the preferred width - * of the layer is smaller than the viewports width. - *

      - * If the ui delegate of this layer is not null, this method delegates its - * implementation to the {@code LayerUI.getScrollableTracksViewportWidth(JXLayer)} - * - * @return whether the layer should track the width of the viewport - * @see Scrollable - * @see LayerUI#getScrollableTracksViewportWidth(JXLayer) - */ - public boolean getScrollableTracksViewportWidth() { - if (getUI() != null) { - return getUI().getScrollableTracksViewportWidth(this); - } - if (getParent() instanceof JViewport) { - return ((getParent()).getWidth() > getPreferredSize().width); - } - return false; - } - - /** - * Components that display logical rows or columns should compute - * the scroll increment that will completely expose one new row - * or column, depending on the value of orientation. Ideally, - * components should handle a partially exposed row or column by - * returning the distance required to completely expose the item. - *

      - * Scrolling containers, like JScrollPane, will use this method - * each time the user requests a unit scroll. - *

      - * If the ui delegate of this layer is not null, this method delegates its - * implementation to the {@code LayerUI.getScrollableUnitIncrement(JXLayer, Rectangle, int, int)} - * - * @return The "unit" increment for scrolling in the specified direction. - * This value should always be positive. - * @see Scrollable - * @see LayerUI#getScrollableUnitIncrement(JXLayer, Rectangle, int, int) - */ - public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, - int direction) { - if (getUI() != null) { - return getUI().getScrollableUnitIncrement( - this, visibleRect, orientation, direction); - } - return 1; - } - - private void readObject(ObjectInputStream s) - throws IOException, ClassNotFoundException { - s.defaultReadObject(); - if (getUI() != null) { - setUI(getUI()); - } - if (getLayerEventMask() != 0) { - eventController.updateAWTEventListener(this); - } - } - - @Override - public AccessibleContext getAccessibleContext() { - if (accessibleContext == null) { - accessibleContext = new AccessibleJComponent() { - @Override - public AccessibleRole getAccessibleRole() { - return AccessibleRole.PANEL; - } - }; - } - return accessibleContext; - } - - /** - * static AWTEventListener to be shared with all AbstractLayerUIs - */ - @SuppressWarnings("serial") - private static class LayerEventController implements AWTEventListener { - private ArrayList> layerList = - new ArrayList>(); - - private long currentEventMask; - - @SuppressWarnings("unchecked") - public void eventDispatched(AWTEvent event) { - Object source = event.getSource(); - if (source instanceof Component) { - Component component = (Component) source; - while (component != null) { - if (component instanceof JXLayer) { - JXLayer l = (JXLayer) component; - LayerUI ui = l.getUI(); - if (ui != null && - isEventEnabled(l.getLayerEventMask(), - event.getID())) { - ui.eventDispatched(event, l); - } - } - component = component.getParent(); - } - } - } - - private boolean layerListContains(JXLayer l) { - for (WeakReference layerWeakReference : layerList) { - if (layerWeakReference.get() == l) { - return true; - } - } - return false; - } - - private void updateAWTEventListener(JXLayer layer) { - if (!layerListContains(layer) && layer.getLayerEventMask() != 0) { - layerList.add(new WeakReference(layer)); - } - long combinedMask = 0; - Iterator> it = layerList.iterator(); - while (it.hasNext()) { - WeakReference weakRef = it.next(); - JXLayer currLayer = weakRef.get(); - if (currLayer == null) { - it.remove(); - } else { - combinedMask |= currLayer.getLayerEventMask(); - } - } - if (combinedMask == 0) { - removeAWTEventListener(); - layerList.clear(); - } else if (getCurrentEventMask() != combinedMask) { - removeAWTEventListener(); - addAWTEventListener(combinedMask); - } - } - - private long getCurrentEventMask() { - return currentEventMask; - } - - private void addAWTEventListener(final long eventMask) { - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - Toolkit.getDefaultToolkit(). - addAWTEventListener(LayerEventController.this, eventMask); - return null; - } - }); - currentEventMask = eventMask; - } - - private void removeAWTEventListener() { - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - Toolkit.getDefaultToolkit(). - removeAWTEventListener(LayerEventController.this); - return null; - } - }); - currentEventMask = 0; - } - - private boolean isEventEnabled(long eventMask, int id) { - return (((eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0 && - id >= ComponentEvent.COMPONENT_FIRST && - id <= ComponentEvent.COMPONENT_LAST) - || ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 && - id >= ContainerEvent.CONTAINER_FIRST && - id <= ContainerEvent.CONTAINER_LAST) - || ((eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0 && - id >= FocusEvent.FOCUS_FIRST && - id <= FocusEvent.FOCUS_LAST) - || ((eventMask & AWTEvent.KEY_EVENT_MASK) != 0 && - id >= KeyEvent.KEY_FIRST && - id <= KeyEvent.KEY_LAST) - || ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 && - id == MouseEvent.MOUSE_WHEEL) - || ((eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0 && - (id == MouseEvent.MOUSE_MOVED || - id == MouseEvent.MOUSE_DRAGGED)) - || ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0 && - id != MouseEvent.MOUSE_MOVED && - id != MouseEvent.MOUSE_DRAGGED && - id != MouseEvent.MOUSE_WHEEL && - id >= MouseEvent.MOUSE_FIRST && - id <= MouseEvent.MOUSE_LAST) - || ((eventMask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0 && - id >= InputMethodEvent.INPUT_METHOD_FIRST && - id <= InputMethodEvent.INPUT_METHOD_LAST) - || ((eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 && - id == HierarchyEvent.HIERARCHY_CHANGED) - || ((eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 && - (id == HierarchyEvent.ANCESTOR_MOVED || - id == HierarchyEvent.ANCESTOR_RESIZED))); - } - } - - @SuppressWarnings("serial") - private static class DefaultLayerLayout implements LayoutManager, Serializable { - /** - * {@inheritDoc} - */ - public void layoutContainer(Container parent) { - JXLayer layer = (JXLayer) parent; - Component view = layer.getView(); - Component glassPane = layer.getGlassPane(); - if (view != null) { - Insets insets = layer.getInsets(); - view.setLocation(insets.left, insets.top); - view.setSize(layer.getWidth() - insets.left - insets.right, - layer.getHeight() - insets.top - insets.bottom); - } - if (glassPane != null) { - glassPane.setLocation(0, 0); - glassPane.setSize(layer.getWidth(), layer.getHeight()); - } - } - - /** - * {@inheritDoc} - */ - public Dimension minimumLayoutSize(Container parent) { - JXLayer layer = (JXLayer) parent; - Insets insets = layer.getInsets(); - Dimension ret = new Dimension(insets.left + insets.right, - insets.top + insets.bottom); - Component view = layer.getView(); - if (view != null) { - Dimension size = view.getMinimumSize(); - ret.width += size.width; - ret.height += size.height; - } - if (ret.width == 0 || ret.height == 0) { - ret.width = ret.height = 4; - } - return ret; - } - - /** - * {@inheritDoc} - */ - public Dimension preferredLayoutSize(Container parent) { - JXLayer layer = (JXLayer) parent; - Insets insets = layer.getInsets(); - Dimension ret = new Dimension(insets.left + insets.right, - insets.top + insets.bottom); - Component view = layer.getView(); - if (view != null) { - Dimension size = view.getPreferredSize(); - if (size.width > 0 && size.height > 0) { - ret.width += size.width; - ret.height += size.height; - } - } - return ret; - } - - /** - * {@inheritDoc} - */ - public void addLayoutComponent(String name, Component comp) { - } - - /** - * {@inheritDoc} - */ - public void removeLayoutComponent(Component comp) { - } - } - - /** - * The default glassPane for the {@link JXLayer}. - * It is a subclass of {@code JPanel} which is non opaque by default. - */ - @SuppressWarnings("serial") - private static class DefaultLayerGlassPane extends JPanel { - /** - * Creates a new {@link DefaultLayerGlassPane} - */ - public DefaultLayerGlassPane() { - setOpaque(false); - } - - /** - * First, implementatation of this method iterates through - * glassPane's child components and returns {@code true} - * if any of them is visible and contains passed x,y point. - * After that it checks if no mouseListeners is attached to this component - * and no mouse cursor is set, then it returns {@code false}, - * otherwise calls the super implementation of this method. - * - * @param x the x coordinate of the point - * @param y the y coordinate of the point - * @return true if this component logically contains x,y - */ - public boolean contains(int x, int y) { - for (int i = 0; i < getComponentCount(); i++) { - Component c = getComponent(i); - Point point = SwingUtilities.convertPoint(this, new Point(x, y), c); - if (c.isVisible() && c.contains(point)) { - return true; - } - } - if (getMouseListeners().length == 0 - && getMouseMotionListeners().length == 0 - && getMouseWheelListeners().length == 0 - && !isCursorSet()) { - return false; - } - return super.contains(x, y); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/jxlayer/plaf/LayerUI.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/jxlayer/plaf/LayerUI.java deleted file mode 100644 index ed82fcfdd5..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/util/jxlayer/plaf/LayerUI.java +++ /dev/null @@ -1,350 +0,0 @@ -/** - * Copyright (c) 2006-2008, Alexander Potochkin - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of the JXLayer project nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.icepdf.ri.util.jxlayer.plaf; - -import org.icepdf.ri.util.jxlayer.JXLayer; - -import javax.swing.*; -import javax.swing.plaf.ComponentUI; -import java.awt.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.Serializable; - -/** - * The base class for all {@link JXLayer}'s UI delegates. - *

      - * {@link #paint(java.awt.Graphics, javax.swing.JComponent)} method performes the - * painting of the {@code JXLayer} - * and {@link #eventDispatched(AWTEvent, JXLayer)} method is notified - * about any {@code AWTEvent}s which have been generated by a {@code JXLayer} - * or any of its subcomponents. - *

      - * The {@code LayerUI} is different from UI delegates of the other components, - * because it is LookAndFeel independent and is not updated by default when - * the system LookAndFeel is changed. - *

      - * The subclasses of {@code LayerUI} can either be stateless and shareable - * by multiple {@code JXLayer}s or not shareable. - * - * @param one of the super types of {@code JXLayer}'s view component - * @author Alexander Potochkin - * @see JXLayer#setUI(LayerUI) - * @see JXLayer#setView(Component) - * @see JXLayer#getView() - */ -public abstract class LayerUI - extends ComponentUI implements Serializable { - - private final PropertyChangeSupport propertyChangeSupport = - new PropertyChangeSupport(this); - - /** - * Paints the specified component. - * Subclasses should override this method and use - * the specified {@code Graphics} object to - * render the content of the component. - * - * @param g the {@code Graphics} context in which to paint; - * @param c the component being painted; - * it can be safely cast to the {@code JXLayer} - */ - @Override - public void paint(Graphics g, JComponent c) { - c.paint(g); - } - - /** - * Dispatches {@code AWTEvent}s for {@code JXLayer} - * and all it subcomponents to this {@code LayerUI}. - *

      - * To enable the {@code AWTEvent} of particular type, - * you should call {@link JXLayer#setLayerEventMask} - * in {@link #installUI(javax.swing.JComponent)} - * and set the layer event mask to {@code 0} - * in {@link #uninstallUI(javax.swing.JComponent)} after that - * - * @param e the event to be dispatched - * @param l the layer this LayerUI is set to - * @see JXLayer#setLayerEventMask(long) - * @see JXLayer#getLayerEventMask() - */ - public void eventDispatched(AWTEvent e, JXLayer l) { - } - - /** - * Invoked when {@link JXLayer#updateUI()} is called - * from the {@code JXLayer} this {@code LayerUI} is set to. - * - * @param l the {@code JXLayer} which UI is updated - */ - public void updateUI(JXLayer l) { - } - - /** - * Configures the {@code JXLayer} this {@code LayerUI} is set to. - * The default implementation registers the {@code LayerUI} - * as a property change listener for the passed {@code JXLayer} - * - * @param c the {@code JXLayer} where this UI delegate is being installed - */ - public void installUI(JComponent c) { - addPropertyChangeListener((JXLayer) c); - } - - /** - * {@inheritDoc} - */ - public void uninstallUI(JComponent c) { - removePropertyChangeListener((JXLayer) c); - } - - /** - * Adds a PropertyChangeListener to the listener list. The listener is - * registered for all bound properties of this class. - *

      - * If listener is null, - * no exception is thrown and no action is performed. - * - * @param listener the property change listener to be added - * @see #removePropertyChangeListener - * @see #getPropertyChangeListeners - * @see #addPropertyChangeListener(String, java.beans.PropertyChangeListener) - */ - public void addPropertyChangeListener(PropertyChangeListener listener) { - propertyChangeSupport.addPropertyChangeListener(listener); - } - - /** - * Removes a PropertyChangeListener from the listener list. This method - * should be used to remove PropertyChangeListeners that were registered - * for all bound properties of this class. - *

      - * If listener is null, no exception is thrown and no action is performed. - * - * @param listener the PropertyChangeListener to be removed - * @see #addPropertyChangeListener - * @see #getPropertyChangeListeners - * @see #removePropertyChangeListener(String, PropertyChangeListener) - */ - public void removePropertyChangeListener(PropertyChangeListener listener) { - propertyChangeSupport.removePropertyChangeListener(listener); - } - - /** - * Returns an array of all the property change listeners - * registered on this component. - * - * @return all of this ui's PropertyChangeListeners - * or an empty array if no property change - * listeners are currently registered - * @see #addPropertyChangeListener - * @see #removePropertyChangeListener - * @see #getPropertyChangeListeners(String) - */ - public PropertyChangeListener[] getPropertyChangeListeners() { - return propertyChangeSupport.getPropertyChangeListeners(); - } - - /** - * Adds a PropertyChangeListener to the listener list for a specific - * property. - *

      - * If propertyName or listener is null, - * no exception is thrown and no action is taken. - * - * @param propertyName one of the property names listed above - * @param listener the property change listener to be added - * @see #removePropertyChangeListener(String, PropertyChangeListener) - * @see #getPropertyChangeListeners(String) - * @see #addPropertyChangeListener(String, PropertyChangeListener) - */ - public void addPropertyChangeListener(String propertyName, - PropertyChangeListener listener) { - propertyChangeSupport.addPropertyChangeListener(propertyName, listener); - } - - /** - * Removes a PropertyChangeListener from the listener - * list for a specific property. This method should be used to remove - * PropertyChangeListeners - * that were registered for a specific bound property. - *

      - * If propertyName or listener is null, - * no exception is thrown and no action is taken. - * - * @param propertyName a valid property name - * @param listener the PropertyChangeListener to be removed - * @see #addPropertyChangeListener(String, PropertyChangeListener) - * @see #getPropertyChangeListeners(String) - * @see #removePropertyChangeListener(PropertyChangeListener) - */ - public void removePropertyChangeListener(String propertyName, - PropertyChangeListener listener) { - propertyChangeSupport.removePropertyChangeListener(propertyName, listener); - } - - /** - * Returns an array of all the listeners which have been associated - * with the named property. - * - * @return all of the PropertyChangeListeners associated with - * the named property; if no such listeners have been added or - * if propertyName is null, an empty - * array is returned - * @see #addPropertyChangeListener(String, PropertyChangeListener) - * @see #removePropertyChangeListener(String, PropertyChangeListener) - * @see #getPropertyChangeListeners - */ - public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { - return propertyChangeSupport.getPropertyChangeListeners(propertyName); - } - - /** - * Support for reporting bound property changes for Object properties. - * This method can be called when a bound property has changed and it will - * send the appropriate PropertyChangeEvent to any registered - * PropertyChangeListeners. - * - * @param propertyName the property whose value has changed - * @param oldValue the property's previous value - * @param newValue the property's new value - */ - protected void firePropertyChange(String propertyName, - Object oldValue, Object newValue) { - propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); - } - - /** - * Notifies the {@code LayerUI} when any of its property is changed - * and allows to update every {@code JXLayer} this {@code LayerUI} is set to. - * - * @param evt the PropertyChangeEvent generated by this {@code LayerUI} - * @param l the {@code JXLayer} this LayerUI is set to - */ - public void handlePropertyChangeEvent(PropertyChangeEvent evt, JXLayer l) { - } - - /** - * Returns the preferred size of the viewport for a view component. - * - * @return the preferred size of the viewport for a view component - * @see Scrollable#getPreferredScrollableViewportSize () - */ - public Dimension getPreferredScrollableViewportSize(JXLayer l) { - if (l.getView() instanceof Scrollable) { - return ((Scrollable) l.getView()).getPreferredScrollableViewportSize(); - } - return l.getPreferredSize(); - } - - /** - * Components that display logical rows or columns should compute - * the scroll increment that will completely expose one block - * of rows or columns, depending on the value of orientation. - * - * @return the "block" increment for scrolling in the specified direction - * @see Scrollable#getScrollableBlockIncrement(Rectangle, int, int) - */ - public int getScrollableBlockIncrement(JXLayer l, - Rectangle visibleRect, - int orientation, int direction) { - if (l.getView() instanceof Scrollable) { - return ((Scrollable) l.getView()).getScrollableBlockIncrement( - visibleRect, orientation, direction); - } - return (orientation == SwingConstants.VERTICAL) ? visibleRect.height : - visibleRect.width; - } - - /** - * Returns false to indicate that the height of the viewport does not - * determine the height of the layer, unless the preferred height - * of the layer is smaller than the viewports height. - * - * @return whether the layer should track the height of the viewport - * @see Scrollable#getScrollableTracksViewportHeight() - */ - public boolean getScrollableTracksViewportHeight(JXLayer l) { - if (l.getView() instanceof Scrollable) { - return ((Scrollable) l.getView()).getScrollableTracksViewportHeight(); - } - if (l.getParent() instanceof JViewport) { - return (((JViewport) l.getParent()).getHeight() > l.getPreferredSize().height); - } - return false; - } - - /** - * Returns false to indicate that the width of the viewport does not - * determine the width of the layer, unless the preferred width - * of the layer is smaller than the viewports width. - * - * @return whether the layer should track the width of the viewport - * @see Scrollable - * @see LayerUI#getScrollableTracksViewportWidth(JXLayer) - */ - public boolean getScrollableTracksViewportWidth(JXLayer l) { - if (l.getView() instanceof Scrollable) { - return ((Scrollable) l.getView()).getScrollableTracksViewportWidth(); - } - if (l.getParent() instanceof JViewport) { - return (((JViewport) l.getParent()).getWidth() > l.getPreferredSize().width); - } - return false; - } - - /** - * Components that display logical rows or columns should compute - * the scroll increment that will completely expose one new row - * or column, depending on the value of orientation. Ideally, - * components should handle a partially exposed row or column by - * returning the distance required to completely expose the item. - *

      - * Scrolling containers, like JScrollPane, will use this method - * each time the user requests a unit scroll. - * - * @return The "unit" increment for scrolling in the specified direction. - * This value should always be positive. - * @see Scrollable#getScrollableUnitIncrement(Rectangle, int, int) - */ - public int getScrollableUnitIncrement(JXLayer l, - Rectangle visibleRect, - int orientation, int direction) { - if (l.getView() instanceof Scrollable) { - return ((Scrollable) l.getView()).getScrollableUnitIncrement( - visibleRect, orientation, direction); - } - return 1; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/Launcher.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/Launcher.java deleted file mode 100644 index 13fe541b0a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/Launcher.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.viewer; - -import org.icepdf.core.util.Defs; -import org.icepdf.ri.common.ViewModel; -import org.icepdf.ri.util.FontPropertiesManager; -import org.icepdf.ri.util.PropertiesManager; -import org.icepdf.ri.util.URLAccess; - -import javax.swing.*; -import java.text.MessageFormat; -import java.util.Properties; -import java.util.ResourceBundle; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - *

      Launches the Viewer Application. The following parameters can be used - * to optionally load a PDF document at startup.

      - * - * - * - * - * - * - * - * - * - * - * - * - * - *
      OptionDescription
      -loadfile filenameStarts the ICEpdf Viewer and displays the specified local PDF file. - * Use the following syntax:
      - * -loadfile c:/examplepath/file.pdf
      -loadfile filenameStarts the ICEpdf Viewer and displays the PDF file at the specified - * URL. Use the following syntax:
      - * -loadurl http://www.examplesite.com/file.pdf
      - */ -public class Launcher { - - private static final Logger logger = - Logger.getLogger(Launcher.class.toString()); - - // manages open windows - public static WindowManager windowManager; - // stores properties used by ICEpdf - private static PropertiesManager propertiesManager; - - public static void main(String[] argv) { - - boolean brokenUsage = false; - - String contentURL = ""; - String contentFile = ""; - String contentProperties = null; - // parse command line arguments - for (int i = 0; i < argv.length; i++) { - if (i == argv.length - 1) { //each argument requires another - brokenUsage = true; - break; - } - String arg = argv[i]; - if (arg.equals("-loadfile")) { - contentFile = argv[++i].trim(); - } else if (arg.equals("-loadurl")) { - contentURL = argv[++i].trim(); - } else if (arg.equals("-loadproperties")) { - contentProperties = argv[++i].trim(); - } else { - brokenUsage = true; - break; - } - } - - // load message bundle - ResourceBundle messageBundle = ResourceBundle.getBundle( - PropertiesManager.DEFAULT_MESSAGE_BUNDLE); - - // Quit if there where any problems parsing the command line arguments - if (brokenUsage) { - System.out.println(messageBundle.getString("viewer.commandLin.error")); - System.exit(1); - } - // start the viewer - run(contentFile, contentURL, contentProperties, messageBundle); - } - - /** - * Starts the viewe application. - * - * @param contentFile URI of a file which will be loaded at runtime, can be - * null. - * @param contentURL URL of a file which will be loaded at runtime, can be - * null. - * @param contentProperties URI of a properties file which will be used in - * place of the default path - * @param messageBundle messageBundle to pull strings from - */ - private static void run(String contentFile, - String contentURL, - String contentProperties, - ResourceBundle messageBundle) { - - // initiate the properties manager. - Properties sysProps = System.getProperties(); - propertiesManager = new PropertiesManager(sysProps, contentProperties, messageBundle); - - // initiate font Cache manager, reads system font data and stores summary - // information in a properties file. If new font are added to the OS - // then the properties file can be deleted to initiate a re-read of the - // font data. - new FontPropertiesManager(propertiesManager, sysProps, messageBundle); - - // input new System properties - System.setProperties(sysProps); - - // set look & feel - setupLookAndFeel(messageBundle); - - ViewModel.setDefaultFilePath(propertiesManager.getDefaultFilePath()); - ViewModel.setDefaultURL(propertiesManager.getDefaultURL()); - - - // application instance - windowManager = WindowManager.createInstance(propertiesManager, messageBundle); - if (contentFile != null && contentFile.length() > 0) { - windowManager.newWindow(contentFile); - ViewModel.setDefaultFilePath(contentFile); - } - - // load a url if specified - if (contentURL != null && contentURL.length() > 0) { - URLAccess urlAccess = URLAccess.doURLAccess(contentURL); - urlAccess.closeConnection(); - if (urlAccess.errorMessage != null) { - - // setup a patterned message - Object[] messageArguments = {urlAccess.errorMessage, - urlAccess.urlLocation - }; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.launcher.URLError.dialog.message")); - - JOptionPane.showMessageDialog( - null, - formatter.format(messageArguments), - messageBundle.getString("viewer.launcher.URLError.dialog.title"), - JOptionPane.INFORMATION_MESSAGE); - } else { - windowManager.newWindow(urlAccess.url); - } - ViewModel.setDefaultURL(urlAccess.urlLocation); - urlAccess.dispose(); - } - - // Start an empy viewer if there was no command line parameters - if (((contentFile == null || contentFile.length() == 0) && - (contentURL == null || contentURL.length() == 0)) - || (windowManager.getNumberOfWindows() == 0) - ) { - windowManager.newWindow(""); - } - } - - /** - * If a L&F has been specifically set then try and use it. If not - * then resort to the 'native' system L&F. - * - * @param messageBundle - */ - private static void setupLookAndFeel(ResourceBundle messageBundle) { - - // Do Mac related-setup (if running on a Mac) - if (Defs.sysProperty("mrj.version") != null) { - // Running on a mac - // take the menu bar off the jframe - Defs.setSystemProperty("apple.laf.useScreenMenuBar", "true"); - // set the name of the application menu item (must precede the L&F setup) - String appName = messageBundle.getString("viewer.window.title.default"); - Defs.setSystemProperty("com.apple.mrj.application.apple.menu.about.name", appName); - } - - String className = - propertiesManager.getLookAndFeel("application.lookandfeel", - null); - - if (className != null) { - try { - UIManager.setLookAndFeel(className); - return; - } catch (Exception e) { - - // setup a patterned message - Object[] messageArguments = { - propertiesManager.getString("application.lookandfeel") - }; - MessageFormat formatter = new MessageFormat( - messageBundle.getString("viewer.launcher.URLError.dialog.message")); - - // Error - unsupported L&F (probably windows) - JOptionPane.showMessageDialog( - null, - formatter.format(messageArguments), - messageBundle.getString("viewer.launcher.lookAndFeel.error.message"), - JOptionPane.ERROR_MESSAGE); - - } - } - - try { - String defaultLF = UIManager.getSystemLookAndFeelClassName(); - UIManager.setLookAndFeel(defaultLF); - } catch (Exception e) { - logger.log(Level.FINE, "Error setting Swing Look and Feel.", e); - } - - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/Main.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/Main.java deleted file mode 100644 index bce98c2fa1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/Main.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.viewer; - -import org.icepdf.ri.images.Images; - -import javax.swing.*; -import java.awt.*; -import java.net.URL; - -/** - *

      This class is the Main class for the ICEpdf Viewer application. It does - * the following tasks:

      - *
        - *
      • Presents a splash window - *
      • Loads the viewer application - *
      - * - * @since 1.0 - */ -public class Main { - - private static SplashWindow splashWindow = null; - - public static void main(final String[] args) { - // Read the image data and display the splash screen - URL imageURL = Images.get("icepdf-splash.png"); - - if (imageURL != null) { - Image splashImage = - Toolkit.getDefaultToolkit().getImage(imageURL); - if (splashImage != null) { - splashWindow = new SplashWindow(splashImage); - splashWindow.splash(); - } - } - - // Call the main method of the application's Main class - // using Reflection so that related classes resoving happens - // after splash window is shown up - SwingUtilities.invokeLater(new Runnable() { - public void run() { - try { - Class.forName("org.icepdf.ri.viewer.Launcher") - .getMethod("main", String[].class) - .invoke(null, new Object[]{args}); - } catch (Throwable e) { - e.printStackTrace(); - System.err.flush(); - System.exit(10); - } - } - }); - - // Dispose the splash screen - if (splashWindow != null) { - splashWindow.dispose(); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/SplashWindow.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/SplashWindow.java deleted file mode 100644 index ae20130069..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/SplashWindow.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.viewer; - -import javax.swing.*; -import java.awt.*; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Construct a JWindow, paints a splash image, and centers the frame on the - * screen. - * - * @author Icesoft Technologies. - */ -@SuppressWarnings("serial") -final class SplashWindow extends JWindow { - - private static final Logger logger = - Logger.getLogger(SplashWindow.class.toString()); - - private Image splashImage; - private MediaTracker mediaTracker; - - /** - * Constructs a splash window and takes splash image - * - * @param image The splash image to be displayed - */ - public SplashWindow(Image image) { - splashImage = image; - } - - /** - * Shows splash screen and centers it on screen - */ - public void splash() { - mediaTracker = new MediaTracker(this); - setSize(splashImage.getWidth(null), splashImage.getHeight(null)); - - mediaTracker.addImage(splashImage, 0); - try { - mediaTracker.waitForID(0); - } catch (InterruptedException ex) { - logger.log(Level.FINE, "Failed to track splash image load.", ex); - } - - setSize(splashImage.getWidth(null), splashImage.getHeight(null)); - center(); - setVisible(true); - } - - /** - * Centers this frame on the screen. - */ - private void center() { - Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); - Rectangle frame = getBounds(); - setLocation((screen.width - frame.width) / 2, - (screen.height - frame.height) / 2); - } - - /** - * Paint the splash image to the frame - */ - public void paint(Graphics graphics) { - if (splashImage != null) { - graphics.drawImage(splashImage, 0, 0, this); - } - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/WindowManager.java b/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/WindowManager.java deleted file mode 100644 index 81b536353e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/icepdf/ri/viewer/WindowManager.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright 2006-2017 ICEsoft Technologies Canada Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an "AS - * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.icepdf.ri.viewer; - -import org.icepdf.core.pobjects.Document; -import org.icepdf.core.util.Defs; -import org.icepdf.ri.common.*; -import org.icepdf.ri.common.views.DocumentViewController; -import org.icepdf.ri.common.views.DocumentViewControllerImpl; -import org.icepdf.ri.util.PropertiesManager; - -import javax.swing.*; -import java.awt.*; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.ResourceBundle; - -/** - * An implementation of WindowManagementCallback to manage the viewer applications - * windows. - * - * @since 1.0 - */ -public class WindowManager implements WindowManagementCallback { - - private static WindowManager windowManager; - - private PropertiesManager properties; - - private ArrayList controllers; - - private long newWindowInvocationCounter = 0; - - private ResourceBundle messageBundle = null; - - private WindowManager() { - } - - public static WindowManager getInstance() { - return windowManager; - } - - //window management functions - public static WindowManager createInstance(PropertiesManager properties, ResourceBundle messageBundle) { - - windowManager = new WindowManager(); - windowManager.properties = properties; - windowManager.controllers = new ArrayList(); - - if (messageBundle != null) { - windowManager.messageBundle = messageBundle; - } else { - windowManager.messageBundle = ResourceBundle.getBundle( - PropertiesManager.DEFAULT_MESSAGE_BUNDLE); - } - - // Annouce ourselves... - if (Defs.booleanProperty("org.icepdf.core.verbose", true)) { - System.out.println("\nICEsoft ICEpdf Viewer " + Document.getLibraryVersion()); - System.out.println("Copyright ICEsoft Technologies, Inc.\n"); - } - return windowManager; - } - - public PropertiesManager getProperties() { - return properties; - } - - public long getNumberOfWindows() { - return newWindowInvocationCounter; - } - - - public void newWindow(final String location) { - SwingController controller = commonWindowCreation(); - controller.openDocument(location); - } - - public void newWindow(final Document document, final String fileName) { - SwingController controller = commonWindowCreation(); - controller.openDocument(document, fileName); - } - - public void newWindow(URL location) { - SwingController controller = commonWindowCreation(); - controller.openDocument(location); - } - - protected SwingController commonWindowCreation() { - SwingController controller = new SwingController(messageBundle); - controller.setWindowManagementCallback(this); - - // assign properties manager. - controller.setPropertiesManager(properties); - - // add interactive mouse link annotation support - controller.getDocumentViewController().setAnnotationCallback( - new MyAnnotationCallback(controller.getDocumentViewController())); - - controllers.add(controller); - // guild a new swing viewer with remembered view settings. - int viewType = DocumentViewControllerImpl.ONE_PAGE_VIEW; - int pageFit = DocumentViewController.PAGE_FIT_WINDOW_WIDTH; - try { - viewType = getProperties().getInt("document.viewtype", - DocumentViewControllerImpl.ONE_PAGE_VIEW); - pageFit = getProperties().getInt( - PropertiesManager.PROPERTY_DEFAULT_PAGEFIT, - DocumentViewController.PAGE_FIT_WINDOW_WIDTH); - } catch (NumberFormatException e) { - // eating error, as we can continue with out alarm - } - - SwingViewBuilder factory = - new SwingViewBuilder(controller, viewType, pageFit); - - JFrame frame = factory.buildViewerFrame(); - if (frame != null) { - int width = getProperties().getInt("application.width", 800); - int height = getProperties().getInt("application.height", 600); - frame.setSize(width, height); - - int x = getProperties().getInt("application.x", 1); - int y = getProperties().getInt("application.y", 1); - - frame.setLocation((int) (x + (newWindowInvocationCounter * 10)), - (int) (y + (newWindowInvocationCounter * 10))); - ++newWindowInvocationCounter; - frame.setVisible(true); - } - - return controller; - } - - public void disposeWindow(SwingController controller, JFrame viewer, - Properties properties) { - if (controllers.size() <= 1) { - quit(controller, viewer, properties); - return; - } - - //gets the window to close from the list - int index = controllers.indexOf(controller); - if (index >= 0) { - controllers.remove(index); - newWindowInvocationCounter--; - if (viewer != null) { - viewer.setVisible(false); - viewer.dispose(); - } - } - } - - public void quit(SwingController controller, JFrame viewer, - Properties properties) { - if (controller != null && viewer != null) { - //save width & height - Rectangle sz = viewer.getBounds(); - getProperties().setInt("application.x", sz.x); - getProperties().setInt("application.y", sz.y); - getProperties().setInt("application.height", sz.height); - getProperties().setInt("application.width", sz.width); - if (properties != null) { - getProperties().set(PropertiesManager.PROPERTY_DEFAULT_PAGEFIT, - properties.getProperty(PropertiesManager.PROPERTY_DEFAULT_PAGEFIT)); - int viewType = Integer.parseInt(properties.getProperty("document.viewtype")); - // don't save the attachments view as it only applies to specific - // document types. - if (viewType != DocumentViewControllerImpl.USE_ATTACHMENTS_VIEW) { - getProperties().set("document.viewtype", - properties.getProperty("document.viewtype")); - } - } - getProperties().setDefaultFilePath(ViewModel.getDefaultFilePath()); - getProperties().setDefaultURL(ViewModel.getDefaultURL()); - } - - // save all the rest, cookies, bookmarks, etc. - getProperties().saveAndEnd(); - - // make sure all the controllers have been disposed. - for (SwingController c : controllers) { - if (c == null) - continue; - c.dispose(); - } - - System.exit(0); - } - - public void minimiseAllWindows() { - for (SwingController controller : controllers) { - JFrame frame = controller.getViewerFrame(); - if (frame != null) - frame.setState(Frame.ICONIFIED); - } - } - - public void bringAllWindowsToFront(SwingController frontMost) { - JFrame frontMostFrame = null; - for (SwingController controller : controllers) { - JFrame frame = controller.getViewerFrame(); - if (frame != null) { - if (frontMost == controller) { - frontMostFrame = frame; - continue; - } - frame.setState(Frame.NORMAL); - frame.toFront(); - } - } - if (frontMostFrame != null) { - frontMostFrame.setState(Frame.NORMAL); - frontMostFrame.toFront(); - } - } - - public void bringWindowToFront(int index) { - if (index >= 0 && index < controllers.size()) { - SwingController controller = controllers.get(index); - JFrame frame = controller.getViewerFrame(); - if (frame != null) { - frame.setState(Frame.NORMAL); - frame.toFront(); - } - } - } - - /** - * As long as no windows have openned or closed, then the indexes in the - * returned list should still be valid for doing operations on - * the respective Controller objects - * - * @param giveIndex Give this SwingControllers index in the list as an Integer appended to the List - * @return List of String objects, each representing an open Document's origin. The last element may be an Integer - */ - public List getWindowDocumentOriginList(SwingController giveIndex) { - Integer foundIndex = null; - int count = controllers.size(); - List list = new ArrayList(count + 1); - for (int i = 0; i < count; i++) { - Object toAdd = null; - SwingController controller = controllers.get(i); - if (giveIndex == controller) - foundIndex = i; - Document document = controller.getDocument(); - if (document != null) - toAdd = document.getDocumentOrigin(); - list.add(toAdd); - } - if (foundIndex != null) - list.add(foundIndex); - return list; - } - - void updateUI() { - for (SwingController controller : controllers) { - JFrame frame = controller.getViewerFrame(); - if (frame != null) - SwingUtilities.updateComponentTreeUI(frame); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/JBIG2Decoder.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/JBIG2Decoder.java deleted file mode 100644 index c3d18eb18f..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/JBIG2Decoder.java +++ /dev/null @@ -1,244 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== -* -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* JBIG2Decoder.java -* --------------- - */ -package org.jpedal.jbig2; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.image.JBIG2Bitmap; -import org.jpedal.jbig2.segment.Segment; -import org.jpedal.jbig2.segment.pageinformation.PageInformationSegment; - -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferByte; -import java.io.*; -import java.util.Iterator; -import java.util.List; - -public class JBIG2Decoder { - - private JBIG2StreamDecoder streamDecoder; - - /** - * Constructor - */ - public JBIG2Decoder() { - streamDecoder = new JBIG2StreamDecoder(); - } - - /** - * If the data stream is taken from a PDF, there may be some global data. Pass any global data - * in here. Call this method before decodeJBIG2(...) - * - * @param data global data - * @throws IOException - * @throws JBIG2Exception - */ - public void setGlobalData(byte[] data) throws IOException, JBIG2Exception { - streamDecoder.setGlobalData(data); - } - - /** - * Decodes a JBIG2 image from a File object - * - * @param file File to decode - * @throws IOException - * @throws JBIG2Exception - */ - public void decodeJBIG2(File file) throws IOException, JBIG2Exception { - decodeJBIG2(file.getAbsolutePath()); - } - - /** - * Decodes a JBIG2 image from a String path - * - * @param file Must be the full path to the image - * @throws IOException - * @throws JBIG2Exception - */ - public void decodeJBIG2(String file) throws IOException, JBIG2Exception { - decodeJBIG2(new FileInputStream(file)); - } - - /** - * Decodes a JBIG2 image from an InputStream - * - * @param inputStream InputStream - * @throws IOException - * @throws JBIG2Exception - */ - public void decodeJBIG2(InputStream inputStream) throws IOException, JBIG2Exception { - int availiable = inputStream.available(); - - byte[] bytes = new byte[availiable]; - inputStream.read(bytes); - - decodeJBIG2(bytes); - } - - /** - * Decodes a JBIG2 image from a DataInput - * - * @param dataInput DataInput - * @throws IOException - * @throws JBIG2Exception - */ - public void decodeJBIG2(DataInput dataInput) throws IOException, JBIG2Exception { -// long availiable = inputStream.length(); -// -// byte[] bytes = new byte[availiable]; -// inputStream.read(bytes); -// -// decodeJBIG2(bytes); - } - - /** - * Decodes a JBIG2 image from a byte array - * - * @param data the raw data stream - * @throws IOException - * @throws JBIG2Exception - */ - public void decodeJBIG2(byte[] data) throws IOException, JBIG2Exception { - streamDecoder.decodeJBIG2(data); - } - - public void cleanupPostDecode() { - streamDecoder.cleanupPostDecode(); - } - - /** - * @param page - * @return - */ - public BufferedImage getPageAsBufferedImage(int page) { - page++; - JBIG2Bitmap pageBitmap = streamDecoder.findPageSegement(page).getPageBitmap(); - - /* - * Initial optimisation attempt, replaced with further efforts, below - byte[] bytes = pageBitmap.getData(true); - - if (bytes == null) - return null; - - // make a a DEEP copy so we cant alter - //int len = bytes.length; - //byte[] copy = new byte[len]; - //System.arraycopy(bytes, 0, copy, 0, len); - - // Don't make a deep copy, since pageBitmap.getData(boolean) - // just allocated the byte[] for us - byte[] copy = bytes; - - // byte[] data = pageBitmap.getData(true).clone(); - int width = pageBitmap.getWidth(); - int height = pageBitmap.getHeight(); - - // create an image from the raw data - DataBuffer db = new DataBufferByte(copy, copy.length); - - WritableRaster raster = Raster.createPackedRaster(db, width, height, 1, null); - BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); - image.setData(raster); - */ - - - // byte[] data = pageBitmap.getData(true).clone(); - int width = pageBitmap.getWidth(); - int height = pageBitmap.getHeight(); - BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); - byte[] bytes = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); - pageBitmap.getData(bytes, true); - - return image; - } - - public boolean isNumberOfPagesKnown() { - return streamDecoder.isNumberOfPagesKnown(); - } - - public int getNumberOfPages() { - int pages = streamDecoder.getNumberOfPages(); - if (streamDecoder.isNumberOfPagesKnown() && pages != 0) - return pages; - - int noOfPages = 0; - - List segments = getAllSegments(); - for (Iterator it = segments.iterator(); it.hasNext(); ) { - Segment segment = (Segment) it.next(); - if (segment.getSegmentHeader().getSegmentType() == Segment.PAGE_INFORMATION) - noOfPages++; - } - - return noOfPages; - } - - public List getAllSegments() { - return streamDecoder.getAllSegments(); - } - - public PageInformationSegment findPageSegement(int page) { - page++; - return streamDecoder.findPageSegement(page); - } - - public Segment findSegment(int segmentNumber) { - return streamDecoder.findSegment(segmentNumber); - } - - public JBIG2Bitmap getPageAsJBIG2Bitmap(int page) { - page++; - return streamDecoder.findPageSegement(page).getPageBitmap(); - } - - public boolean isRandomAccessOrganisationUsed() { - return streamDecoder.isRandomAccessOrganisationUsed(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/JBIG2Exception.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/JBIG2Exception.java deleted file mode 100644 index 56e6cd6215..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/JBIG2Exception.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * JBIG2Exception.java - * --------------- - */ -package org.jpedal.jbig2; - -@SuppressWarnings("serial") -public class JBIG2Exception extends Exception { - public JBIG2Exception(Exception ex) { - super(ex); - } - - /** - * Constructs a JBIGException whithout a message. - */ - - public JBIG2Exception() { - super(); - } - - /** - * Constructs a JBIGException with a message. - * - * @param message a message describing the exception - */ - - public JBIG2Exception(String message) { - super(message); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/ArithmeticDecoder.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/ArithmeticDecoder.java deleted file mode 100644 index 613183d4ae..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/ArithmeticDecoder.java +++ /dev/null @@ -1,339 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett - * -* This file is part of JPedal - * -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* ArithmeticDecoder.java -* --------------- - */ -package org.jpedal.jbig2.decoders; - -import org.jpedal.jbig2.io.StreamReader; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.io.IOException; - -public class ArithmeticDecoder { - - private StreamReader reader; - - public ArithmeticDecoderStats genericRegionStats, refinementRegionStats; - - public ArithmeticDecoderStats iadhStats, iadwStats, iaexStats, iaaiStats, iadtStats, iaitStats, iafsStats, iadsStats, iardxStats, iardyStats, iardwStats, iardhStats, iariStats, iaidStats; - - int contextSize[] = {16, 13, 10, 10}, referredToContextSize[] = {13, 10}; - - long buffer0, buffer1; - long c, a; - long previous; - - int counter; - - private ArithmeticDecoder() { - } - - public ArithmeticDecoder(StreamReader reader) { - this.reader = reader; - - genericRegionStats = new ArithmeticDecoderStats(1 << 1); - refinementRegionStats = new ArithmeticDecoderStats(1 << 1); - - iadhStats = new ArithmeticDecoderStats(1 << 9); - iadwStats = new ArithmeticDecoderStats(1 << 9); - iaexStats = new ArithmeticDecoderStats(1 << 9); - iaaiStats = new ArithmeticDecoderStats(1 << 9); - iadtStats = new ArithmeticDecoderStats(1 << 9); - iaitStats = new ArithmeticDecoderStats(1 << 9); - iafsStats = new ArithmeticDecoderStats(1 << 9); - iadsStats = new ArithmeticDecoderStats(1 << 9); - iardxStats = new ArithmeticDecoderStats(1 << 9); - iardyStats = new ArithmeticDecoderStats(1 << 9); - iardwStats = new ArithmeticDecoderStats(1 << 9); - iardhStats = new ArithmeticDecoderStats(1 << 9); - iariStats = new ArithmeticDecoderStats(1 << 9); - iaidStats = new ArithmeticDecoderStats(1 << 1); - } - - public void resetIntStats(int symbolCodeLength) { - iadhStats.reset(); - iadwStats.reset(); - iaexStats.reset(); - iaaiStats.reset(); - iadtStats.reset(); - iaitStats.reset(); - iafsStats.reset(); - iadsStats.reset(); - iardxStats.reset(); - iardyStats.reset(); - iardwStats.reset(); - iardhStats.reset(); - iariStats.reset(); - - if (iaidStats.getContextSize() == 1 << (symbolCodeLength + 1)) { - iaidStats.reset(); - } else { - iaidStats = new ArithmeticDecoderStats(1 << (symbolCodeLength + 1)); - } - } - - public void resetGenericStats(int template, ArithmeticDecoderStats previousStats) { - int size = contextSize[template]; - - if (previousStats != null && previousStats.getContextSize() == size) { - if (genericRegionStats.getContextSize() == size) { - genericRegionStats.overwrite(previousStats); - } else { - genericRegionStats = previousStats.copy(); - } - } else { - if (genericRegionStats.getContextSize() == size) { - genericRegionStats.reset(); - } else { - genericRegionStats = new ArithmeticDecoderStats(1 << size); - } - } - } - - public void resetRefinementStats(int template, ArithmeticDecoderStats previousStats) { - int size = referredToContextSize[template]; - if (previousStats != null && previousStats.getContextSize() == size) { - if (refinementRegionStats.getContextSize() == size) { - refinementRegionStats.overwrite(previousStats); - } else { - refinementRegionStats = previousStats.copy(); - } - } else { - if (refinementRegionStats.getContextSize() == size) { - refinementRegionStats.reset(); - } else { - refinementRegionStats = new ArithmeticDecoderStats(1 << size); - } - } - } - - public void start() throws IOException { - buffer0 = reader.readByte(); - buffer1 = reader.readByte(); - - c = BinaryOperation.bit32Shift((buffer0 ^ 0xff), 16, BinaryOperation.LEFT_SHIFT); - readByte(); - c = BinaryOperation.bit32Shift(c, 7, BinaryOperation.LEFT_SHIFT); - counter -= 7; - a = 0x80000000l; - } - - public DecodeIntResult decodeInt(ArithmeticDecoderStats stats) throws IOException { - long value; - - previous = 1; - int s = decodeIntBit(stats); - if (decodeIntBit(stats) != 0) { - if (decodeIntBit(stats) != 0) { - if (decodeIntBit(stats) != 0) { - if (decodeIntBit(stats) != 0) { - if (decodeIntBit(stats) != 0) { - value = 0; - for (int i = 0; i < 32; i++) { - value = BinaryOperation.bit32Shift(value, 1, BinaryOperation.LEFT_SHIFT) | decodeIntBit(stats); - } - value += 4436; - } else { - value = 0; - for (int i = 0; i < 12; i++) { - value = BinaryOperation.bit32Shift(value, 1, BinaryOperation.LEFT_SHIFT) | decodeIntBit(stats); - } - value += 340; - } - } else { - value = 0; - for (int i = 0; i < 8; i++) { - value = BinaryOperation.bit32Shift(value, 1, BinaryOperation.LEFT_SHIFT) | decodeIntBit(stats); - } - value += 84; - } - } else { - value = 0; - for (int i = 0; i < 6; i++) { - value = BinaryOperation.bit32Shift(value, 1, BinaryOperation.LEFT_SHIFT) | decodeIntBit(stats); - } - value += 20; - } - } else { - value = decodeIntBit(stats); - value = BinaryOperation.bit32Shift(value, 1, BinaryOperation.LEFT_SHIFT) | decodeIntBit(stats); - value = BinaryOperation.bit32Shift(value, 1, BinaryOperation.LEFT_SHIFT) | decodeIntBit(stats); - value = BinaryOperation.bit32Shift(value, 1, BinaryOperation.LEFT_SHIFT) | decodeIntBit(stats); - value += 4; - } - } else { - value = decodeIntBit(stats); - value = BinaryOperation.bit32Shift(value, 1, BinaryOperation.LEFT_SHIFT) | decodeIntBit(stats); - } - - int decodedInt; - if (s != 0) { - if (value == 0) { - return new DecodeIntResult((int) value, false); - } - decodedInt = (int) -value; - } else { - decodedInt = (int) value; - } - - return new DecodeIntResult(decodedInt, true); - } - - public long decodeIAID(long codeLen, ArithmeticDecoderStats stats) throws IOException { - previous = 1; - for (long i = 0; i < codeLen; i++) { - int bit = decodeBit(previous, stats); - previous = BinaryOperation.bit32Shift(previous, 1, BinaryOperation.LEFT_SHIFT) | bit; - } - - return previous - (1 << codeLen); - } - - public int decodeBit(long context, ArithmeticDecoderStats stats) throws IOException { - int iCX = BinaryOperation.bit8Shift(stats.getContextCodingTableValue((int) context), 1, BinaryOperation.RIGHT_SHIFT); - int mpsCX = stats.getContextCodingTableValue((int) context) & 1; - int qe = qeTable[iCX]; - - a -= qe; - - int bit; - if (c < a) { - if ((a & 0x80000000) != 0) { - bit = mpsCX; - } else { - if (a < qe) { - bit = 1 - mpsCX; - if (switchTable[iCX] != 0) { - stats.setContextCodingTableValue((int) context, (nlpsTable[iCX] << 1) | (1 - mpsCX)); - } else { - stats.setContextCodingTableValue((int) context, (nlpsTable[iCX] << 1) | mpsCX); - } - } else { - bit = mpsCX; - stats.setContextCodingTableValue((int) context, (nmpsTable[iCX] << 1) | mpsCX); - } - do { - if (counter == 0) { - readByte(); - } - - a = BinaryOperation.bit32Shift(a, 1, BinaryOperation.LEFT_SHIFT); - c = BinaryOperation.bit32Shift(c, 1, BinaryOperation.LEFT_SHIFT); - - counter--; - } while ((a & 0x80000000) == 0); - } - } else { - c -= a; - - if (a < qe) { - bit = mpsCX; - stats.setContextCodingTableValue((int) context, (nmpsTable[iCX] << 1) | mpsCX); - } else { - bit = 1 - mpsCX; - if (switchTable[iCX] != 0) { - stats.setContextCodingTableValue((int) context, (nlpsTable[iCX] << 1) | (1 - mpsCX)); - } else { - stats.setContextCodingTableValue((int) context, (nlpsTable[iCX] << 1) | mpsCX); - } - } - a = qe; - - do { - if (counter == 0) { - readByte(); - } - - a = BinaryOperation.bit32Shift(a, 1, BinaryOperation.LEFT_SHIFT); - c = BinaryOperation.bit32Shift(c, 1, BinaryOperation.LEFT_SHIFT); - - counter--; - } while ((a & 0x80000000) == 0); - } - return bit; - } - - private void readByte() throws IOException { - if (buffer0 == 0xff) { - if (buffer1 > 0x8f) { - counter = 8; - } else { - buffer0 = buffer1; - buffer1 = reader.readByte(); - c = c + 0xfe00 - (BinaryOperation.bit32Shift(buffer0, 9, BinaryOperation.LEFT_SHIFT)); - counter = 7; - } - } else { - buffer0 = buffer1; - buffer1 = reader.readByte(); - c = c + 0xff00 - (BinaryOperation.bit32Shift(buffer0, 8, BinaryOperation.LEFT_SHIFT)); - counter = 8; - } - } - - private int decodeIntBit(ArithmeticDecoderStats stats) throws IOException { - int bit; - - bit = decodeBit(previous, stats); - if (previous < 0x100) { - previous = BinaryOperation.bit32Shift(previous, 1, BinaryOperation.LEFT_SHIFT) | bit; - } else { - previous = (((BinaryOperation.bit32Shift(previous, 1, BinaryOperation.LEFT_SHIFT)) | bit) & 0x1ff) | 0x100; - } - return bit; - } - - int qeTable[] = {0x56010000, 0x34010000, 0x18010000, 0x0AC10000, 0x05210000, 0x02210000, 0x56010000, 0x54010000, 0x48010000, 0x38010000, 0x30010000, 0x24010000, 0x1C010000, 0x16010000, 0x56010000, 0x54010000, 0x51010000, 0x48010000, 0x38010000, 0x34010000, 0x30010000, 0x28010000, 0x24010000, 0x22010000, 0x1C010000, 0x18010000, 0x16010000, 0x14010000, 0x12010000, 0x11010000, 0x0AC10000, 0x09C10000, 0x08A10000, 0x05210000, 0x04410000, 0x02A10000, 0x02210000, 0x01410000, 0x01110000, 0x00850000, 0x00490000, 0x00250000, 0x00150000, 0x00090000, 0x00050000, 0x00010000, - 0x56010000}; - - int nmpsTable[] = {1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46}; - - int nlpsTable[] = {1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46}; - - int switchTable[] = {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/ArithmeticDecoderStats.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/ArithmeticDecoderStats.java deleted file mode 100644 index 81ad278e4d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/ArithmeticDecoderStats.java +++ /dev/null @@ -1,96 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* ArithmeticDecoderStats.java -* --------------- - */ -package org.jpedal.jbig2.decoders; - -public class ArithmeticDecoderStats { - private int contextSize; - private int[] codingContextTable; - - public ArithmeticDecoderStats(int contextSize) { - this.contextSize = contextSize; - this.codingContextTable = new int[contextSize]; - - reset(); - } - - public void reset() { - for (int i = 0; i < contextSize; i++) { - codingContextTable[i] = 0; - } - } - - public void setEntry(int codingContext, int i, int moreProbableSymbol) { - codingContextTable[codingContext] = (i << i) + moreProbableSymbol; - } - - public int getContextCodingTableValue(int index) { - return codingContextTable[index]; - } - - public void setContextCodingTableValue(int index, int value) { - codingContextTable[index] = value; - } - - public int getContextSize() { - return contextSize; - } - - public void overwrite(ArithmeticDecoderStats stats) { - System.arraycopy(stats.codingContextTable, 0, codingContextTable, 0, contextSize); - } - - public ArithmeticDecoderStats copy() { - ArithmeticDecoderStats stats = new ArithmeticDecoderStats(contextSize); - - System.arraycopy(codingContextTable, 0, stats.codingContextTable, 0, contextSize); - - return stats; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/DecodeIntResult.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/DecodeIntResult.java deleted file mode 100644 index c6d6665f61..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/DecodeIntResult.java +++ /dev/null @@ -1,69 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* DecodeIntResult.java -* --------------- - */ -package org.jpedal.jbig2.decoders; - -public class DecodeIntResult { - - private int intResult; - private boolean booleanResult; - - public DecodeIntResult(int intResult, boolean booleanResult) { - this.intResult = intResult; - this.booleanResult = booleanResult; - } - - public int intResult() { - return intResult; - } - - public boolean booleanResult() { - return booleanResult; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/HuffmanDecoder.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/HuffmanDecoder.java deleted file mode 100644 index d885bc4fc9..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/HuffmanDecoder.java +++ /dev/null @@ -1,168 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* HuffmanDecoder.java -* --------------- - */ -package org.jpedal.jbig2.decoders; - -import org.jpedal.jbig2.io.StreamReader; - -import java.io.IOException; - -public class HuffmanDecoder { - - public static int jbig2HuffmanLOW = 0xfffffffd; - public static int jbig2HuffmanOOB = 0xfffffffe; - public static int jbig2HuffmanEOT = 0xffffffff; - - private StreamReader reader; - - private static HuffmanDecoder ref; - - private HuffmanDecoder() { - } - - public HuffmanDecoder(StreamReader reader) { - this.reader = reader; - } - - public DecodeIntResult decodeInt(int[][] table) throws IOException { - int length = 0, prefix = 0; - - for (int i = 0; table[i][2] != jbig2HuffmanEOT; i++) { - for (; length < table[i][1]; length++) { - int bit = reader.readBit(); - prefix = (prefix << 1) | bit; - } - - if (prefix == table[i][3]) { - if (table[i][2] == jbig2HuffmanOOB) { - return new DecodeIntResult(-1, false); - } - int decodedInt; - if (table[i][2] == jbig2HuffmanLOW) { - int readBits = reader.readBits(32); - decodedInt = table[i][0] - readBits; - } else if (table[i][2] > 0) { - int readBits = reader.readBits(table[i][2]); - decodedInt = table[i][0] + readBits; - } else { - decodedInt = table[i][0]; - } - return new DecodeIntResult(decodedInt, true); - } - } - - return new DecodeIntResult(-1, false); - } - - public static int[][] buildTable(int[][] table, int length) { - int i, j, k, prefix; - int[] tab; - - for (i = 0; i < length; i++) { - for (j = i; j < length && table[j][1] == 0; j++) ; - - if (j == length) { - break; - } - for (k = j + 1; k < length; k++) { - if (table[k][1] > 0 && table[k][1] < table[j][1]) { - j = k; - } - } - if (j != i) { - tab = table[j]; - for (k = j; k > i; k--) { - table[k] = table[k - 1]; - } - table[i] = tab; - } - } - table[i] = table[length]; - - i = 0; - prefix = 0; - table[i++][3] = prefix++; - for (; table[i][2] != jbig2HuffmanEOT; i++) { - prefix <<= table[i][1] - table[i - 1][1]; - table[i][3] = prefix++; - } - - return table; - } - - public static int huffmanTableA[][] = {{0, 1, 4, 0x000}, {16, 2, 8, 0x002}, {272, 3, 16, 0x006}, {65808, 3, 32, 0x007}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableB[][] = {{0, 1, 0, 0x000}, {1, 2, 0, 0x002}, {2, 3, 0, 0x006}, {3, 4, 3, 0x00e}, {11, 5, 6, 0x01e}, {75, 6, 32, 0x03e}, {0, 6, jbig2HuffmanOOB, 0x03f}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableC[][] = {{0, 1, 0, 0x000}, {1, 2, 0, 0x002}, {2, 3, 0, 0x006}, {3, 4, 3, 0x00e}, {11, 5, 6, 0x01e}, {0, 6, jbig2HuffmanOOB, 0x03e}, {75, 7, 32, 0x0fe}, {-256, 8, 8, 0x0fe}, {-257, 8, jbig2HuffmanLOW, 0x0ff}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableD[][] = {{1, 1, 0, 0x000}, {2, 2, 0, 0x002}, {3, 3, 0, 0x006}, {4, 4, 3, 0x00e}, {12, 5, 6, 0x01e}, {76, 5, 32, 0x01f}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableE[][] = {{1, 1, 0, 0x000}, {2, 2, 0, 0x002}, {3, 3, 0, 0x006}, {4, 4, 3, 0x00e}, {12, 5, 6, 0x01e}, {76, 6, 32, 0x03e}, {-255, 7, 8, 0x07e}, {-256, 7, jbig2HuffmanLOW, 0x07f}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableF[][] = {{0, 2, 7, 0x000}, {128, 3, 7, 0x002}, {256, 3, 8, 0x003}, {-1024, 4, 9, 0x008}, {-512, 4, 8, 0x009}, {-256, 4, 7, 0x00a}, {-32, 4, 5, 0x00b}, {512, 4, 9, 0x00c}, {1024, 4, 10, 0x00d}, {-2048, 5, 10, 0x01c}, {-128, 5, 6, 0x01d}, {-64, 5, 5, 0x01e}, {-2049, 6, jbig2HuffmanLOW, 0x03e}, {2048, 6, 32, 0x03f}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableG[][] = {{-512, 3, 8, 0x000}, {256, 3, 8, 0x001}, {512, 3, 9, 0x002}, {1024, 3, 10, 0x003}, {-1024, 4, 9, 0x008}, {-256, 4, 7, 0x009}, {-32, 4, 5, 0x00a}, {0, 4, 5, 0x00b}, {128, 4, 7, 0x00c}, {-128, 5, 6, 0x01a}, {-64, 5, 5, 0x01b}, {32, 5, 5, 0x01c}, {64, 5, 6, 0x01d}, {-1025, 5, jbig2HuffmanLOW, 0x01e}, {2048, 5, 32, 0x01f}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableH[][] = {{0, 2, 1, 0x000}, {0, 2, jbig2HuffmanOOB, 0x001}, {4, 3, 4, 0x004}, {-1, 4, 0, 0x00a}, {22, 4, 4, 0x00b}, {38, 4, 5, 0x00c}, {2, 5, 0, 0x01a}, {70, 5, 6, 0x01b}, {134, 5, 7, 0x01c}, {3, 6, 0, 0x03a}, {20, 6, 1, 0x03b}, {262, 6, 7, 0x03c}, {646, 6, 10, 0x03d}, {-2, 7, 0, 0x07c}, {390, 7, 8, 0x07d}, {-15, 8, 3, 0x0fc}, {-5, 8, 1, 0x0fd}, {-7, 9, 1, 0x1fc}, {-3, 9, 0, 0x1fd}, {-16, 9, jbig2HuffmanLOW, 0x1fe}, {1670, 9, 32, 0x1ff}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableI[][] = {{0, 2, jbig2HuffmanOOB, 0x000}, {-1, 3, 1, 0x002}, {1, 3, 1, 0x003}, {7, 3, 5, 0x004}, {-3, 4, 1, 0x00a}, {43, 4, 5, 0x00b}, {75, 4, 6, 0x00c}, {3, 5, 1, 0x01a}, {139, 5, 7, 0x01b}, {267, 5, 8, 0x01c}, {5, 6, 1, 0x03a}, {39, 6, 2, 0x03b}, {523, 6, 8, 0x03c}, {1291, 6, 11, 0x03d}, {-5, 7, 1, 0x07c}, {779, 7, 9, 0x07d}, {-31, 8, 4, 0x0fc}, {-11, 8, 2, 0x0fd}, {-15, 9, 2, 0x1fc}, {-7, 9, 1, 0x1fd}, {-32, 9, jbig2HuffmanLOW, 0x1fe}, {3339, 9, 32, 0x1ff}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableJ[][] = {{-2, 2, 2, 0x000}, {6, 2, 6, 0x001}, {0, 2, jbig2HuffmanOOB, 0x002}, {-3, 5, 0, 0x018}, {2, 5, 0, 0x019}, {70, 5, 5, 0x01a}, {3, 6, 0, 0x036}, {102, 6, 5, 0x037}, {134, 6, 6, 0x038}, {198, 6, 7, 0x039}, {326, 6, 8, 0x03a}, {582, 6, 9, 0x03b}, {1094, 6, 10, 0x03c}, {-21, 7, 4, 0x07a}, {-4, 7, 0, 0x07b}, {4, 7, 0, 0x07c}, {2118, 7, 11, 0x07d}, {-5, 8, 0, 0x0fc}, {5, 8, 0, 0x0fd}, {-22, 8, jbig2HuffmanLOW, 0x0fe}, {4166, 8, 32, 0x0ff}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableK[][] = {{1, 1, 0, 0x000}, {2, 2, 1, 0x002}, {4, 4, 0, 0x00c}, {5, 4, 1, 0x00d}, {7, 5, 1, 0x01c}, {9, 5, 2, 0x01d}, {13, 6, 2, 0x03c}, {17, 7, 2, 0x07a}, {21, 7, 3, 0x07b}, {29, 7, 4, 0x07c}, {45, 7, 5, 0x07d}, {77, 7, 6, 0x07e}, {141, 7, 32, 0x07f}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableL[][] = {{1, 1, 0, 0x000}, {2, 2, 0, 0x002}, {3, 3, 1, 0x006}, {5, 5, 0, 0x01c}, {6, 5, 1, 0x01d}, {8, 6, 1, 0x03c}, {10, 7, 0, 0x07a}, {11, 7, 1, 0x07b}, {13, 7, 2, 0x07c}, {17, 7, 3, 0x07d}, {25, 7, 4, 0x07e}, {41, 8, 5, 0x0fe}, {73, 8, 32, 0x0ff}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableM[][] = {{1, 1, 0, 0x000}, {2, 3, 0, 0x004}, {7, 3, 3, 0x005}, {3, 4, 0, 0x00c}, {5, 4, 1, 0x00d}, {4, 5, 0, 0x01c}, {15, 6, 1, 0x03a}, {17, 6, 2, 0x03b}, {21, 6, 3, 0x03c}, {29, 6, 4, 0x03d}, {45, 6, 5, 0x03e}, {77, 7, 6, 0x07e}, {141, 7, 32, 0x07f}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableN[][] = {{0, 1, 0, 0x000}, {-2, 3, 0, 0x004}, {-1, 3, 0, 0x005}, {1, 3, 0, 0x006}, {2, 3, 0, 0x007}, {0, 0, jbig2HuffmanEOT, 0}}; - - public static int huffmanTableO[][] = {{0, 1, 0, 0x000}, {-1, 3, 0, 0x004}, {1, 3, 0, 0x005}, {-2, 4, 0, 0x00c}, {2, 4, 0, 0x00d}, {-4, 5, 1, 0x01c}, {3, 5, 1, 0x01d}, {-8, 6, 2, 0x03c}, {5, 6, 2, 0x03d}, {-24, 7, 4, 0x07c}, {9, 7, 4, 0x07d}, {-25, 7, jbig2HuffmanLOW, 0x07e}, {25, 7, 32, 0x07f}, {0, 0, jbig2HuffmanEOT, 0}}; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/JBIG2StreamDecoder.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/JBIG2StreamDecoder.java deleted file mode 100644 index a52037229a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/JBIG2StreamDecoder.java +++ /dev/null @@ -1,707 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * JBIG2StreamDecoder.java - * --------------- - */ -package org.jpedal.jbig2.decoders; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.image.JBIG2Bitmap; -import org.jpedal.jbig2.io.StreamReader; -import org.jpedal.jbig2.segment.Segment; -import org.jpedal.jbig2.segment.SegmentHeader; -import org.jpedal.jbig2.segment.extensions.ExtensionSegment; -import org.jpedal.jbig2.segment.pageinformation.PageInformationSegment; -import org.jpedal.jbig2.segment.pattern.PatternDictionarySegment; -import org.jpedal.jbig2.segment.region.generic.GenericRegionSegment; -import org.jpedal.jbig2.segment.region.halftone.HalftoneRegionSegment; -import org.jpedal.jbig2.segment.region.refinement.RefinementRegionSegment; -import org.jpedal.jbig2.segment.region.text.TextRegionSegment; -import org.jpedal.jbig2.segment.stripes.EndOfStripeSegment; -import org.jpedal.jbig2.segment.symboldictionary.SymbolDictionarySegment; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -public class JBIG2StreamDecoder { - - private StreamReader reader; - - private boolean noOfPagesKnown; - private boolean randomAccessOrganisation; - - private int noOfPages = -1; - - private List segments = new ArrayList(); - private List bitmaps = new ArrayList(); - - private byte[] globalData; - - private ArithmeticDecoder arithmeticDecoder; - - private HuffmanDecoder huffmanDecoder; - - private MMRDecoder mmrDecoder; - - public static boolean debug = false; - - public void movePointer(int i) { - reader.movePointer(i); - } - - public void setGlobalData(byte[] data) { - globalData = data; - } - - public void decodeJBIG2(byte[] data) throws IOException, JBIG2Exception { - reader = new StreamReader(data); - - resetDecoder(); - - boolean validFile = checkHeader(); - if (JBIG2StreamDecoder.debug) - System.out.println("validFile = " + validFile); - - if (!validFile) { - /** - * Assume this is a stream from a PDF so there is no file header, - * end of page segments, or end of file segments. Organisation must - * be sequential, and the number of pages is assumed to be 1. - */ - - noOfPagesKnown = true; - randomAccessOrganisation = false; - noOfPages = 1; - - /** check to see if there is any global data to be read */ - if (globalData != null) { - /** set the reader to read from the global data */ - reader = new StreamReader(globalData); - - huffmanDecoder = new HuffmanDecoder(reader); - mmrDecoder = new MMRDecoder(reader); - arithmeticDecoder = new ArithmeticDecoder(reader); - - /** read in the global data segments */ - readSegments(); - - /** set the reader back to the main data */ - reader = new StreamReader(data); - } else { - /** - * There's no global data, so move the file pointer back to the - * start of the stream - */ - reader.movePointer(-8); - } - } else { - /** - * We have the file header, so assume it is a valid stand-alone - * file. - */ - - if (JBIG2StreamDecoder.debug) - System.out.println("==== File Header ===="); - - setFileHeaderFlags(); - - if (JBIG2StreamDecoder.debug) { - System.out.println("randomAccessOrganisation = " + randomAccessOrganisation); - System.out.println("noOfPagesKnown = " + noOfPagesKnown); - } - - if (noOfPagesKnown) { - noOfPages = getNoOfPages(); - - if (JBIG2StreamDecoder.debug) - System.out.println("noOfPages = " + noOfPages); - } - } - - huffmanDecoder = new HuffmanDecoder(reader); - mmrDecoder = new MMRDecoder(reader); - arithmeticDecoder = new ArithmeticDecoder(reader); - - /** read in the main segment data */ - readSegments(); - } - - public HuffmanDecoder getHuffmanDecoder() { - return huffmanDecoder; - } - - public MMRDecoder getMMRDecoder() { - return mmrDecoder; - } - - public ArithmeticDecoder getArithmeticDecoder() { - return arithmeticDecoder; - } - - private void resetDecoder() { - noOfPagesKnown = false; - randomAccessOrganisation = false; - - noOfPages = -1; - - segments.clear(); - bitmaps.clear(); - } - - public void cleanupPostDecode() { - // Clear away everything but the page segments - for (Iterator it = segments.iterator(); it.hasNext(); ) { - Segment segment = (Segment) it.next(); - SegmentHeader segmentHeader = segment.getSegmentHeader(); - if (segmentHeader.getSegmentType() != Segment.PAGE_INFORMATION) { - it.remove(); - } - } - - bitmaps.clear(); - } - - private void readSegments() throws IOException, JBIG2Exception { - - if (JBIG2StreamDecoder.debug) - System.out.println("==== Segments ===="); - - boolean finished = false; - while (!reader.isFinished() && !finished) { - - SegmentHeader segmentHeader = new SegmentHeader(); - - if (JBIG2StreamDecoder.debug) - System.out.println("==== Segment Header ===="); - - readSegmentHeader(segmentHeader); - - // read the Segment data - Segment segment = null; - - int segmentType = segmentHeader.getSegmentType(); - int[] referredToSegments = segmentHeader.getReferredToSegments(); - int noOfReferredToSegments = segmentHeader.getReferredToSegmentCount(); - - switch (segmentType) { - case Segment.SYMBOL_DICTIONARY: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Segment Symbol Dictionary ===="); - - segment = new SymbolDictionarySegment(this); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.INTERMEDIATE_TEXT_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Intermediate Text Region ===="); - - segment = new TextRegionSegment(this, false); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.IMMEDIATE_TEXT_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Immediate Text Region ===="); - - segment = new TextRegionSegment(this, true); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.IMMEDIATE_LOSSLESS_TEXT_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Immediate Lossless Text Region ===="); - - segment = new TextRegionSegment(this, true); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.PATTERN_DICTIONARY: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Pattern Dictionary ===="); - - segment = new PatternDictionarySegment(this); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.INTERMEDIATE_HALFTONE_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Intermediate Halftone Region ===="); - - segment = new HalftoneRegionSegment(this, false); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.IMMEDIATE_HALFTONE_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Immediate Halftone Region ===="); - - segment = new HalftoneRegionSegment(this, true); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.IMMEDIATE_LOSSLESS_HALFTONE_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Immediate Lossless Halftone Region ===="); - - segment = new HalftoneRegionSegment(this, true); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.INTERMEDIATE_GENERIC_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Intermediate Generic Region ===="); - - segment = new GenericRegionSegment(this, false); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.IMMEDIATE_GENERIC_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Immediate Generic Region ===="); - - segment = new GenericRegionSegment(this, true); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.IMMEDIATE_LOSSLESS_GENERIC_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Immediate Lossless Generic Region ===="); - - segment = new GenericRegionSegment(this, true); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.INTERMEDIATE_GENERIC_REFINEMENT_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Intermediate Generic Refinement Region ===="); - - segment = new RefinementRegionSegment(this, false, referredToSegments, noOfReferredToSegments); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.IMMEDIATE_GENERIC_REFINEMENT_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Immediate Generic Refinement Region ===="); - - segment = new RefinementRegionSegment(this, true, referredToSegments, noOfReferredToSegments); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.IMMEDIATE_LOSSLESS_GENERIC_REFINEMENT_REGION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Immediate lossless Generic Refinement Region ===="); - - segment = new RefinementRegionSegment(this, true, referredToSegments, noOfReferredToSegments); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.PAGE_INFORMATION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Page Information Dictionary ===="); - - segment = new PageInformationSegment(this); - - segment.setSegmentHeader(segmentHeader); - - break; - - case Segment.END_OF_PAGE: - continue; - - case Segment.END_OF_STRIPE: - if (JBIG2StreamDecoder.debug) - System.out.println("==== End of Stripes ===="); - - segment = new EndOfStripeSegment(this); - - segment.setSegmentHeader(segmentHeader); - break; - - case Segment.END_OF_FILE: - if (JBIG2StreamDecoder.debug) - System.out.println("==== End of File ===="); - - finished = true; - - continue; - - case Segment.PROFILES: - if (JBIG2StreamDecoder.debug) - System.out.println("PROFILES UNIMPLEMENTED"); - break; - - case Segment.TABLES: - if (JBIG2StreamDecoder.debug) - System.out.println("TABLES UNIMPLEMENTED"); - break; - - case Segment.EXTENSION: - if (JBIG2StreamDecoder.debug) - System.out.println("==== Extensions ===="); - - segment = new ExtensionSegment(this); - - segment.setSegmentHeader(segmentHeader); - - break; - - default: - System.out.println("Unknown Segment type in JBIG2 stream"); - - break; - } - - if (!randomAccessOrganisation && segment != null) { - segment.readSegment(); - } - - if (segments != null) { - segments.add(segment); - } - } - - if (randomAccessOrganisation && segments != null) { - for (Object segment1 : segments) { - Segment segment = (Segment) segment1; - segment.readSegment(); - } - } - } - - public PageInformationSegment findPageSegement(int page) { - for (Object segment1 : segments) { - Segment segment = (Segment) segment1; - SegmentHeader segmentHeader = segment.getSegmentHeader(); - if (segmentHeader.getSegmentType() == Segment.PAGE_INFORMATION && segmentHeader.getPageAssociation() == page) { - return (PageInformationSegment) segment; - } - } - - return null; - } - - public Segment findSegment(int segmentNumber) { - for (Object segment1 : segments) { - Segment segment = (Segment) segment1; - if (segment.getSegmentHeader().getSegmentNumber() == segmentNumber) { - return segment; - } - } - - return null; - } - - private void readSegmentHeader(SegmentHeader segmentHeader) throws IOException, JBIG2Exception { - handleSegmentNumber(segmentHeader); - - handleSegmentHeaderFlags(segmentHeader); - - handleSegmentReferredToCountAndRententionFlags(segmentHeader); - - handleReferedToSegmentNumbers(segmentHeader); - - handlePageAssociation(segmentHeader); - - if (segmentHeader.getSegmentType() != Segment.END_OF_FILE) - handleSegmentDataLength(segmentHeader); - } - - private void handlePageAssociation(SegmentHeader segmentHeader) throws IOException { - int pageAssociation; - - boolean isPageAssociationSizeSet = segmentHeader.isPageAssociationSizeSet(); - if (isPageAssociationSizeSet) { // field is 4 bytes long - short[] buf = new short[4]; - reader.readByte(buf); - pageAssociation = BinaryOperation.getInt32(buf); - } else { // field is 1 byte long - pageAssociation = reader.readByte(); - } - - segmentHeader.setPageAssociation(pageAssociation); - - if (JBIG2StreamDecoder.debug) - System.out.println("pageAssociation = " + pageAssociation); - } - - private void handleSegmentNumber(SegmentHeader segmentHeader) throws IOException { - short[] segmentBytes = new short[4]; - reader.readByte(segmentBytes); - - int segmentNumber = BinaryOperation.getInt32(segmentBytes); - - if (JBIG2StreamDecoder.debug) - System.out.println("SegmentNumber = " + segmentNumber); - segmentHeader.setSegmentNumber(segmentNumber); - } - - private void handleSegmentHeaderFlags(SegmentHeader segmentHeader) throws IOException { - short segmentHeaderFlags = reader.readByte(); - // System.out.println("SegmentHeaderFlags = " + SegmentHeaderFlags); - segmentHeader.setSegmentHeaderFlags(segmentHeaderFlags); - } - - private void handleSegmentReferredToCountAndRententionFlags(SegmentHeader segmentHeader) throws IOException, JBIG2Exception { - short referedToSegmentCountAndRetentionFlags = reader.readByte(); - - int referredToSegmentCount = (referedToSegmentCountAndRetentionFlags & 224) >> 5; // 224 - // = - // 11100000 - - short[] retentionFlags; - /** take off the first three bits of the first byte */ - short firstByte = (short) (referedToSegmentCountAndRetentionFlags & 31); // 31 = - // 00011111 - - if (referredToSegmentCount <= 4) { // short form - - retentionFlags = new short[1]; - retentionFlags[0] = firstByte; - - } else if (referredToSegmentCount == 7) { // long form - - short[] longFormCountAndFlags = new short[4]; - /** add the first byte of the four */ - longFormCountAndFlags[0] = firstByte; - - for (int i = 1; i < 4; i++) - // add the next 3 bytes to the array - longFormCountAndFlags[i] = reader.readByte(); - - /** get the count of the referred to Segments */ - referredToSegmentCount = BinaryOperation.getInt32(longFormCountAndFlags); - - /** calculate the number of bytes in this field */ - int noOfBytesInField = (int) Math.ceil(4 + ((referredToSegmentCount + 1) / 8d)); - // System.out.println("noOfBytesInField = " + noOfBytesInField); - - int noOfRententionFlagBytes = noOfBytesInField - 4; - retentionFlags = new short[noOfRententionFlagBytes]; - reader.readByte(retentionFlags); - - } else { // error - throw new JBIG2Exception("Error, 3 bit Segment count field = " + referredToSegmentCount); - } - - segmentHeader.setReferredToSegmentCount(referredToSegmentCount); - - if (JBIG2StreamDecoder.debug) - System.out.println("referredToSegmentCount = " + referredToSegmentCount); - - segmentHeader.setRententionFlags(retentionFlags); - - if (JBIG2StreamDecoder.debug) - System.out.print("retentionFlags = "); - - if (JBIG2StreamDecoder.debug) { - for (short retentionFlag : retentionFlags) - System.out.print(retentionFlag + " "); - System.out.println(""); - } - } - - private void handleReferedToSegmentNumbers(SegmentHeader segmentHeader) throws IOException { - int referredToSegmentCount = segmentHeader.getReferredToSegmentCount(); - int[] referredToSegments = new int[referredToSegmentCount]; - - int segmentNumber = segmentHeader.getSegmentNumber(); - - if (segmentNumber <= 256) { - for (int i = 0; i < referredToSegmentCount; i++) - referredToSegments[i] = reader.readByte(); - } else if (segmentNumber <= 65536) { - short[] buf = new short[2]; - for (int i = 0; i < referredToSegmentCount; i++) { - reader.readByte(buf); - referredToSegments[i] = BinaryOperation.getInt16(buf); - } - } else { - short[] buf = new short[4]; - for (int i = 0; i < referredToSegmentCount; i++) { - reader.readByte(buf); - referredToSegments[i] = BinaryOperation.getInt32(buf); - } - } - - segmentHeader.setReferredToSegments(referredToSegments); - - if (JBIG2StreamDecoder.debug) { - System.out.print("referredToSegments = "); - for (int referredToSegment : referredToSegments) - System.out.print(referredToSegment + " "); - System.out.println(""); - } - } - - private int getNoOfPages() throws IOException { - short[] noOfPages = new short[4]; - reader.readByte(noOfPages); - - return BinaryOperation.getInt32(noOfPages); - } - - private void handleSegmentDataLength(SegmentHeader segmentHeader) throws IOException { - short[] buf = new short[4]; - reader.readByte(buf); - - int dateLength = BinaryOperation.getInt32(buf); - segmentHeader.setDataLength(dateLength); - - if (JBIG2StreamDecoder.debug) - System.out.println("dateLength = " + dateLength); - } - - private void setFileHeaderFlags() throws IOException { - short headerFlags = reader.readByte(); - - if ((headerFlags & 0xfc) != 0) { - System.out.println("Warning, reserved bits (2-7) of file header flags are not zero " + headerFlags); - } - - int fileOrganisation = headerFlags & 1; - randomAccessOrganisation = fileOrganisation == 0; - - int pagesKnown = headerFlags & 2; - noOfPagesKnown = pagesKnown == 0; - } - - private boolean checkHeader() throws IOException { - short[] controlHeader = new short[]{151, 74, 66, 50, 13, 10, 26, 10}; - short[] actualHeader = new short[8]; - reader.readByte(actualHeader); - - return Arrays.equals(controlHeader, actualHeader); - } - - public int readBits(int num) throws IOException { - return reader.readBits(num); - } - - public int readBit() throws IOException { - return reader.readBit(); - } - - public void readByte(short[] buff) throws IOException { - reader.readByte(buff); - } - - public void consumeRemainingBits() throws IOException { - reader.consumeRemainingBits(); - } - - public short readByte() throws java.io.IOException { - return reader.readByte(); - } - - public void appendBitmap(JBIG2Bitmap bitmap) { - bitmaps.add(bitmap); - } - - public JBIG2Bitmap findBitmap(int bitmapNumber) { - for (Object bitmap1 : bitmaps) { - JBIG2Bitmap bitmap = (JBIG2Bitmap) bitmap1; - if (bitmap.getBitmapNumber() == bitmapNumber) { - return bitmap; - } - } - - return null; - } - - public JBIG2Bitmap getPageAsJBIG2Bitmap(int i) { - return findPageSegement(i).getPageBitmap(); - } - - public boolean isNumberOfPagesKnown() { - return noOfPagesKnown; - } - - public int getNumberOfPages() { - return noOfPages; - } - - public boolean isRandomAccessOrganisationUsed() { - return randomAccessOrganisation; - } - - public List getAllSegments() { - return segments; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/MMRDecoder.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/MMRDecoder.java deleted file mode 100644 index f0398c73bf..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/decoders/MMRDecoder.java +++ /dev/null @@ -1,301 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett - * -* This file is part of JPedal - * -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* MMRDecoder.java -* --------------- - */ -package org.jpedal.jbig2.decoders; - -import org.jpedal.jbig2.io.StreamReader; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.io.IOException; - -public class MMRDecoder { - - private StreamReader reader; - - private long bufferLength = 0, buffer = 0, noOfBytesRead = 0; - - private MMRDecoder() { - } - - public MMRDecoder(StreamReader reader) { - this.reader = reader; - } - - public void reset() { - bufferLength = 0; - noOfBytesRead = 0; - buffer = 0; - } - - public void skipTo(int length) throws IOException { - while (noOfBytesRead < length) { - reader.readByte(); - noOfBytesRead++; - } - } - - public long get24Bits() throws IOException { - while (bufferLength < 24) { - - buffer = ((BinaryOperation.bit32Shift(buffer, 8, BinaryOperation.LEFT_SHIFT)) | (reader.readByte() & 0xff)); - bufferLength += 8; - noOfBytesRead++; - } - - return (BinaryOperation.bit32Shift(buffer, (int) (bufferLength - 24), BinaryOperation.RIGHT_SHIFT)) & 0xffffff; - } - - public int get2DCode() throws IOException { - int[] tuple; - - if (bufferLength == 0) { - buffer = (reader.readByte() & 0xff); - - bufferLength = 8; - - noOfBytesRead++; - - int lookup = (int) ((BinaryOperation.bit32Shift(buffer, 1, BinaryOperation.RIGHT_SHIFT)) & 0x7f); - - tuple = twoDimensionalTable1[lookup]; - } else if (bufferLength == 8) { - int lookup = (int) ((BinaryOperation.bit32Shift(buffer, 1, BinaryOperation.RIGHT_SHIFT)) & 0x7f); - tuple = twoDimensionalTable1[lookup]; - } else { - int lookup = (int) ((BinaryOperation.bit32Shift(buffer, (int) (7 - bufferLength), BinaryOperation.LEFT_SHIFT)) & 0x7f); - - tuple = twoDimensionalTable1[lookup]; - if (tuple[0] < 0 || tuple[0] > (int) bufferLength) { - int right = (reader.readByte() & 0xff); - - long left = (BinaryOperation.bit32Shift(buffer, 8, BinaryOperation.LEFT_SHIFT)); - - buffer = left | right; - bufferLength += 8; - noOfBytesRead++; - - int look = (int) (BinaryOperation.bit32Shift(buffer, (int) (bufferLength - 7), BinaryOperation.RIGHT_SHIFT) & 0x7f); - - tuple = twoDimensionalTable1[look]; - } - } - if (tuple[0] < 0) { - if (JBIG2StreamDecoder.debug) - System.out.println("Bad two dim code in JBIG2 MMR stream"); - - return 0; - } - bufferLength -= tuple[0]; - - return tuple[1]; - } - - public int getWhiteCode() throws IOException { - int[] tuple; - long code; - - if (bufferLength == 0) { - buffer = (reader.readByte() & 0xff); - bufferLength = 8; - noOfBytesRead++; - } - while (true) { - if (bufferLength >= 7 && ((BinaryOperation.bit32Shift(buffer, (int) (bufferLength - 7), BinaryOperation.RIGHT_SHIFT)) & 0x7f) == 0) { - if (bufferLength <= 12) { - code = BinaryOperation.bit32Shift(buffer, (int) (12 - bufferLength), BinaryOperation.LEFT_SHIFT); - } else { - code = BinaryOperation.bit32Shift(buffer, (int) (bufferLength - 12), BinaryOperation.RIGHT_SHIFT); - } - - tuple = whiteTable1[(int) (code & 0x1f)]; - } else { - if (bufferLength <= 9) { - code = BinaryOperation.bit32Shift(buffer, (int) (9 - bufferLength), BinaryOperation.LEFT_SHIFT); - } else { - code = BinaryOperation.bit32Shift(buffer, (int) (bufferLength - 9), BinaryOperation.RIGHT_SHIFT); - } - - int lookup = (int) (code & 0x1ff); - if (lookup >= 0) - tuple = whiteTable2[lookup]; - else - tuple = whiteTable2[whiteTable2.length + lookup]; - } - if (tuple[0] > 0 && tuple[0] <= (int) bufferLength) { - bufferLength -= tuple[0]; - return tuple[1]; - } - if (bufferLength >= 12) { - break; - } - buffer = ((BinaryOperation.bit32Shift(buffer, 8, BinaryOperation.LEFT_SHIFT)) | reader.readByte() & 0xff); - bufferLength += 8; - noOfBytesRead++; - } - if (JBIG2StreamDecoder.debug) - System.out.println("Bad white code in JBIG2 MMR stream"); - - bufferLength--; - - return 1; - } - - public int getBlackCode() throws IOException { - int[] tuple; - long code; - - if (bufferLength == 0) { - buffer = (reader.readByte() & 0xff); - bufferLength = 8; - noOfBytesRead++; - } - while (true) { - if (bufferLength >= 6 && ((BinaryOperation.bit32Shift(buffer, (int) (bufferLength - 6), BinaryOperation.RIGHT_SHIFT)) & 0x3f) == 0) { - if (bufferLength <= 13) { - code = BinaryOperation.bit32Shift(buffer, (int) (13 - bufferLength), BinaryOperation.LEFT_SHIFT); - } else { - code = BinaryOperation.bit32Shift(buffer, (int) (bufferLength - 13), BinaryOperation.RIGHT_SHIFT); - } - tuple = blackTable1[(int) (code & 0x7f)]; - } else if (bufferLength >= 4 && ((buffer >> (bufferLength - 4)) & 0x0f) == 0) { - if (bufferLength <= 12) { - code = BinaryOperation.bit32Shift(buffer, (int) (12 - bufferLength), BinaryOperation.LEFT_SHIFT); - } else { - code = BinaryOperation.bit32Shift(buffer, (int) (bufferLength - 12), BinaryOperation.RIGHT_SHIFT); - } - - int lookup = (int) ((code & 0xff) - 64); - if (lookup >= 0) - tuple = blackTable2[lookup]; - else - tuple = blackTable1[blackTable1.length + lookup]; - } else { - if (bufferLength <= 6) { - code = BinaryOperation.bit32Shift(buffer, (int) (6 - bufferLength), BinaryOperation.LEFT_SHIFT); - } else { - code = BinaryOperation.bit32Shift(buffer, (int) (bufferLength - 6), BinaryOperation.RIGHT_SHIFT); - } - - int lookup = (int) (code & 0x3f); - if (lookup >= 0) - tuple = blackTable3[lookup]; - else - tuple = blackTable2[blackTable2.length + lookup]; - } - if (tuple[0] > 0 && tuple[0] <= (int) bufferLength) { - bufferLength -= tuple[0]; - return tuple[1]; - } - if (bufferLength >= 13) { - break; - } - buffer = ((BinaryOperation.bit32Shift(buffer, 8, BinaryOperation.LEFT_SHIFT)) | (reader.readByte() & 0xff)); - bufferLength += 8; - noOfBytesRead++; - } - - if (JBIG2StreamDecoder.debug) - System.out.println("Bad black code in JBIG2 MMR stream"); - - bufferLength--; - return 1; - } - - public static int ccittEndOfLine = -2; - - public static final int twoDimensionalPass = 0; - public static final int twoDimensionalHorizontal = 1; - public static final int twoDimensionalVertical0 = 2; - public static final int twoDimensionalVerticalR1 = 3; - public static final int twoDimensionalVerticalL1 = 4; - public static final int twoDimensionalVerticalR2 = 5; - public static final int twoDimensionalVerticalL2 = 6; - public static final int twoDimensionalVerticalR3 = 7; - public static final int twoDimensionalVerticalL3 = 8; - - private int twoDimensionalTable1[][] = {{-1, -1}, {-1, -1}, {7, twoDimensionalVerticalL3}, {7, twoDimensionalVerticalR3}, {6, twoDimensionalVerticalL2}, {6, twoDimensionalVerticalL2}, {6, twoDimensionalVerticalR2}, {6, twoDimensionalVerticalR2}, {4, twoDimensionalPass}, {4, twoDimensionalPass}, {4, twoDimensionalPass}, {4, twoDimensionalPass}, {4, twoDimensionalPass}, {4, twoDimensionalPass}, {4, twoDimensionalPass}, {4, twoDimensionalPass}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, - {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalHorizontal}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, - {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalL1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, - {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {3, twoDimensionalVerticalR1}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, - {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, - {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, - {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}, {1, twoDimensionalVertical0}}; - - /** - * white run lengths - */ - private int whiteTable1[][] = {{-1, -1}, {12, ccittEndOfLine}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {11, 1792}, {11, 1792}, {12, 1984}, {12, 2048}, {12, 2112}, {12, 2176}, {12, 2240}, {12, 2304}, {11, 1856}, {11, 1856}, {11, 1920}, {11, 1920}, {12, 2368}, {12, 2432}, {12, 2496}, {12, 2560}}; - - private int whiteTable2[][] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {8, 29}, {8, 29}, {8, 30}, {8, 30}, {8, 45}, {8, 45}, {8, 46}, {8, 46}, {7, 22}, {7, 22}, {7, 22}, {7, 22}, {7, 23}, {7, 23}, {7, 23}, {7, 23}, {8, 47}, {8, 47}, {8, 48}, {8, 48}, {6, 13}, {6, 13}, {6, 13}, {6, 13}, {6, 13}, {6, 13}, {6, 13}, {6, 13}, {7, 20}, {7, 20}, {7, 20}, {7, 20}, {8, 33}, {8, 33}, {8, 34}, {8, 34}, {8, 35}, {8, 35}, {8, 36}, {8, 36}, {8, 37}, {8, 37}, {8, 38}, {8, 38}, {7, 19}, {7, 19}, - {7, 19}, {7, 19}, {8, 31}, {8, 31}, {8, 32}, {8, 32}, {6, 1}, {6, 1}, {6, 1}, {6, 1}, {6, 1}, {6, 1}, {6, 1}, {6, 1}, {6, 12}, {6, 12}, {6, 12}, {6, 12}, {6, 12}, {6, 12}, {6, 12}, {6, 12}, {8, 53}, {8, 53}, {8, 54}, {8, 54}, {7, 26}, {7, 26}, {7, 26}, {7, 26}, {8, 39}, {8, 39}, {8, 40}, {8, 40}, {8, 41}, {8, 41}, {8, 42}, {8, 42}, {8, 43}, {8, 43}, {8, 44}, {8, 44}, {7, 21}, {7, 21}, {7, 21}, {7, 21}, {7, 28}, {7, 28}, {7, 28}, {7, 28}, {8, 61}, {8, 61}, - {8, 62}, {8, 62}, {8, 63}, {8, 63}, {8, 0}, {8, 0}, {8, 320}, {8, 320}, {8, 384}, {8, 384}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {7, 27}, {7, 27}, {7, 27}, {7, 27}, {8, 59}, {8, 59}, {8, 60}, {8, 60}, {9, 1472}, - {9, 1536}, {9, 1600}, {9, 1728}, {7, 18}, {7, 18}, {7, 18}, {7, 18}, {7, 24}, {7, 24}, {7, 24}, {7, 24}, {8, 49}, {8, 49}, {8, 50}, {8, 50}, {8, 51}, {8, 51}, {8, 52}, {8, 52}, {7, 25}, {7, 25}, {7, 25}, {7, 25}, {8, 55}, {8, 55}, {8, 56}, {8, 56}, {8, 57}, {8, 57}, {8, 58}, {8, 58}, {6, 192}, {6, 192}, {6, 192}, {6, 192}, {6, 192}, {6, 192}, {6, 192}, {6, 192}, {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, {8, 448}, - {8, 448}, {8, 512}, {8, 512}, {9, 704}, {9, 768}, {8, 640}, {8, 640}, {8, 576}, {8, 576}, {9, 832}, {9, 896}, {9, 960}, {9, 1024}, {9, 1088}, {9, 1152}, {9, 1216}, {9, 1280}, {9, 1344}, {9, 1408}, {7, 256}, {7, 256}, {7, 256}, {7, 256}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 8}, - {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {6, 16}, {6, 16}, {6, 16}, {6, 16}, {6, 16}, {6, 16}, {6, 16}, {6, 16}, {6, 17}, {6, 17}, {6, 17}, {6, 17}, {6, 17}, {6, 17}, {6, 17}, {6, 17}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {6, 14}, {6, 14}, {6, 14}, {6, 14}, {6, 14}, {6, 14}, {6, 14}, {6, 14}, {6, 15}, {6, 15}, {6, 15}, {6, 15}, {6, 15}, {6, 15}, {6, 15}, {6, 15}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}}; - - /** - * black run lengths - */ - int blackTable1[][] = {{-1, -1}, {-1, -1}, {12, ccittEndOfLine}, {12, ccittEndOfLine}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {11, 1792}, {11, 1792}, {11, 1792}, {11, 1792}, {12, 1984}, {12, 1984}, {12, 2048}, {12, 2048}, {12, 2112}, {12, 2112}, - {12, 2176}, {12, 2176}, {12, 2240}, {12, 2240}, {12, 2304}, {12, 2304}, {11, 1856}, {11, 1856}, {11, 1856}, {11, 1856}, {11, 1920}, {11, 1920}, {11, 1920}, {11, 1920}, {12, 2368}, {12, 2368}, {12, 2432}, {12, 2432}, {12, 2496}, {12, 2496}, {12, 2560}, {12, 2560}, {10, 18}, {10, 18}, {10, 18}, {10, 18}, {10, 18}, {10, 18}, {10, 18}, {10, 18}, {12, 52}, {12, 52}, {13, 640}, {13, 704}, {13, 768}, {13, 832}, {12, 55}, {12, 55}, {12, 56}, {12, 56}, {13, 1280}, {13, 1344}, - {13, 1408}, {13, 1472}, {12, 59}, {12, 59}, {12, 60}, {12, 60}, {13, 1536}, {13, 1600}, {11, 24}, {11, 24}, {11, 24}, {11, 24}, {11, 25}, {11, 25}, {11, 25}, {11, 25}, {13, 1664}, {13, 1728}, {12, 320}, {12, 320}, {12, 384}, {12, 384}, {12, 448}, {12, 448}, {13, 512}, {13, 576}, {12, 53}, {12, 53}, {12, 54}, {12, 54}, {13, 896}, {13, 960}, {13, 1024}, {13, 1088}, {13, 1152}, {13, 1216}, {10, 64}, {10, 64}, {10, 64}, {10, 64}, {10, 64}, {10, 64}, {10, 64}, {10, 64}}; - - int blackTable2[][] = {{8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {11, 23}, {11, 23}, {12, 50}, {12, 51}, {12, 44}, {12, 45}, {12, 46}, {12, 47}, {12, 57}, {12, 58}, {12, 61}, {12, 256}, {10, 16}, {10, 16}, {10, 16}, {10, 16}, {10, 17}, {10, 17}, {10, 17}, {10, 17}, {12, 48}, {12, 49}, {12, 62}, {12, 63}, {12, 30}, {12, 31}, {12, 32}, {12, 33}, {12, 40}, {12, 41}, {11, 22}, - {11, 22}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {9, 15}, {9, 15}, {9, 15}, {9, 15}, {9, 15}, {9, 15}, {9, 15}, {9, 15}, {12, 128}, {12, 192}, {12, 26}, {12, 27}, {12, 28}, {12, 29}, {11, 19}, {11, 19}, {11, 20}, {11, 20}, {12, 34}, {12, 35}, - {12, 36}, {12, 37}, {12, 38}, {12, 39}, {11, 21}, {11, 21}, {12, 42}, {12, 43}, {10, 0}, {10, 0}, {10, 0}, {10, 0}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}}; - - int blackTable3[][] = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, {6, 9}, {6, 8}, {5, 7}, {5, 7}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {3, 1}, {3, 1}, {3, 1}, {3, 1}, {3, 1}, {3, 1}, {3, 1}, {3, 1}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, - {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}}; - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/examples/jai/JBIG2ReaderPluginTester.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/examples/jai/JBIG2ReaderPluginTester.java deleted file mode 100644 index f4496eba7d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/examples/jai/JBIG2ReaderPluginTester.java +++ /dev/null @@ -1,609 +0,0 @@ -package org.jpedal.jbig2.examples.jai; - -import javax.imageio.ImageIO; -import javax.imageio.ImageReadParam; -import javax.imageio.ImageReader; -import javax.imageio.stream.ImageInputStream; -import javax.swing.*; -import javax.swing.border.Border; -import javax.swing.border.EtchedBorder; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.image.BufferedImage; -import java.io.File; -import java.util.Iterator; - -@SuppressWarnings("serial") -public class JBIG2ReaderPluginTester extends JFrame { - final static String appTitle = "JBIG2 Reader Plug-in Tester"; - - final static int FORMAT_NAME = 0; - final static int INPUT = 1; - final static int MIME_TYPE = 2; - final static int SUFFIX = 3; - - // Most recently read PCX image. - - BufferedImage biImage; - - // Offset in destination image where future decoded pixels will be placed. - - int dstOffX, dstOffY; - - // Image height and width. - - int height, width; - - // Source region definition. - - int srcX, srcY, srcWidth, srcHeight = 1; - - // Subsampling horizontal and vertical periods. - - int xSS = 1, ySS = 1; - - // Application status bar -- holds path and name of most recent PCX file. - - JLabel lblStatus; - - // Current method for getting an image reader. - - int method = FORMAT_NAME; - - // The picture panel displays the contents of the most recently read PCX - // image. - - PicPanel pp; - - // The scroll pane allows the user to scroll around images that are bigger - // than the picture panel. - - JScrollPane jsp; - - // Construct the PCXRPT GUI and indirectly start AWT helper threads. - - public JBIG2ReaderPluginTester(String title) { - // Pass application title to superclass so that it appears on the title - // bar. - - super(title); - - // Terminate the application when the user clicks the tiny x button on - // the title bar. - - setDefaultCloseOperation(EXIT_ON_CLOSE); - - // Construct an open file chooser. Initialize the starting directory to - // the current directory. - - final JFileChooser fcOpen = new JFileChooser(); - fcOpen.setCurrentDirectory(new File(System.getProperty("user.dir"))); - - // Construct the application's menu bar. - - JMenuBar mb = new JMenuBar(); - - // The only menu to appear on the menu bar is File. The user invokes - // menu items on this menu to open PCX images, configure the PCX reader - // plug-in, and terminate the application. - - JMenu menuFile = new JMenu("File"); - - // Create and install the open menu item. - - JMenuItem miOpen = new JMenuItem("Open..."); - - ActionListener openl; - openl = new ActionListener() { - public void actionPerformed(ActionEvent e) { - // Present the "open" file chooser without any file selected. If - // the user cancels this file chooser, exit this method. - - fcOpen.setSelectedFile(null); - if (fcOpen.showOpenDialog(JBIG2ReaderPluginTester.this) != JFileChooser.APPROVE_OPTION) - return; - - // Attempt to read the image from the selected file. If something - // goes wrong, doOpen() presents an appropriate error message and - // false returns. Exit this method. - - if (!doOpen(fcOpen.getSelectedFile())) - return; - - // Provide the user with assorted information. - - lblStatus.setText("Width: " + width + ", Height: " + height + ", File: " + fcOpen.getSelectedFile().getAbsolutePath()); - - // Display the new PCX image in the picture panel. The picture - // panel automatically adjusts its dimensions, causing the - // scrollpane to determine if scrollbars should be displayed. - - pp.setBufferedImage(biImage); - - // Reset the scroll positions so that the image's upper-left - // corner is visible. - - jsp.getHorizontalScrollBar().setValue(0); - jsp.getVerticalScrollBar().setValue(0); - } - }; - miOpen.addActionListener(openl); - - menuFile.add(miOpen); - - // Create and install the configure menu item. - - JMenuItem miConfigure = new JMenuItem("Configure..."); - - ActionListener cfgl; - cfgl = new ActionListener() { - public void actionPerformed(ActionEvent e) { - CfgDialog cfgdlg = new CfgDialog(JBIG2ReaderPluginTester.this, dstOffX, dstOffY, method, srcX, srcY, srcWidth, srcHeight, xSS, ySS); - cfgdlg.setVisible(true); - - if (cfgdlg.isCanceled()) - return; - - dstOffX = cfgdlg.getDstOffX(); - dstOffY = cfgdlg.getDstOffY(); - - method = cfgdlg.getMethod(); - - srcX = cfgdlg.getSrcX(); - srcY = cfgdlg.getSrcY(); - srcWidth = cfgdlg.getSrcWidth(); - srcHeight = cfgdlg.getSrcHeight(); - - xSS = cfgdlg.getXSS(); - ySS = cfgdlg.getYSS(); - } - }; - miConfigure.addActionListener(cfgl); - - menuFile.add(miConfigure); - - menuFile.addSeparator(); - - // Create and install the exit menu item. - - JMenuItem miExit = new JMenuItem("Exit"); - - ActionListener exitl; - exitl = new ActionListener() { - public void actionPerformed(ActionEvent e) { - System.exit(0); - } - }; - miExit.addActionListener(exitl); - - menuFile.add(miExit); - - // Add the file menu to the menu bar. - - mb.add(menuFile); - - // Install the menu bar. - - setJMenuBar(mb); - - // Create an initial picture panel that does not display a picture, but - // has a default size. - - pp = new PicPanel(null); - - // Indirectly add the picture panel, by way of a scrollpane, to the - // application's contentpane. - - getContentPane().add(jsp = new JScrollPane(pp)); - - // Create a status bar that displays the method used to obtain an image - // reader, the height and width of the current image, and the path and - // name of the current image's file. Initialize the status bar text to - // one space so that it will be displayed at a height corresponding to - // its current font's size. Surround the status bar with an etched - // border to visually separate this component from the picture panel. - - lblStatus = new JLabel(" "); - lblStatus.setBorder(BorderFactory.createEtchedBorder()); - - // Add the status bar to the bottom of the application's contentpane. - - getContentPane().add(lblStatus, BorderLayout.SOUTH); - - // Resize all components to their preferred sizes. - - pack(); - - // Display GUI and start GUI processing. - - setVisible(true); - } - - // Open the specified JBIG2 file and read the file's JBIG2 image. - - boolean doOpen(File file) { - if (!file.exists()) { - JOptionPane.showMessageDialog(JBIG2ReaderPluginTester.this, "File does not exist!", appTitle, JOptionPane.ERROR_MESSAGE); - - return false; - } - - try { - // Validate file extension. - - String path = file.getAbsolutePath().toLowerCase(); - - if (!path.endsWith(".jbig2") && !path.endsWith(".jb2")) { - JOptionPane.showMessageDialog(JBIG2ReaderPluginTester.this, "Incorrect file extension!", appTitle, JOptionPane.ERROR_MESSAGE); - - return false; - } - - // Obtain an appropriate reader. - - ImageInputStream iis = ImageIO.createImageInputStream(file); - - Iterator iter; - if (method == FORMAT_NAME) - iter = ImageIO.getImageReadersByFormatName("jbig2"); - else if (method == MIME_TYPE) - iter = ImageIO.getImageReadersByMIMEType("image/x-jbig2"); - else if (method == SUFFIX) - iter = ImageIO.getImageReadersBySuffix("jbig2"); - else - iter = ImageIO.getImageReaders(iis); - - // Validate existence of reader. A reader will not be returned by - // getImageReaders() if JBIG2ImageReaderSpi's canDecodeInput() method - // returns false. - - if (!iter.hasNext()) { - JOptionPane.showMessageDialog(JBIG2ReaderPluginTester.this, "Unable to obtain reader!", appTitle, JOptionPane.ERROR_MESSAGE); - - return false; - } - - // Extract reader. - - ImageReader reader = (ImageReader) iter.next(); - - // Configure reader's input source. - - reader.setInput(iis, true); - - // Configure reader parameters. - - ImageReadParam irp = reader.getDefaultReadParam(); - - if (!(dstOffX == 0 && dstOffY == 0)) - irp.setDestinationOffset(new Point(dstOffX, dstOffY)); - - if (srcWidth != 0) - irp.setSourceRegion(new Rectangle(srcX, srcY, srcWidth, srcHeight)); - - if (!(xSS == 1 && ySS == 1)) - irp.setSourceSubsampling(xSS, ySS, 0, 0); - - // Read the image. - biImage = reader.read(0, irp); - - // Obtain the image's width and height. - - width = reader.getWidth(0); - height = reader.getHeight(0); - - // Cleanup. - - reader.dispose(); - - return true; - } catch (Exception e) { - JOptionPane.showMessageDialog(JBIG2ReaderPluginTester.this, e.getMessage(), appTitle, JOptionPane.ERROR_MESSAGE); - - return false; - } - } - - // Application entry point. - - public static void main(String[] args) { - // Create the application's GUI and start the application. - - new JBIG2ReaderPluginTester(appTitle); - } -} - -@SuppressWarnings("serial") -class CfgDialog extends JDialog { - private final static int MAX_DSTOFFX = 9999; - private final static int MAX_DSTOFFY = 9999; - - private final static int MAX_XSS = 9999; - private final static int MAX_YSS = 9999; - - private final static int MAX_SRCX = 9999; - private final static int MAX_SRCY = 9999; - - private final static int MAX_SRCWIDTH = 9999; - private final static int MAX_SRCHEIGHT = 9999; - - private boolean canceled; - - private int dstOffX, dstOffY; - - private int srcHeight, srcWidth, srcX, srcY; - - private int xSS, ySS; - - private int method; - - CfgDialog(JFrame f, int dstOffX, int dstOffY, int method, int srcX, int srcY, int srcWidth, int srcHeight, int xSS, int ySS) { - // Assign title to dialog box's title bar and ensure dialog box is - // modal. - - super(f, "Configure", true); - - // Create a main layout panel that divides the GUI into several - // sections, where each section has the same width and height. - - JPanel pnlLayout = new JPanel(); - pnlLayout.setLayout(new GridLayout(5, 1)); - - // Create and install the destination offset section. - - JPanel pnl = new JPanel(); - Border bd = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); - pnl.setBorder(BorderFactory.createTitledBorder(bd, "Destination Offset")); - - pnl.add(new JLabel("X")); - final JSpinner spnDstOffX = new JSpinner(new SpinnerNumberModel(dstOffX, 0, MAX_DSTOFFX, 1)); - pnl.add(spnDstOffX); - - pnl.add(new JLabel("Y")); - final JSpinner spnDstOffY = new JSpinner(new SpinnerNumberModel(dstOffY, 0, MAX_DSTOFFY, 1)); - pnl.add(spnDstOffY); - - pnlLayout.add(pnl); - - // Create and install the method section. - - pnl = new JPanel(); - bd = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); - pnl.setBorder(BorderFactory.createTitledBorder(bd, "Method")); - - final JRadioButton rbChoice1 = new JRadioButton("Format name"); - if (method == JBIG2ReaderPluginTester.FORMAT_NAME) - rbChoice1.setSelected(true); - pnl.add(rbChoice1); - - final JRadioButton rbChoice2 = new JRadioButton("Input"); - if (method == JBIG2ReaderPluginTester.INPUT) - rbChoice2.setSelected(true); - pnl.add(rbChoice2); - - final JRadioButton rbChoice3 = new JRadioButton("MIME type"); - if (method == JBIG2ReaderPluginTester.MIME_TYPE) - rbChoice3.setSelected(true); - pnl.add(rbChoice3); - - final JRadioButton rbChoice4 = new JRadioButton("Suffix"); - if (method == JBIG2ReaderPluginTester.SUFFIX) - rbChoice4.setSelected(true); - pnl.add(rbChoice4); - - final ButtonGroup bg = new ButtonGroup(); - bg.add(rbChoice1); - bg.add(rbChoice2); - bg.add(rbChoice3); - bg.add(rbChoice4); - - pnlLayout.add(pnl); - - // Create and install the source region section. - - pnl = new JPanel(); - bd = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); - pnl.setBorder(BorderFactory.createTitledBorder(bd, "Source Region")); - - pnl.add(new JLabel("Src X")); - final JSpinner spnSrcX = new JSpinner(new SpinnerNumberModel(srcX, 0, MAX_SRCX, 1)); - pnl.add(spnSrcX); - - pnl.add(new JLabel("Src Y")); - final JSpinner spnSrcY = new JSpinner(new SpinnerNumberModel(srcY, 0, MAX_SRCY, 1)); - pnl.add(spnSrcY); - - pnl.add(new JLabel("Src Width")); - final JSpinner spnSrcWidth = new JSpinner(new SpinnerNumberModel(srcWidth, 0, MAX_SRCWIDTH, 1)); - pnl.add(spnSrcWidth); - - pnl.add(new JLabel("Src Height")); - final JSpinner spnSrcHeight = new JSpinner(new SpinnerNumberModel(srcHeight, 1, MAX_SRCHEIGHT, 1)); - pnl.add(spnSrcHeight); - - pnlLayout.add(pnl); - - // Create and install the source subsampling section. - - pnl = new JPanel(); - bd = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); - pnl.setBorder(BorderFactory.createTitledBorder(bd, "Source Subsampling")); - - pnl.add(new JLabel("X Subsampling")); - final JSpinner spnXSS = new JSpinner(new SpinnerNumberModel(xSS, 1, MAX_XSS, 1)); - pnl.add(spnXSS); - - pnl.add(new JLabel("Y Subsampling")); - final JSpinner spnYSS = new JSpinner(new SpinnerNumberModel(ySS, 1, MAX_YSS, 1)); - pnl.add(spnYSS); - - pnlLayout.add(pnl); - - // Create and install the button section. - - pnl = new JPanel(); - pnl.setLayout(new FlowLayout(FlowLayout.RIGHT)); - - JButton btn = new JButton("OK"); - pnl.add(btn); - btn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - canceled = false; - - if (rbChoice1.isSelected()) - CfgDialog.this.method = JBIG2ReaderPluginTester.FORMAT_NAME; - else if (rbChoice2.isSelected()) - CfgDialog.this.method = JBIG2ReaderPluginTester.INPUT; - else if (rbChoice3.isSelected()) - CfgDialog.this.method = JBIG2ReaderPluginTester.MIME_TYPE; - else - CfgDialog.this.method = JBIG2ReaderPluginTester.SUFFIX; - - CfgDialog.this.dstOffX = (Integer) spnDstOffX.getValue(); - CfgDialog.this.dstOffY = (Integer) spnDstOffY.getValue(); - - CfgDialog.this.xSS = (Integer) spnXSS.getValue(); - CfgDialog.this.ySS = (Integer) spnYSS.getValue(); - - CfgDialog.this.srcX = (Integer) spnSrcX.getValue(); - CfgDialog.this.srcY = (Integer) spnSrcY.getValue(); - CfgDialog.this.srcWidth = (Integer) spnSrcWidth.getValue(); - CfgDialog.this.srcHeight = (Integer) spnSrcHeight.getValue(); - - dispose(); - } - }); - - btn = new JButton("Cancel"); - pnl.add(btn); - btn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - canceled = true; - - dispose(); - } - }); - - pnlLayout.add(pnl); - - // Add main layout panel to content pane. - - getContentPane().add(pnlLayout); - - // Resize dialog box to union of collective preferred sizes of all - // contained components. - - pack(); - } - - int getDstOffX() { - return dstOffX; - } - - int getDstOffY() { - return dstOffY; - } - - int getMethod() { - return method; - } - - int getSrcHeight() { - return srcHeight; - } - - int getSrcWidth() { - return srcWidth; - } - - int getSrcX() { - return srcX; - } - - int getSrcY() { - return srcY; - } - - int getXSS() { - return xSS; - } - - int getYSS() { - return ySS; - } - - boolean isCanceled() { - return canceled; - } -} - -@SuppressWarnings("serial") -class PicPanel extends JPanel { - // Dimensions of picture panel's preferred size. - - final static int WIDTH = 600; - final static int HEIGHT = 440; - - // Reference to BufferedImage whose image is displayed in panel. If null - // reference, nothing is displayed in panel area. - - private BufferedImage bi; - - // Create a picture panel component. - - PicPanel(BufferedImage bi) { - // Install the buffered image for this panel. - - setBufferedImage(bi); - } - - // Retrieve this component's preferred size for layout purposes. - - public Dimension getPreferredSize() { - // When the program starts, there is no installed buffered image so a - // default preferred size is chosen. After a buffered image has been - // installed, that buffered image's size is returned as the preferred - // size. - - if (bi == null) - return new Dimension(WIDTH, HEIGHT); - else - return new Dimension(bi.getWidth(), bi.getHeight()); - } - - // Redraw the picture panel. - - public void paintComponent(Graphics g) { - // Paint the component's background to prevent artifacts from appearing. - - super.paintComponent(g); - - // If a buffered image has been installed, paint its contents on the - // panel. - - if (bi != null) - g.drawImage(bi, 0, 0, this); - } - - // Install a new buffered image into the picture panel. - - public void setBufferedImage(BufferedImage bi) { - // Save the buffered image for future painting. - - this.bi = bi; - - // The following method call invalidates this component and then adds - // this component's validateRoot (the JScrollPane in which the picture - // panel is contained) to a list of components that need to be validated. - // Validation results in a call to this component's getPreferredSize() - // method; this information will be used by the scrollpane to determine - // if its scrollbars should be shown. - - revalidate(); - - // Paint the new image on the panel. - - repaint(); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/examples/pdf/PDFSegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/examples/pdf/PDFSegment.java deleted file mode 100644 index 5e88fedd35..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/examples/pdf/PDFSegment.java +++ /dev/null @@ -1,90 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* PDFSegment.java -* --------------- - */ -package org.jpedal.jbig2.examples.pdf; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -public class PDFSegment { - - private ByteArrayOutputStream header = new ByteArrayOutputStream(); - private ByteArrayOutputStream data = new ByteArrayOutputStream(); - private int segmentDataLength; - - public void writeToHeader(short bite) { - header.write(bite); - } - - public void writeToHeader(short[] bites) throws IOException { - for (int i = 0; i < bites.length; i++) - header.write(bites[i]); - } - - public void writeToData(short bite) { - data.write(bite); - } - - public ByteArrayOutputStream getHeader() { - return header; - } - - public ByteArrayOutputStream getData() { - return data; - } - - public void setDataLength(int segmentDataLength) { - this.segmentDataLength = segmentDataLength; - - } - - public int getSegmentDataLength() { - return segmentDataLength; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/image/BitmapPointer.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/image/BitmapPointer.java deleted file mode 100644 index 7370a1cf38..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/image/BitmapPointer.java +++ /dev/null @@ -1,113 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * BitmapPointer.java - * --------------- - */ -package org.jpedal.jbig2.image; - -public class BitmapPointer { - private int x, y, width, height, bits, count; - private JBIG2Bitmap bitmap; - - public BitmapPointer(JBIG2Bitmap bitmap) { - this.bitmap = bitmap; - this.height = bitmap.getHeight(); - this.width = bitmap.getWidth(); - } - - public void setPointer(int x, int y) { - this.x = x; - this.y = y; - count = 0; - } - - public int nextPixel() { - - // fairly certain the byte can be cached here - seems to work fine. only - // problem would be if cached pixel was modified, and the modified - // version needed. -// if (y < 0 || y >= height || x >= width) { -// return 0; -// } else if (x < 0) { -// x++; -// return 0; -// } -// -// if (count == 0 && width - x >= 8) { -// bits = bitmap.getPixelByte(x, y); -// count = 8; -// } else { -// count = 0; -// } -// -// if (count > 0) { -// int b = bits & 0x01; -// count--; -// bits >>= 1; -// x++; -// return b; -// } -// -// int pixel = bitmap.getPixel(x, y); -// x++; -// -// return pixel; - - if (y < 0 || y >= height || x >= width) { - return 0; - } else if (x < 0) { - x++; - return 0; - } - - int pixel = bitmap.getPixel(x, y); - - x++; - - return pixel; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/image/JBIG2Bitmap.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/image/JBIG2Bitmap.java deleted file mode 100644 index 2f5cfd9a9c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/image/JBIG2Bitmap.java +++ /dev/null @@ -1,1233 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * JBIG2Bitmap.java - * --------------- - */ -package org.jpedal.jbig2.image; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.*; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.awt.image.*; -import java.io.IOException; -import java.util.Arrays; -import java.util.BitSet; - -public final class JBIG2Bitmap { - - private int width, height, line; - private int bitmapNumber; - //private FastBitSet data; - - private BitSet data; - - private static int counter = 0; - - private ArithmeticDecoder arithmeticDecoder; - private HuffmanDecoder huffmanDecoder; - private MMRDecoder mmrDecoder; - - public JBIG2Bitmap(int width, int height, ArithmeticDecoder arithmeticDecoder, HuffmanDecoder huffmanDecoder, MMRDecoder mmrDecoder) { - this.width = width; - this.height = height; - this.arithmeticDecoder = arithmeticDecoder; - this.huffmanDecoder = huffmanDecoder; - this.mmrDecoder = mmrDecoder; - - this.line = (width + 7) >> 3; - - this.data = new BitSet(width * height); - } - - public void readBitmap(boolean useMMR, int template, boolean typicalPredictionGenericDecodingOn, boolean useSkip, JBIG2Bitmap skipBitmap, short[] adaptiveTemplateX, short[] adaptiveTemplateY, int mmrDataLength) throws IOException, JBIG2Exception { - - if (useMMR) { - - //MMRDecoder mmrDecoder = MMRDecoder.getInstance(); - mmrDecoder.reset(); - - int[] referenceLine = new int[width + 2]; - int[] codingLine = new int[width + 2]; - codingLine[0] = codingLine[1] = width; - - for (int row = 0; row < height; row++) { - - int i = 0; - for (; codingLine[i] < width; i++) { - referenceLine[i] = codingLine[i]; - } - referenceLine[i] = referenceLine[i + 1] = width; - - int referenceI = 0; - int codingI = 0; - int a0 = 0; - - do { - int code1 = mmrDecoder.get2DCode(), code2, code3; - - switch (code1) { - case MMRDecoder.twoDimensionalPass: - if (referenceLine[referenceI] < width) { - a0 = referenceLine[referenceI + 1]; - referenceI += 2; - } - break; - case MMRDecoder.twoDimensionalHorizontal: - if ((codingI & 1) != 0) { - code1 = 0; - do { - code1 += code3 = mmrDecoder.getBlackCode(); - } while (code3 >= 64); - - code2 = 0; - do { - code2 += code3 = mmrDecoder.getWhiteCode(); - } while (code3 >= 64); - } else { - code1 = 0; - do { - code1 += code3 = mmrDecoder.getWhiteCode(); - } while (code3 >= 64); - - code2 = 0; - do { - code2 += code3 = mmrDecoder.getBlackCode(); - } while (code3 >= 64); - - } - if (code1 > 0 || code2 > 0) { - a0 = codingLine[codingI++] = a0 + code1; - a0 = codingLine[codingI++] = a0 + code2; - - while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { - referenceI += 2; - } - } - break; - case MMRDecoder.twoDimensionalVertical0: - a0 = codingLine[codingI++] = referenceLine[referenceI]; - if (referenceLine[referenceI] < width) { - referenceI++; - } - - break; - case MMRDecoder.twoDimensionalVerticalR1: - a0 = codingLine[codingI++] = referenceLine[referenceI] + 1; - if (referenceLine[referenceI] < width) { - referenceI++; - while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { - referenceI += 2; - } - } - - break; - case MMRDecoder.twoDimensionalVerticalR2: - a0 = codingLine[codingI++] = referenceLine[referenceI] + 2; - if (referenceLine[referenceI] < width) { - referenceI++; - while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { - referenceI += 2; - } - } - - break; - case MMRDecoder.twoDimensionalVerticalR3: - a0 = codingLine[codingI++] = referenceLine[referenceI] + 3; - if (referenceLine[referenceI] < width) { - referenceI++; - while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { - referenceI += 2; - } - } - - break; - case MMRDecoder.twoDimensionalVerticalL1: - a0 = codingLine[codingI++] = referenceLine[referenceI] - 1; - if (referenceI > 0) { - referenceI--; - } else { - referenceI++; - } - - while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { - referenceI += 2; - } - - break; - case MMRDecoder.twoDimensionalVerticalL2: - a0 = codingLine[codingI++] = referenceLine[referenceI] - 2; - if (referenceI > 0) { - referenceI--; - } else { - referenceI++; - } - - while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { - referenceI += 2; - } - - break; - case MMRDecoder.twoDimensionalVerticalL3: - a0 = codingLine[codingI++] = referenceLine[referenceI] - 3; - if (referenceI > 0) { - referenceI--; - } else { - referenceI++; - } - - while (referenceLine[referenceI] <= a0 && referenceLine[referenceI] < width) { - referenceI += 2; - } - - break; - default: - if (JBIG2StreamDecoder.debug) - System.out.println("Illegal code in JBIG2 MMR bitmap data"); - - break; - } - } while (a0 < width); - - codingLine[codingI++] = width; - - for (int j = 0; codingLine[j] < width; j += 2) { - for (int col = codingLine[j]; col < codingLine[j + 1]; col++) { - setPixel(col, row, 1); - } - } - } - - if (mmrDataLength >= 0) { - mmrDecoder.skipTo(mmrDataLength); - } else { - if (mmrDecoder.get24Bits() != 0x001001) { - if (JBIG2StreamDecoder.debug) - System.out.println("Missing EOFB in JBIG2 MMR bitmap data"); - } - } - - } else { - - //ArithmeticDecoder arithmeticDecoder = ArithmeticDecoder.getInstance(); - - BitmapPointer cxPtr0 = new BitmapPointer(this), cxPtr1 = new BitmapPointer(this); - BitmapPointer atPtr0 = new BitmapPointer(this), atPtr1 = new BitmapPointer(this), atPtr2 = new BitmapPointer(this), atPtr3 = new BitmapPointer(this); - - long ltpCX = 0; - if (typicalPredictionGenericDecodingOn) { - switch (template) { - case 0: - ltpCX = 0x3953; - break; - case 1: - ltpCX = 0x079a; - break; - case 2: - ltpCX = 0x0e3; - break; - case 3: - ltpCX = 0x18a; - break; - } - } - - boolean ltp = false; - long cx, cx0, cx1, cx2; - - for (int row = 0; row < height; row++) { - if (typicalPredictionGenericDecodingOn) { - int bit = arithmeticDecoder.decodeBit(ltpCX, arithmeticDecoder.genericRegionStats); - if (bit != 0) { - ltp = !ltp; - } - - if (ltp) { - duplicateRow(row, row - 1); - continue; - } - } - - int pixel; - - switch (template) { - case 0: - - cxPtr0.setPointer(0, row - 2); - cx0 = cxPtr0.nextPixel(); - cx0 = (BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel(); - - cxPtr1.setPointer(0, row - 1); - cx1 = cxPtr1.nextPixel(); - - cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); - cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); - - cx2 = 0; - - atPtr0.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); - atPtr1.setPointer(adaptiveTemplateX[1], row + adaptiveTemplateY[1]); - atPtr2.setPointer(adaptiveTemplateX[2], row + adaptiveTemplateY[2]); - atPtr3.setPointer(adaptiveTemplateX[3], row + adaptiveTemplateY[3]); - - for (int col = 0; col < width; col++) { - - cx = (BinaryOperation.bit32Shift(cx0, 13, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx1, 8, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx2, 4, BinaryOperation.LEFT_SHIFT)) | (atPtr0.nextPixel() << 3) | (atPtr1.nextPixel() << 2) | (atPtr2.nextPixel() << 1) | atPtr3.nextPixel(); - - if (useSkip && skipBitmap.getPixel(col, row) != 0) { - pixel = 0; - } else { - pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.genericRegionStats); - if (pixel != 0) { - setPixel(col, row, 1); - } - } - - cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 0x07; - cx1 = ((BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel()) & 0x1f; - cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | pixel) & 0x0f; - } - break; - - case 1: - - cxPtr0.setPointer(0, row - 2); - cx0 = cxPtr0.nextPixel(); - cx0 = (BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel(); - cx0 = (BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel(); - - cxPtr1.setPointer(0, row - 1); - cx1 = cxPtr1.nextPixel(); - cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); - cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); - - cx2 = 0; - - atPtr0.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); - - for (int col = 0; col < width; col++) { - - cx = (BinaryOperation.bit32Shift(cx0, 9, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx1, 4, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | atPtr0.nextPixel(); - - if (useSkip && skipBitmap.getPixel(col, row) != 0) { - pixel = 0; - } else { - pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.genericRegionStats); - if (pixel != 0) { - setPixel(col, row, 1); - } - } - - cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 0x0f; - cx1 = ((BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel()) & 0x1f; - cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | pixel) & 0x07; - } - break; - - case 2: - - cxPtr0.setPointer(0, row - 2); - cx0 = cxPtr0.nextPixel(); - cx0 = (BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel(); - - cxPtr1.setPointer(0, row - 1); - cx1 = cxPtr1.nextPixel(); - cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); - - cx2 = 0; - - atPtr0.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); - - for (int col = 0; col < width; col++) { - - cx = (BinaryOperation.bit32Shift(cx0, 7, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx1, 3, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | atPtr0.nextPixel(); - - if (useSkip && skipBitmap.getPixel(col, row) != 0) { - pixel = 0; - } else { - pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.genericRegionStats); - if (pixel != 0) { - setPixel(col, row, 1); - } - } - - cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 0x07; - cx1 = ((BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel()) & 0x0f; - cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | pixel) & 0x03; - } - break; - - case 3: - - cxPtr1.setPointer(0, row - 1); - cx1 = cxPtr1.nextPixel(); - cx1 = (BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel(); - - cx2 = 0; - - atPtr0.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); - - for (int col = 0; col < width; col++) { - - cx = (BinaryOperation.bit32Shift(cx1, 5, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | atPtr0.nextPixel(); - - if (useSkip && skipBitmap.getPixel(col, row) != 0) { - pixel = 0; - - } else { - pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.genericRegionStats); - if (pixel != 0) { - setPixel(col, row, 1); - } - } - - cx1 = ((BinaryOperation.bit32Shift(cx1, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr1.nextPixel()) & 0x1f; - cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | pixel) & 0x0f; - } - break; - } - } - } - } - - public void readGenericRefinementRegion(int template, boolean typicalPredictionGenericRefinementOn, JBIG2Bitmap referredToBitmap, int referenceDX, int referenceDY, short[] adaptiveTemplateX, short[] adaptiveTemplateY) throws IOException, JBIG2Exception { - - //ArithmeticDecoder arithmeticDecoder = ArithmeticDecoder.getInstance(); - - BitmapPointer cxPtr0, cxPtr1, cxPtr2, cxPtr3, cxPtr4, cxPtr5, cxPtr6, typicalPredictionGenericRefinementCXPtr0, typicalPredictionGenericRefinementCXPtr1, typicalPredictionGenericRefinementCXPtr2; - - long ltpCX; - if (template != 0) { - ltpCX = 0x008; - - cxPtr0 = new BitmapPointer(this); - cxPtr1 = new BitmapPointer(this); - cxPtr2 = new BitmapPointer(referredToBitmap); - cxPtr3 = new BitmapPointer(referredToBitmap); - cxPtr4 = new BitmapPointer(referredToBitmap); - cxPtr5 = new BitmapPointer(this); - cxPtr6 = new BitmapPointer(this); - typicalPredictionGenericRefinementCXPtr0 = new BitmapPointer(referredToBitmap); - typicalPredictionGenericRefinementCXPtr1 = new BitmapPointer(referredToBitmap); - typicalPredictionGenericRefinementCXPtr2 = new BitmapPointer(referredToBitmap); - } else { - ltpCX = 0x0010; - - cxPtr0 = new BitmapPointer(this); - cxPtr1 = new BitmapPointer(this); - cxPtr2 = new BitmapPointer(referredToBitmap); - cxPtr3 = new BitmapPointer(referredToBitmap); - cxPtr4 = new BitmapPointer(referredToBitmap); - cxPtr5 = new BitmapPointer(this); - cxPtr6 = new BitmapPointer(referredToBitmap); - typicalPredictionGenericRefinementCXPtr0 = new BitmapPointer(referredToBitmap); - typicalPredictionGenericRefinementCXPtr1 = new BitmapPointer(referredToBitmap); - typicalPredictionGenericRefinementCXPtr2 = new BitmapPointer(referredToBitmap); - } - - long cx, cx0, cx2, cx3, cx4; - long typicalPredictionGenericRefinementCX0, typicalPredictionGenericRefinementCX1, typicalPredictionGenericRefinementCX2; - boolean ltp = false; - - for (int row = 0; row < height; row++) { - - if (template != 0) { - - cxPtr0.setPointer(0, row - 1); - cx0 = cxPtr0.nextPixel(); - - cxPtr1.setPointer(-1, row); - - cxPtr2.setPointer(-referenceDX, row - 1 - referenceDY); - - cxPtr3.setPointer(-1 - referenceDX, row - referenceDY); - cx3 = cxPtr3.nextPixel(); - cx3 = (BinaryOperation.bit32Shift(cx3, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr3.nextPixel(); - - cxPtr4.setPointer(-referenceDX, row + 1 - referenceDY); - cx4 = cxPtr4.nextPixel(); - - typicalPredictionGenericRefinementCX0 = typicalPredictionGenericRefinementCX1 = typicalPredictionGenericRefinementCX2 = 0; - - if (typicalPredictionGenericRefinementOn) { - typicalPredictionGenericRefinementCXPtr0.setPointer(-1 - referenceDX, row - 1 - referenceDY); - typicalPredictionGenericRefinementCX0 = typicalPredictionGenericRefinementCXPtr0.nextPixel(); - typicalPredictionGenericRefinementCX0 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel(); - typicalPredictionGenericRefinementCX0 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel(); - - typicalPredictionGenericRefinementCXPtr1.setPointer(-1 - referenceDX, row - referenceDY); - typicalPredictionGenericRefinementCX1 = typicalPredictionGenericRefinementCXPtr1.nextPixel(); - typicalPredictionGenericRefinementCX1 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel(); - typicalPredictionGenericRefinementCX1 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel(); - - typicalPredictionGenericRefinementCXPtr2.setPointer(-1 - referenceDX, row + 1 - referenceDY); - typicalPredictionGenericRefinementCX2 = typicalPredictionGenericRefinementCXPtr2.nextPixel(); - typicalPredictionGenericRefinementCX2 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel(); - typicalPredictionGenericRefinementCX2 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel(); - } - - for (int col = 0; col < width; col++) { - - cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 7; - cx3 = ((BinaryOperation.bit32Shift(cx3, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr3.nextPixel()) & 7; - cx4 = ((BinaryOperation.bit32Shift(cx4, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr4.nextPixel()) & 3; - - if (typicalPredictionGenericRefinementOn) { - typicalPredictionGenericRefinementCX0 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel()) & 7; - typicalPredictionGenericRefinementCX1 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel()) & 7; - typicalPredictionGenericRefinementCX2 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel()) & 7; - - int decodeBit = arithmeticDecoder.decodeBit(ltpCX, arithmeticDecoder.refinementRegionStats); - if (decodeBit != 0) { - ltp = !ltp; - } - if (typicalPredictionGenericRefinementCX0 == 0 && typicalPredictionGenericRefinementCX1 == 0 && typicalPredictionGenericRefinementCX2 == 0) { - setPixel(col, row, 0); - continue; - } else if (typicalPredictionGenericRefinementCX0 == 7 && typicalPredictionGenericRefinementCX1 == 7 && typicalPredictionGenericRefinementCX2 == 7) { - setPixel(col, row, 1); - continue; - } - } - - cx = (BinaryOperation.bit32Shift(cx0, 7, BinaryOperation.LEFT_SHIFT)) | (cxPtr1.nextPixel() << 6) | (cxPtr2.nextPixel() << 5) | (BinaryOperation.bit32Shift(cx3, 2, BinaryOperation.LEFT_SHIFT)) | cx4; - - int pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.refinementRegionStats); - if (pixel == 1) { - setPixel(col, row, 1); - } - } - - } else { - - cxPtr0.setPointer(0, row - 1); - cx0 = cxPtr0.nextPixel(); - - cxPtr1.setPointer(-1, row); - - cxPtr2.setPointer(-referenceDX, row - 1 - referenceDY); - cx2 = cxPtr2.nextPixel(); - - cxPtr3.setPointer(-1 - referenceDX, row - referenceDY); - cx3 = cxPtr3.nextPixel(); - cx3 = (BinaryOperation.bit32Shift(cx3, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr3.nextPixel(); - - cxPtr4.setPointer(-1 - referenceDX, row + 1 - referenceDY); - cx4 = cxPtr4.nextPixel(); - cx4 = (BinaryOperation.bit32Shift(cx4, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr4.nextPixel(); - - cxPtr5.setPointer(adaptiveTemplateX[0], row + adaptiveTemplateY[0]); - - cxPtr6.setPointer(adaptiveTemplateX[1] - referenceDX, row + adaptiveTemplateY[1] - referenceDY); - - typicalPredictionGenericRefinementCX0 = typicalPredictionGenericRefinementCX1 = typicalPredictionGenericRefinementCX2 = 0; - if (typicalPredictionGenericRefinementOn) { - typicalPredictionGenericRefinementCXPtr0.setPointer(-1 - referenceDX, row - 1 - referenceDY); - typicalPredictionGenericRefinementCX0 = typicalPredictionGenericRefinementCXPtr0.nextPixel(); - typicalPredictionGenericRefinementCX0 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel(); - typicalPredictionGenericRefinementCX0 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel(); - - typicalPredictionGenericRefinementCXPtr1.setPointer(-1 - referenceDX, row - referenceDY); - typicalPredictionGenericRefinementCX1 = typicalPredictionGenericRefinementCXPtr1.nextPixel(); - typicalPredictionGenericRefinementCX1 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel(); - typicalPredictionGenericRefinementCX1 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel(); - - typicalPredictionGenericRefinementCXPtr2.setPointer(-1 - referenceDX, row + 1 - referenceDY); - typicalPredictionGenericRefinementCX2 = typicalPredictionGenericRefinementCXPtr2.nextPixel(); - typicalPredictionGenericRefinementCX2 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel(); - typicalPredictionGenericRefinementCX2 = (BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel(); - } - - for (int col = 0; col < width; col++) { - - cx0 = ((BinaryOperation.bit32Shift(cx0, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr0.nextPixel()) & 3; - cx2 = ((BinaryOperation.bit32Shift(cx2, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr2.nextPixel()) & 3; - cx3 = ((BinaryOperation.bit32Shift(cx3, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr3.nextPixel()) & 7; - cx4 = ((BinaryOperation.bit32Shift(cx4, 1, BinaryOperation.LEFT_SHIFT)) | cxPtr4.nextPixel()) & 7; - - if (typicalPredictionGenericRefinementOn) { - typicalPredictionGenericRefinementCX0 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX0, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr0.nextPixel()) & 7; - typicalPredictionGenericRefinementCX1 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX1, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr1.nextPixel()) & 7; - typicalPredictionGenericRefinementCX2 = ((BinaryOperation.bit32Shift(typicalPredictionGenericRefinementCX2, 1, BinaryOperation.LEFT_SHIFT)) | typicalPredictionGenericRefinementCXPtr2.nextPixel()) & 7; - - int decodeBit = arithmeticDecoder.decodeBit(ltpCX, arithmeticDecoder.refinementRegionStats); - if (decodeBit == 1) { - ltp = !ltp; - } - if (typicalPredictionGenericRefinementCX0 == 0 && typicalPredictionGenericRefinementCX1 == 0 && typicalPredictionGenericRefinementCX2 == 0) { - setPixel(col, row, 0); - continue; - } else if (typicalPredictionGenericRefinementCX0 == 7 && typicalPredictionGenericRefinementCX1 == 7 && typicalPredictionGenericRefinementCX2 == 7) { - setPixel(col, row, 1); - continue; - } - } - - cx = (BinaryOperation.bit32Shift(cx0, 11, BinaryOperation.LEFT_SHIFT)) | (cxPtr1.nextPixel() << 10) | (BinaryOperation.bit32Shift(cx2, 8, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx3, 5, BinaryOperation.LEFT_SHIFT)) | (BinaryOperation.bit32Shift(cx4, 2, BinaryOperation.LEFT_SHIFT)) | (cxPtr5.nextPixel() << 1) | cxPtr6.nextPixel(); - - int pixel = arithmeticDecoder.decodeBit(cx, arithmeticDecoder.refinementRegionStats); - if (pixel == 1) { - setPixel(col, row, 1); - } - } - } - } - } - - public void readTextRegion(boolean huffman, boolean symbolRefine, int noOfSymbolInstances, int logStrips, int noOfSymbols, int[][] symbolCodeTable, int symbolCodeLength, JBIG2Bitmap[] symbols, int defaultPixel, int combinationOperator, boolean transposed, int referenceCorner, int sOffset, int[][] huffmanFSTable, int[][] huffmanDSTable, int[][] huffmanDTTable, int[][] huffmanRDWTable, int[][] huffmanRDHTable, int[][] huffmanRDXTable, int[][] huffmanRDYTable, int[][] huffmanRSizeTable, int template, short[] symbolRegionAdaptiveTemplateX, - short[] symbolRegionAdaptiveTemplateY, JBIG2StreamDecoder decoder) throws JBIG2Exception, IOException { - - JBIG2Bitmap symbolBitmap; - - int strips = 1 << logStrips; - - clear(defaultPixel); - - //HuffmanDecoder huffDecoder = HuffmanDecoder.getInstance(); - //ArithmeticDecoder arithmeticDecoder = ArithmeticDecoder.getInstance(); - - int t; - if (huffman) { - t = huffmanDecoder.decodeInt(huffmanDTTable).intResult(); - } else { - t = arithmeticDecoder.decodeInt(arithmeticDecoder.iadtStats).intResult(); - } - t *= -strips; - - int currentInstance = 0; - int firstS = 0; - int dt, tt, ds, s; - while (currentInstance < noOfSymbolInstances) { - - if (huffman) { - dt = huffmanDecoder.decodeInt(huffmanDTTable).intResult(); - } else { - dt = arithmeticDecoder.decodeInt(arithmeticDecoder.iadtStats).intResult(); - } - t += dt * strips; - - if (huffman) { - ds = huffmanDecoder.decodeInt(huffmanFSTable).intResult(); - } else { - ds = arithmeticDecoder.decodeInt(arithmeticDecoder.iafsStats).intResult(); - } - firstS += ds; - s = firstS; - - while (true) { - - if (strips == 1) { - dt = 0; - } else if (huffman) { - dt = decoder.readBits(logStrips); - } else { - dt = arithmeticDecoder.decodeInt(arithmeticDecoder.iaitStats).intResult(); - } - tt = t + dt; - - long symbolID; - if (huffman) { - if (symbolCodeTable != null) { - symbolID = huffmanDecoder.decodeInt(symbolCodeTable).intResult(); - } else { - symbolID = decoder.readBits(symbolCodeLength); - } - } else { - symbolID = arithmeticDecoder.decodeIAID(symbolCodeLength, arithmeticDecoder.iaidStats); - } - - if (symbolID >= noOfSymbols) { - if (JBIG2StreamDecoder.debug) - System.out.println("Invalid symbol number in JBIG2 text region"); - } else { - // symbolBitmap = null; - - int ri; - if (symbolRefine) { - if (huffman) { - ri = decoder.readBit(); - } else { - ri = arithmeticDecoder.decodeInt(arithmeticDecoder.iariStats).intResult(); - } - } else { - ri = 0; - } - if (ri != 0) { - - int refinementDeltaWidth, refinementDeltaHeight, refinementDeltaX, refinementDeltaY; - - if (huffman) { - refinementDeltaWidth = huffmanDecoder.decodeInt(huffmanRDWTable).intResult(); - refinementDeltaHeight = huffmanDecoder.decodeInt(huffmanRDHTable).intResult(); - refinementDeltaX = huffmanDecoder.decodeInt(huffmanRDXTable).intResult(); - refinementDeltaY = huffmanDecoder.decodeInt(huffmanRDYTable).intResult(); - - decoder.consumeRemainingBits(); - arithmeticDecoder.start(); - } else { - refinementDeltaWidth = arithmeticDecoder.decodeInt(arithmeticDecoder.iardwStats).intResult(); - refinementDeltaHeight = arithmeticDecoder.decodeInt(arithmeticDecoder.iardhStats).intResult(); - refinementDeltaX = arithmeticDecoder.decodeInt(arithmeticDecoder.iardxStats).intResult(); - refinementDeltaY = arithmeticDecoder.decodeInt(arithmeticDecoder.iardyStats).intResult(); - } - refinementDeltaX = ((refinementDeltaWidth >= 0) ? refinementDeltaWidth : refinementDeltaWidth - 1) / 2 + refinementDeltaX; - refinementDeltaY = ((refinementDeltaHeight >= 0) ? refinementDeltaHeight : refinementDeltaHeight - 1) / 2 + refinementDeltaY; - - symbolBitmap = new JBIG2Bitmap(refinementDeltaWidth + symbols[(int) symbolID].width, refinementDeltaHeight + symbols[(int) symbolID].height, arithmeticDecoder, huffmanDecoder, mmrDecoder); - - symbolBitmap.readGenericRefinementRegion(template, false, symbols[(int) symbolID], refinementDeltaX, refinementDeltaY, symbolRegionAdaptiveTemplateX, symbolRegionAdaptiveTemplateY); - - } else { - symbolBitmap = symbols[(int) symbolID]; - } - - int bitmapWidth = symbolBitmap.width - 1; - int bitmapHeight = symbolBitmap.height - 1; - if (transposed) { - switch (referenceCorner) { - case 0: // bottom left - combine(symbolBitmap, tt, s, combinationOperator); - break; - case 1: // top left - combine(symbolBitmap, tt, s, combinationOperator); - break; - case 2: // bottom right - combine(symbolBitmap, tt - bitmapWidth, s, combinationOperator); - break; - case 3: // top right - combine(symbolBitmap, tt - bitmapWidth, s, combinationOperator); - break; - } - s += bitmapHeight; - } else { - switch (referenceCorner) { - case 0: // bottom left - combine(symbolBitmap, s, tt - bitmapHeight, combinationOperator); - break; - case 1: // top left - combine(symbolBitmap, s, tt, combinationOperator); - break; - case 2: // bottom right - combine(symbolBitmap, s, tt - bitmapHeight, combinationOperator); - break; - case 3: // top right - combine(symbolBitmap, s, tt, combinationOperator); - break; - } - s += bitmapWidth; - } - } - - currentInstance++; - - DecodeIntResult decodeIntResult; - - if (huffman) { - decodeIntResult = huffmanDecoder.decodeInt(huffmanDSTable); - } else { - decodeIntResult = arithmeticDecoder.decodeInt(arithmeticDecoder.iadsStats); - } - - if (!decodeIntResult.booleanResult()) { - break; - } - - ds = decodeIntResult.intResult(); - - s += sOffset + ds; - } - } - } - - public void clear(int defPixel) { - data.set(0, data.size(), defPixel == 1); - } - - public void combine(JBIG2Bitmap bitmap, int x, int y, long combOp) { - int srcWidth = bitmap.width; - int srcHeight = bitmap.height; - int srcRow = 0, srcCol = 0; - -// int maxRow = y + srcHeight; -// int maxCol = x + srcWidth; -// -// for (int row = y; row < maxRow; row++) { -// for (int col = x; col < maxCol; srcCol += 8, col += 8) { -// -// byte srcPixelByte = bitmap.getPixelByte(srcCol, srcRow); -// byte dstPixelByte = getPixelByte(col, row); -// byte endPixelByte; -// -// switch ((int) combOp) { -// case 0: // or -// endPixelByte = (byte) (dstPixelByte | srcPixelByte); -// break; -// case 1: // and -// endPixelByte = (byte) (dstPixelByte & srcPixelByte); -// break; -// case 2: // xor -// endPixelByte = (byte) (dstPixelByte ^ srcPixelByte); -// break; -// case 3: // xnor -// endPixelByte = (byte) ~(dstPixelByte ^ srcPixelByte); -// break; -// case 4: // replace -// default: -// endPixelByte = srcPixelByte; -// break; -// } -// int used = maxCol - col; -// if (used < 8) { -// // mask bits -// endPixelByte = (byte) ((endPixelByte & (0xFF >> (8 - used))) | (dstPixelByte & (0xFF << (used)))); -// } -// setPixelByte(col, row, endPixelByte); -// } -// -// srcCol = 0; -// srcRow++; - - for (int row = y; row < y + srcHeight; row++) { - for (int col = x; col < x + srcWidth; col++) { - - int srcPixel = bitmap.getPixel(srcCol, srcRow); - - switch ((int) combOp) { - case 0: // or - setPixel(col, row, getPixel(col, row) | srcPixel); - break; - case 1: // and - setPixel(col, row, getPixel(col, row) & srcPixel); - break; - case 2: // xor - setPixel(col, row, getPixel(col, row) ^ srcPixel); - break; - case 3: // xnor - if ((getPixel(col, row) == 1 && srcPixel == 1) || (getPixel(col, row) == 0 && srcPixel == 0)) - setPixel(col, row, 1); - else - setPixel(col, row, 0); - - break; - case 4: // replace - setPixel(col, row, srcPixel); - break; - } - srcCol++; - } - - srcCol = 0; - srcRow++; - } - } - - /** - * set a full byte of pixels - */ -// private void setPixelByte(int col, int row, byte bits) { - //data.setByte(row, col, bits); -// } - - /** - * get a byte of pixels - */ -// public byte getPixelByte(int col, int row) { - //return data.getByte(row, col); -// } - private void duplicateRow(int yDest, int ySrc) { -// for (int i = 0; i < width;) { -// setPixelByte(i, yDest, getPixelByte(i, ySrc)); -// i += 8; -// } - for (int i = 0; i < width; i++) { - setPixel(i, yDest, getPixel(i, ySrc)); - } - } - - public int getWidth() { - return width; - } - - public int getHeight() { - return height; - } - - public byte[] getData(boolean switchPixelColor) { -// byte[] bytes = new byte[height * line]; -// -// for (int i = 0; i < height; i++) { -// System.arraycopy(data.bytes[i], 0, bytes, line * i, line); -// } -// -// for (int i = 0; i < bytes.length; i++) { -// // reverse bits -// -// int value = bytes[i]; -// value = (value & 0x0f) << 4 | (value & 0xf0) >> 4; -// value = (value & 0x33) << 2 | (value & 0xcc) >> 2; -// value = (value & 0x55) << 1 | (value & 0xaa) >> 1; -// -// if (switchPixelColor) { -// value ^= 0xff; -// } -// -// bytes[i] = (byte) (value & 0xFF); -// } -// -// return bytes; - byte[] bytes = new byte[height * line]; - getData(bytes, switchPixelColor); - return bytes; - } - - public void getData(byte[] bytes, boolean switchPixelColor) { - int count = 0, offset = 0; - for (int row = 0; row < height; row++) { - for (int col = 0; col < width; col++) { - if (data.get(count)) { - int bite = (count + offset) / 8; - int bit = (count + offset) % 8; - - bytes[bite] |= 1 << (7 - bit); - } - count++; - } - - offset = (line * 8 * (row + 1)) - count; - } - - if (switchPixelColor) { - for (int i = 0; i < bytes.length; i++) { - bytes[i] ^= 0xff; - } - } - } - - public JBIG2Bitmap getSlice(int x, int y, int width, int height) { -// JBIG2Bitmap slice = new JBIG2Bitmap(width, height); -// -// int sliceRow = 0, sliceCol = 0; -// int maxCol = x + width; -// -// //ShowGUIMessage.showGUIMessage("x", this.getBufferedImage(), "xx"); -// -// System.out.println(">>> getSlice x = "+x+" y = "+y+ " width = "+width+ " height = "+height); -// System.out.println(">>> baseImage width = "+this.width+ " height = "+this.height); -// -// System.out.println("counter = "+counter); -// if(counter == 17){ -// System.out.println(); -// //ShowGUIMessage.showGUIMessage("x", this.getBufferedImage(), "xx"); -// } -// -// ShowGUIMessage.showGUIMessage("x", this.getBufferedImage(), "xx"); -// -// for (int row = y; row < height; row++) { -// for (int col = x; col < maxCol; col += 8, sliceCol += 8) { -// slice.setPixelByte(sliceCol, sliceRow, getPixelByte(col, row)); -// //if(counter > 10) -// //ShowGUIMessage.showGUIMessage("new", slice.getBufferedImage(), "new"); -// } -// sliceCol = 0; -// sliceRow++; -// } -// counter++; -// -// ShowGUIMessage.showGUIMessage("new", slice.getBufferedImage(), "new"); -// -// return slice; - - JBIG2Bitmap slice = new JBIG2Bitmap(width, height, arithmeticDecoder, huffmanDecoder, mmrDecoder); - - int sliceRow = 0, sliceCol = 0; - for (int row = y; row < height; row++) { - for (int col = x; col < x + width; col++) { - //System.out.println("row = "+row +" column = "+col); - slice.setPixel(sliceCol, sliceRow, getPixel(col, row)); - sliceCol++; - } - sliceCol = 0; - sliceRow++; - } - - return slice; - } - - private void setPixel(int col, int row, FastBitSet data, int value) { - if (value == 1) - data.set(row, col); - else - data.clear(row, col); - } - -// private void setPixelByte(int col, int row, FastBitSet data, byte bits) { -// data.setByte(row, col, bits); -// } - -// public void setPixel(int col, int row, int value) { -// setPixel(col, row, data, value); -// } - -// public int getPixel(int col, int row) { -// return data.get(row, col) ? 1 : 0; -// } - - private void setPixel(int col, int row, BitSet data, int value) { - int index = (row * width) + col; - - data.set(index, value == 1); - } - - public void setPixel(int col, int row, int value) { - setPixel(col, row, data, value); - } - - public int getPixel(int col, int row) { - // compensate for PDF-675 - if (row < 0) { - row = 0; - } - return data.get((row * width) + col) ? 1 : 0; - } - - public void expand(int newHeight, int defaultPixel) { -// System.out.println("expand FastBitSet"); -// FastBitSet newData = new FastBitSet(width, newHeight); -// -// for (int row = 0; row < height; row++) { -// for (int col = 0; col < width; col += 8) { -// setPixelByte(col, row, newData, getPixelByte(col, row)); -// } -// } -// -// this.height = newHeight; -// this.data = newData; - BitSet newData = new BitSet(newHeight * width); - - for (int row = 0; row < height; row++) { - for (int col = 0; col < width; col++) { - setPixel(col, row, newData, getPixel(col, row)); - } - } - - this.height = newHeight; - this.data = newData; - } - - public void setBitmapNumber(int segmentNumber) { - this.bitmapNumber = segmentNumber; - } - - public int getBitmapNumber() { - return bitmapNumber; - } - - public BufferedImage getBufferedImage() { - byte[] bytes = getData(true); - - if (bytes == null) - return null; - - // make a a DEEP copy so we can't alter - int len = bytes.length; - byte[] copy = new byte[len]; - System.arraycopy(bytes, 0, copy, 0, len); - - /** create an image from the raw data */ - DataBuffer db = new DataBufferByte(copy, copy.length); - - WritableRaster raster = Raster.createPackedRaster(db, width, height, 1, null); - - BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY); - image.setData(raster); - - return image; - } - - static final class FastBitSet { - byte[][] bytes; - - int w, h; - - public FastBitSet(int width, int height) { - bytes = new byte[height][(width + 7) / 8]; - this.w = width; - this.h = height; - //System.out.println("width = "+width+" height = "+height); - } - -// public int getByte(int row, int col) { -// -// System.out.println("(width + 7) / 8 = " + (width + 7) / 8); -// System.out.println("external width = " + width + " external height = " + height); -// System.out.println("internal width = " + w + " internal height = " + h); -// System.out.println("row = " + row + " column = " + col); -// -// int offset = col / 8; -// int mod = col % 8; -// -// System.out.println("offset = " + offset + " mod = " + mod+" bytes[row].length = "+bytes[row].length); -// -// if (mod == 0) -// return bytes[row][offset]; -// -// if(offset == bytes[row].length - 1){ -// System.out.println("returning"); -// return ((bytes[row][offset] & 0xFF) >> mod); -// } -// -// int left = ((bytes[row][offset] & 0xFF) >> mod); -// int right = ((bytes[row][offset + 1] & 0xFF) << (8 - mod)); -// -// return left | right; -// } - -// public void setByte(int row, int col, int bits) { -// int offset = col / 8; -// int mod = col % 8; -// -// System.out.println("setByte offset = " + offset + " mod = " + mod); -// -// -// if (mod == 0) -// bytes[row][offset] = (byte) bits; -// else { -// int mask = 0xFF >> (8 - mod); -// System.out.println("setByte mask = " + mask); -// bytes[row][offset] = (byte) ((bytes[row][offset] & mask) | ((bits & 0xFF) << mod)); -// bytes[row][offset + 1] = (byte) ((bytes[row][offset + 1] & ~mask) | ((bits & 0xFF) >> (8 - mod))); -// } -// } - - public byte getByte(int row, int col) { -// System.out.println("(width + 7) / 8 = " + (width + 7) / 8); -// System.out.println("external width = " + width + " external height = " + height); -// System.out.println("internal width = " + w + " internal height = " + h); -// System.out.println("row = " + row + " column = " + col); - - int offset = col / 8; - int mod = col % 8; - -// System.out.println("offset = " + offset + " mod = " + mod+" bytes[row].length = "+bytes[row].length); - - if (mod == 0) - return bytes[row][offset]; - -// if(offset == bytes[row].length - 1){ -// System.out.println("returning"); -// return ((bytes[row][offset] & 0xFF) >> mod); -// } - - byte leftMask = (byte) (0xFF >> (8 - mod)); - byte rightMask = (byte) (0xFF << mod); - - byte left = (byte) ((bytes[row][offset] & leftMask) << (8 - mod)); - - if (offset + 1 >= bytes[row].length) { - System.out.println("returning"); - return left; - } - - byte right = (byte) ((bytes[row][offset + 1] & rightMask) >> mod); - - return (byte) (left | right); - } - - public void setByte(int row, int col, byte bits) { - int offset = col / 8; - int mod = col % 8; - - //System.out.println("setByte offset = " + offset + " mod = " + mod); - - - if (mod == 0) - bytes[row][offset] = bits; - else { - - byte left = (byte) (bits >> mod); - byte leftMask = (byte) (0xFF << (8 - mod)); - - bytes[row][offset] &= leftMask; - bytes[row][offset] |= left; - - if (offset + 1 >= bytes[row].length) - return; - - byte right = (byte) (bits << (8 - mod)); - byte rightMask = (byte) (0xFF >> mod); - - bytes[row][offset + 1] &= rightMask; - bytes[row][offset + 1] |= right; - -// int mask = 0xFF >> (8 - mod); -// System.out.println("setByte mask = " + mask); -// bytes[row][offset] = (byte) ((bytes[row][offset] & mask) | ((bits & 0xFF) << mod)); -// bytes[row][offset + 1] = (byte) ((bytes[row][offset + 1] & ~mask) | ((bits & 0xFF) >> (8 - mod))); - } - } - - public void set(int row, int col) { - byte bit = (byte) (1 << (col % 8)); - bytes[row][col / 8] |= bit; - } - - public void clear(int row, int col) { - byte bit = (byte) (1 << (col % 8)); - bytes[row][col / 8] &= ~bit; - } - - public boolean get(int row, int col) { - byte bit = (byte) (1 << (col % 8)); - return (bytes[row][col / 8] & bit) != 0; - } - - public void reset(boolean set) { - for (byte[] aByte : bytes) - Arrays.fill(aByte, set ? (byte) 0xFF : (byte) 0x00); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/io/StreamReader.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/io/StreamReader.java deleted file mode 100644 index f123b721c2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/io/StreamReader.java +++ /dev/null @@ -1,135 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* StreamReader.java -* --------------- - */ -package org.jpedal.jbig2.io; - -import org.jpedal.jbig2.examples.pdf.PDFSegment; - -import java.io.IOException; - -public class StreamReader { - private byte[] data; - - private int bitPointer = 7; - - private int bytePointer = 0; - - public StreamReader(byte[] data) { - this.data = data; - } - - public short readByte(PDFSegment pdfSeg) { - short bite = (short) (data[bytePointer++] & 255); - - if (pdfSeg != null) - pdfSeg.writeToHeader(bite); - - return bite; - } - - public void readByte(short[] buf, PDFSegment pdfSeg) throws IOException { - for (int i = 0; i < buf.length; i++) { - buf[i] = (short) (data[bytePointer++] & 255); - } - - if (pdfSeg != null) - pdfSeg.writeToHeader(buf); - } - - public short readByte() { - short bite = (short) (data[bytePointer++] & 255); - - return bite; - } - - public void readByte(short[] buf) { - for (int i = 0; i < buf.length; i++) { - buf[i] = (short) (data[bytePointer++] & 255); - } - } - - public int readBit() { - short buf = readByte(); - short mask = (short) (1 << bitPointer); - - int bit = (buf & mask) >> bitPointer; - - bitPointer--; - if (bitPointer == -1) { - bitPointer = 7; - } else { - movePointer(-1); - } - - return bit; - } - - public int readBits(int num) { - int result = 0; - - for (int i = 0; i < num; i++) { - result = (result << 1) | readBit(); - } - - return result; - } - - public void movePointer(int ammount) { - bytePointer += ammount; - } - - public void consumeRemainingBits() { - if (bitPointer != 7) - readBits(bitPointer + 1); - } - - public boolean isFinished() { - return bytePointer == data.length; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/jai/JBIG2ImageReader.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/jai/JBIG2ImageReader.java deleted file mode 100644 index 2815027f88..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/jai/JBIG2ImageReader.java +++ /dev/null @@ -1,519 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * JBIG2ImageReader.java - * --------------- - */ -package org.jpedal.jbig2.jai; - -import org.jpedal.jbig2.JBIG2Decoder; -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.image.JBIG2Bitmap; - -import javax.imageio.ImageReadParam; -import javax.imageio.ImageReader; -import javax.imageio.ImageTypeSpecifier; -import javax.imageio.metadata.IIOMetadata; -import javax.imageio.spi.ImageReaderSpi; -import javax.imageio.stream.ImageInputStream; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.awt.image.DataBufferByte; -import java.awt.image.Raster; -import java.awt.image.WritableRaster; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class JBIG2ImageReader extends ImageReader { - - private static final Logger logger = - Logger.getLogger(JBIG2ImageReader.class.toString()); - - private JBIG2Decoder decoder; - private ImageInputStream stream; - private boolean readFile; - - protected JBIG2ImageReader(ImageReaderSpi originatingProvider) { - // Save the identity of the ImageReaderSpi subclass that invoked this - // constructor. - super(originatingProvider); - } - - public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) { - super.setInput(input, seekForwardOnly, ignoreMetadata); - - if (input == null) { - this.stream = null; - return; - } - - // The input source must be an ImageInputStream because the originating - // provider -- the JBIG2ImageReaderSpi class -- passes - // STANDARD_INPUT_TYPE - // -- an array consisting only of ImageInputStream -- to its superclass - // in its constructor call. - - if (input instanceof ImageInputStream) - this.stream = (ImageInputStream) input; - else - throw new IllegalArgumentException("ImageInputStream expected!"); - } - - public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException { - - BufferedImage dst = null; - try { - // Calculate and return a Rectangle that identifies the region of - // the - // source image that should be read: - // - // 1. If param is null, the upper-left corner of the region is (0, - // 0), - // and the width and height are specified by the width and height - // arguments. In other words, the entire image is read. - // - // 2. If param is not null - // - // 2.1 If param.getSourceRegion() returns a non-null Rectangle, the - // region is calculated as the intersection of param's Rectangle - // and the earlier (0, 0, width, height Rectangle). - // - // 2.2 param.getSubsamplingXOffset() is added to the region's x - // coordinate and subtracted from its width. - // - // 2.3 param.getSubsamplingYOffset() is added to the region's y - // coordinate and subtracted from its height. - - int width = getWidth(imageIndex); - int height = getHeight(imageIndex); - - Rectangle sourceRegion = getSourceRegion(param, width, height); - - // Source subsampling is used to return a scaled-down source image. - // Default 1 values for X and Y subsampling indicate that a - // non-scaled - // source image will be returned. - - int sourceXSubsampling = 1; - int sourceYSubsampling = 1; - - // The destination offset determines the starting location in the - // destination where decoded pixels are placed. Default (0, 0) - // values indicate the upper-left corner. - - Point destinationOffset = new Point(0, 0); - - // If param is not null, override the source subsampling, and - // destination offset defaults. - - if (param != null) { - sourceXSubsampling = param.getSourceXSubsampling(); - sourceYSubsampling = param.getSourceYSubsampling(); - destinationOffset = param.getDestinationOffset(); - } - - // Obtain a BufferedImage into which decoded pixels will be placed. - // This destination will be returned to the application. - // - // 1. If param is not null - // - // 1.1 If param.getDestination() returns a BufferedImage - // - // 1.1.1 Return this BufferedImage - // - // Else - // - // 1.1.2 Invoke param.getDestinationType (). - // - // 1.1.3 If the returned ImageTypeSpecifier equals - // getImageTypes (0) (see below), return its BufferedImage. - // - // 2. If param is null or a BufferedImage has not been obtained - // - // 2.1 Return getImageTypes (0)'s BufferedImage. - - dst = getDestination(param, getImageTypes(0), width, height); - - // Create a WritableRaster for the destination. - - WritableRaster wrDst = dst.getRaster(); - - JBIG2Bitmap bitmap = decoder.getPageAsJBIG2Bitmap(imageIndex).getSlice(sourceRegion.x, sourceRegion.y, sourceRegion.width, sourceRegion.height); - - BufferedImage image = bitmap.getBufferedImage(); - - int newWidth = (int) (image.getWidth() * (1 / (double) sourceXSubsampling)); - int newHeight = (int) (image.getHeight() * (1 / (double) sourceYSubsampling)); - - BufferedImage scaledImage = scaleImage(image.getRaster(), newWidth, newHeight, 1, 1); - - Raster raster; - - if (scaledImage != null) { - raster = scaledImage.getRaster(); - } else - raster = image.getRaster(); - - wrDst.setRect(destinationOffset.x, destinationOffset.y, raster); - - } catch (RuntimeException e) { - logger.log(Level.FINE, "Error reading JBIG2 image data", e); - } - - return dst; - - } - - public IIOMetadata getImageMetadata(int imageIndex) throws IOException { - return null; - } - - public IIOMetadata getStreamMetadata() throws IOException { - return null; - } - - public Iterator getImageTypes(int imageIndex) throws IOException { - readFile(); - - checkIndex(imageIndex); - - // Create a List of ImageTypeSpecifiers that identify the possible image - // types to which the single JBIG2 image can be decoded. An - // ImageTypeSpecifier is used with ImageReader's getDestination() method - // to return an appropriate BufferedImage that contains the decoded - // image, and is accessed by an application. - - List l = new ArrayList(); - - // The JBIG2 reader only uses a single List entry. This entry describes - // a - // BufferedImage of TYPE_INT_RGB, which is a commonly used image type. - - l.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_BINARY)); - - // Return an iterator that retrieves elements from the list. - - return l.iterator(); - } - - public int getNumImages(boolean allowSearch) throws IOException { - readFile(); - - return decoder.getNumberOfPages(); - } - - public int getHeight(int imageIndex) throws IOException { - readFile(); - - checkIndex(imageIndex); - - return decoder.getPageAsJBIG2Bitmap(imageIndex).getHeight(); - } - - public int getWidth(int imageIndex) throws IOException { - readFile(); - - checkIndex(imageIndex); - - return decoder.getPageAsJBIG2Bitmap(imageIndex).getWidth(); - } - - private void checkIndex(int imageIndex) { - int noOfPages = decoder.getNumberOfPages(); - if (imageIndex < 0 || imageIndex > noOfPages) - throw new IndexOutOfBoundsException("Bad index!"); - } - - private static BufferedImage scaleImage(Raster ras, int pX, int pY, int comp, int d) { - - int w = ras.getWidth(); - int h = ras.getHeight(); - - byte[] data = ((DataBufferByte) ras.getDataBuffer()).getData(); - - // see what we could reduce to and still be big enough for page - int newW = w, newH = h; - - int sampling = 1; - int smallestH = pY << 2; // double so comparison works - int smallestW = pX << 2; - - // cannot be smaller than page - while (newW > smallestW && newH > smallestH) { - sampling = sampling << 1; - newW = newW >> 1; - newH = newH >> 1; - } - - int scaleX = w / pX; - if (scaleX < 1) - scaleX = 1; - - int scaleY = h / pY; - if (scaleY < 1) - scaleY = 1; - - // choose smaller value so at least size of page - sampling = scaleX; - if (sampling > scaleY) - sampling = scaleY; - - // switch to 8 bit and reduce bw image size by averaging - if (sampling > 1) { - - newW = w / sampling; - newH = h / sampling; - - if (d == 1) { - - int size = newW * newH; - - byte[] newData = new byte[size]; - - final int[] flag = {1, 2, 4, 8, 16, 32, 64, 128}; - - int origLineLength = (w + 7) >> 3; - - int bit; - byte currentByte; - - // scan all pixels and down-sample - for (int y = 0; y < newH; y++) { - for (int x = 0; x < newW; x++) { - - int bytes = 0, count = 0; - - // allow for edges in number of pixels left - int wCount = sampling, hCount = sampling; - int wGapLeft = w - x; - int hGapLeft = h - y; - if (wCount > wGapLeft) - wCount = wGapLeft; - if (hCount > hGapLeft) - hCount = hGapLeft; - - // count pixels in sample we will make into a pixel (ie - // 2x2 is 4 pixels , 4x4 is 16 pixels) - for (int yy = 0; yy < hCount; yy++) { - for (int xx = 0; xx < wCount; xx++) { - - currentByte = data[((yy + (y * sampling)) * origLineLength) + (((x * sampling) + xx) >> 3)]; - - bit = currentByte & flag[7 - (((x * sampling) + xx) & 7)]; - - if (bit != 0) - bytes++; - count++; - } - } - - // set value as white or average of pixels - int offset = x + (newW * y); - if (count > 0) { - newData[offset] = (byte) ((255 * bytes) / count); - } else { - newData[offset] = (byte) 255; - } - } - } - - data = newData; - - h = newH; - w = newW; - d = 8; - - // imageMask=false; - - } else if (d == 8) { - - int x = 0, y = 0, xx = 0, yy = 0, jj = 0, origLineLength = 0; - try { - - // black and white - if (w * h == data.length) - comp = 1; - - byte[] newData = new byte[newW * newH * comp]; - - // System.err.println(w+" "+h+" "+data.length+" - // comp="+comp+" scaling="+sampling+" "+decodeColorData); - - origLineLength = w * comp; - - // System.err.println("size="+w*h*comp+" filter"+filter+" - // scaling="+sampling+" comp="+comp); - // System.err.println("w="+w+" h="+h+" data="+data.length+" - // origLineLength="+origLineLength+" sampling="+sampling); - // scan all pixels and down-sample - for (y = 0; y < newH; y++) { - for (x = 0; x < newW; x++) { - - // allow for edges in number of pixels left - int wCount = sampling, hCount = sampling; - int wGapLeft = w - x; - int hGapLeft = h - y; - if (wCount > wGapLeft) - wCount = wGapLeft; - if (hCount > hGapLeft) - hCount = hGapLeft; - - for (jj = 0; jj < comp; jj++) { - int byteTotal = 0, count = 0; - // count pixels in sample we will make into a - // pixel (ie 2x2 is 4 pixels , 4x4 is 16 pixels) - for (yy = 0; yy < hCount; yy++) { - for (xx = 0; xx < wCount; xx++) { - - byteTotal = byteTotal + (data[((yy + (y * sampling)) * origLineLength) + (((x * sampling * comp) + (xx * comp) + jj))] & 255); - - count++; - } - } - - // set value as white or average of pixels - if (count > 0) - // if(index==null) - newData[jj + (x * comp) + (newW * y * comp)] = (byte) ((byteTotal) / count); - // else - // newData[x+(newW*y)]=(byte)(((index[1] & - // 255)*byteTotal)/count); -// else { - // if(index==null) - // newData[jj+x+(newW*y*comp)]=(byte) 255; - // else - // newData[x+(newW*y)]=index[0]; -// } - } - } - } - - data = newData; - h = newH; - w = newW; - - } catch (Exception e) { - - if (logger.isLoggable(Level.FINE)) { - // - logger.fine("xx=" + xx + " yy=" + yy + " jj=" + jj + " ptr=" + ((yy + (y * sampling)) * origLineLength) + (((x * sampling) + (xx * comp) + jj)) + '/' + data.length); - - // System.err.println("index="+index); - logger.fine(((yy + (y * sampling)) * origLineLength) + " " + (((x * sampling) + (xx * comp) + jj))); - logger.fine("w=" + w + " h=" + h + " sampling=" + sampling + " x=" + x + " y=" + y); - // System.out.println("xx="+xx+" yy="+yy); - logger.log(Level.FINE, "Error scaling image", e); - // - } - } - } - } - - if (sampling > 1) { - final int[] bands = {0}; - - // System.out.println("w=" + w + " h=" + h + " size=" + - // data.length); - // WritableRaster raster =Raster.createPackedRaster(new - // DataBufferByte(newData, newData.length), newW, newH, 1, null); - Raster raster = Raster.createInterleavedRaster(new DataBufferByte(data, data.length), w, h, w, 1, bands, null); - - BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY); - image.setData(raster); - - return image; - } else { - return null; - } - } - - private void readFile() { - // Do not allow this header to be read more than once. - - if (readFile) - return; - - // Make sure that the application has set the input source. - - if (stream == null) - throw new IllegalStateException("No input stream!"); - - // Read the header. - - decoder = new JBIG2Decoder(); - - try { - byte[] data; - int size = (int) stream.length(); - if (size == -1) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] temp = new byte[8192]; - for (int len; (len = stream.read(temp)) > 0; ) { - bos.write(temp, 0, len); - } - bos.close(); - data = bos.toByteArray(); - } else { - data = new byte[size]; - stream.readFully(data); - } - - decoder.decodeJBIG2(data); - - } catch (IOException e) { - logger.log(Level.FINE, "Error reading JBIG2 image data", e); - } catch (JBIG2Exception e) { - logger.log(Level.FINE, "Error reading JBIG2 image data", e); - } - - readFile = true; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/jai/JBIG2ImageReaderSpi.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/jai/JBIG2ImageReaderSpi.java deleted file mode 100644 index a5c1595096..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/jai/JBIG2ImageReaderSpi.java +++ /dev/null @@ -1,126 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * JBIG2ImageReaderSpi.java - * --------------- - */ -package org.jpedal.jbig2.jai; - -import javax.imageio.ImageReader; -import javax.imageio.spi.ImageReaderSpi; -import javax.imageio.stream.ImageInputStream; -import java.io.IOException; -import java.util.Arrays; - -public class JBIG2ImageReaderSpi extends ImageReaderSpi { - - public JBIG2ImageReaderSpi() { - super("JPedal", // vendorName - "1.0", // version - new String[]{"JBIG2"}, // names - new String[]{"jb2", "jbig2"}, // suffixes - new String[]{"image/x-jbig2"}, // MIMETypes - "org.jpedal.jbig2.jai.JBIG2ImageReader", // readerClassName - new Class[]{ImageInputStream.class}, // inputTypes - null, // writerSpiNames - false, // supportsStandardStreamMetadataFormat - null, // nativeStreamMetadataFormatName - null, // nativeStreamMetadataFormatClassName - null, // extraStreamMetadataFormatNames - null, // extraStreamMetadataFormatClassNames - false, // supportsStandardImageMetadataFormat - null, // nativeImageMetadataFormatName - null, // nativeImageMetadataFormatClassName - null, // extraImageMetadataFormatNames - null); // extraImageMetadataFormatClassNames - - } - - public boolean canDecodeInput(Object input) throws IOException { - - // The input source must be an ImageInputStream because the constructor - // passes STANDARD_INPUT_TYPE (an array consisting of ImageInputStream) - // as the only type of input source that it will deal with to its - // superclass. - - if (!(input instanceof ImageInputStream)) - return false; - - ImageInputStream stream = (ImageInputStream) input; - - /** Read and validate the input source's header. */ - byte[] header = new byte[8]; - try { - // The input source's current position must be preserved so that - // other ImageReaderSpis can determine if they can decode the input - // source's format, should this input source be unable to handle the - // decoding. Because the input source is an ImageInputStream, its - // mark() and reset() methods are called to preserve the current - // position. - - stream.mark(); - stream.read(header); - stream.reset(); - } catch (IOException e) { - return false; - } - - byte[] controlHeader = new byte[]{(byte) 151, 74, 66, 50, 13, 10, 26, 10}; - - return Arrays.equals(controlHeader, header); - } - - public ImageReader createReaderInstance(Object extension) throws IOException { - // Inform the JBIG2 image reader that this JBIG2 image reader SPI is the - // originating provider -- the object that creates the JBIG2 image - // reader. - return new JBIG2ImageReader(this); - } - - public String getDescription(java.util.Locale locale) { - return "JPedal JBIG2 Image Decoder provided by IDRsolutions. See http://www.jpedal.org/jbig.php"; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/Flags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/Flags.java deleted file mode 100644 index 80f6d43379..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/Flags.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * Flags.java - * --------------- - */ -package org.jpedal.jbig2.segment; - -import java.util.LinkedHashMap; -import java.util.Map; - -public abstract class Flags { - - protected int flagsAsInt; - - protected Map flags = new LinkedHashMap(); - - public int getFlagValue(String key) { - return flags.get(key); - } - - public abstract void setFlags(int flagsAsInt); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/Segment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/Segment.java deleted file mode 100644 index fc3afe3862..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/Segment.java +++ /dev/null @@ -1,131 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* Segment.java -* --------------- - */ -package org.jpedal.jbig2.segment; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.ArithmeticDecoder; -import org.jpedal.jbig2.decoders.HuffmanDecoder; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.decoders.MMRDecoder; - -import java.io.IOException; - -public abstract class Segment { - - public static final int SYMBOL_DICTIONARY = 0; - public static final int INTERMEDIATE_TEXT_REGION = 4; - public static final int IMMEDIATE_TEXT_REGION = 6; - public static final int IMMEDIATE_LOSSLESS_TEXT_REGION = 7; - public static final int PATTERN_DICTIONARY = 16; - public static final int INTERMEDIATE_HALFTONE_REGION = 20; - public static final int IMMEDIATE_HALFTONE_REGION = 22; - public static final int IMMEDIATE_LOSSLESS_HALFTONE_REGION = 23; - public static final int INTERMEDIATE_GENERIC_REGION = 36; - public static final int IMMEDIATE_GENERIC_REGION = 38; - public static final int IMMEDIATE_LOSSLESS_GENERIC_REGION = 39; - public static final int INTERMEDIATE_GENERIC_REFINEMENT_REGION = 40; - public static final int IMMEDIATE_GENERIC_REFINEMENT_REGION = 42; - public static final int IMMEDIATE_LOSSLESS_GENERIC_REFINEMENT_REGION = 43; - public static final int PAGE_INFORMATION = 48; - public static final int END_OF_PAGE = 49; - public static final int END_OF_STRIPE = 50; - public static final int END_OF_FILE = 51; - public static final int PROFILES = 52; - public static final int TABLES = 53; - public static final int EXTENSION = 62; - public static final int BITMAP = 70; - - protected SegmentHeader segmentHeader; - - protected HuffmanDecoder huffmanDecoder; - - protected ArithmeticDecoder arithmeticDecoder; - - protected MMRDecoder mmrDecoder; - - protected JBIG2StreamDecoder decoder; - - public Segment(JBIG2StreamDecoder streamDecoder) { - this.decoder = streamDecoder; - -// try { - //huffDecoder = HuffmanDecoder.getInstance(); -// arithmeticDecoder = ArithmeticDecoder.getInstance(); - - huffmanDecoder = decoder.getHuffmanDecoder(); - arithmeticDecoder = decoder.getArithmeticDecoder(); - mmrDecoder = decoder.getMMRDecoder(); - -// } catch (JBIG2Exception e) { -// e.printStackTrace(); -// } - } - - protected short readATValue() throws IOException { - short atValue; - short c0 = atValue = decoder.readByte(); - - if ((c0 & 0x80) != 0) { - atValue |= -1 - 0xff; - } - - return atValue; - } - - public SegmentHeader getSegmentHeader() { - return segmentHeader; - } - - public void setSegmentHeader(SegmentHeader segmentHeader) { - this.segmentHeader = segmentHeader; - } - - public abstract void readSegment() throws IOException, JBIG2Exception; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/SegmentHeader.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/SegmentHeader.java deleted file mode 100644 index 4ae6f8e82e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/SegmentHeader.java +++ /dev/null @@ -1,144 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett - * -* This file is part of JPedal - * -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* SegmentHeader.java -* --------------- - */ -package org.jpedal.jbig2.segment; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; - -public class SegmentHeader { - - private int segmentNumber; - - private int segmentType; - private boolean pageAssociationSizeSet; - private boolean deferredNonRetainSet; - - private int referredToSegmentCount; - private short[] rententionFlags; - - private int[] referredToSegments; - private int pageAssociation; - private int dataLength; - - public void setSegmentNumber(int SegmentNumber) { - this.segmentNumber = SegmentNumber; - } - - public void setSegmentHeaderFlags(short SegmentHeaderFlags) { - segmentType = SegmentHeaderFlags & 63; // 63 = 00111111 - pageAssociationSizeSet = (SegmentHeaderFlags & 64) == 64; // 64 = // 01000000 - deferredNonRetainSet = (SegmentHeaderFlags & 80) == 80; // 64 = 10000000 - - if (JBIG2StreamDecoder.debug) { - System.out.println("SegmentType = " + segmentType); - System.out.println("pageAssociationSizeSet = " + pageAssociationSizeSet); - System.out.println("deferredNonRetainSet = " + deferredNonRetainSet); - } - } - - public void setReferredToSegmentCount(int referredToSegmentCount) { - this.referredToSegmentCount = referredToSegmentCount; - } - - public void setRententionFlags(short[] rententionFlags) { - this.rententionFlags = rententionFlags; - } - - public void setReferredToSegments(int[] referredToSegments) { - this.referredToSegments = referredToSegments; - } - - public int[] getReferredToSegments() { - return referredToSegments; - } - - public int getSegmentType() { - return segmentType; - } - - public int getSegmentNumber() { - return segmentNumber; - } - - public boolean isPageAssociationSizeSet() { - return pageAssociationSizeSet; - } - - public boolean isDeferredNonRetainSet() { - return deferredNonRetainSet; - } - - public int getReferredToSegmentCount() { - return referredToSegmentCount; - } - - public short[] getRententionFlags() { - return rententionFlags; - } - - public int getPageAssociation() { - return pageAssociation; - } - - public void setPageAssociation(int pageAssociation) { - this.pageAssociation = pageAssociation; - } - - public void setDataLength(int dataLength) { - this.dataLength = dataLength; - } - - public void setSegmentType(int type) { - this.segmentType = type; - } - - public int getSegmentDataLength() { - return dataLength; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/extensions/ExtensionSegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/extensions/ExtensionSegment.java deleted file mode 100644 index 3b6fd1aefe..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/extensions/ExtensionSegment.java +++ /dev/null @@ -1,69 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* ExtensionSegment.java -* --------------- - */ -package org.jpedal.jbig2.segment.extensions; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Segment; - -import java.io.IOException; - -public class ExtensionSegment extends Segment { - - public ExtensionSegment(JBIG2StreamDecoder streamDecoder) { - super(streamDecoder); - } - - public void readSegment() throws IOException, JBIG2Exception { - for (int i = 0; i < getSegmentHeader().getSegmentDataLength(); i++) { - decoder.readByte(); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pageinformation/PageInformationFlags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pageinformation/PageInformationFlags.java deleted file mode 100644 index be3f9f77f3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pageinformation/PageInformationFlags.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * PageInformationFlags.java - * --------------- - */ -package org.jpedal.jbig2.segment.pageinformation; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Flags; - -public class PageInformationFlags extends Flags { - - public static String DEFAULT_PIXEL_VALUE = "DEFAULT_PIXEL_VALUE"; - public static String DEFAULT_COMBINATION_OPERATOR = "DEFAULT_COMBINATION_OPERATOR"; - - public void setFlags(int flagsAsInt) { - this.flagsAsInt = flagsAsInt; - - /** extract DEFAULT_PIXEL_VALUE */ - flags.put(DEFAULT_PIXEL_VALUE, (flagsAsInt >> 2) & 1); - - /** extract DEFAULT_COMBINATION_OPERATOR */ - flags.put(DEFAULT_COMBINATION_OPERATOR, (flagsAsInt >> 3) & 3); - - if (JBIG2StreamDecoder.debug) - System.out.println(flags); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pageinformation/PageInformationSegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pageinformation/PageInformationSegment.java deleted file mode 100644 index 86b49798bb..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pageinformation/PageInformationSegment.java +++ /dev/null @@ -1,141 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* PageInformationSegment.java -* --------------- - */ -package org.jpedal.jbig2.segment.pageinformation; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.image.JBIG2Bitmap; -import org.jpedal.jbig2.segment.Segment; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.io.IOException; - -public class PageInformationSegment extends Segment { - - private int pageBitmapHeight, pageBitmapWidth; - private int yResolution, xResolution; - - PageInformationFlags pageInformationFlags = new PageInformationFlags(); - private int pageStriping; - - private JBIG2Bitmap pageBitmap; - - public PageInformationSegment(JBIG2StreamDecoder streamDecoder) { - super(streamDecoder); - } - - public PageInformationFlags getPageInformationFlags() { - return pageInformationFlags; - } - - public JBIG2Bitmap getPageBitmap() { - return pageBitmap; - } - - public void readSegment() throws IOException, JBIG2Exception { - - if (JBIG2StreamDecoder.debug) - System.out.println("==== Reading Page Information Dictionary ===="); - - short[] buff = new short[4]; - decoder.readByte(buff); - pageBitmapWidth = BinaryOperation.getInt32(buff); - - buff = new short[4]; - decoder.readByte(buff); - pageBitmapHeight = BinaryOperation.getInt32(buff); - - if (JBIG2StreamDecoder.debug) - System.out.println("Bitmap size = " + pageBitmapWidth + 'x' + pageBitmapHeight); - - buff = new short[4]; - decoder.readByte(buff); - xResolution = BinaryOperation.getInt32(buff); - - buff = new short[4]; - decoder.readByte(buff); - yResolution = BinaryOperation.getInt32(buff); - - if (JBIG2StreamDecoder.debug) - System.out.println("Resolution = " + xResolution + 'x' + yResolution); - - /** extract page information flags */ - short pageInformationFlagsField = decoder.readByte(); - - pageInformationFlags.setFlags(pageInformationFlagsField); - - if (JBIG2StreamDecoder.debug) - System.out.println("symbolDictionaryFlags = " + pageInformationFlagsField); - - buff = new short[2]; - decoder.readByte(buff); - pageStriping = BinaryOperation.getInt16(buff); - - if (JBIG2StreamDecoder.debug) - System.out.println("Page Striping = " + pageStriping); - - int defPix = pageInformationFlags.getFlagValue(PageInformationFlags.DEFAULT_PIXEL_VALUE); - - int height; - - if (pageBitmapHeight == -1) { - height = pageStriping & 0x7fff; - } else { - height = pageBitmapHeight; - } - - pageBitmap = new JBIG2Bitmap(pageBitmapWidth, height, arithmeticDecoder, huffmanDecoder, mmrDecoder); - pageBitmap.clear(defPix); - } - - public int getPageBitmapHeight() { - return pageBitmapHeight; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pattern/PatternDictionaryFlags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pattern/PatternDictionaryFlags.java deleted file mode 100644 index 8a945313e7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pattern/PatternDictionaryFlags.java +++ /dev/null @@ -1,72 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* PatternDictionaryFlags.java -* --------------- - */ -package org.jpedal.jbig2.segment.pattern; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Flags; - -public class PatternDictionaryFlags extends Flags { - - public static String HD_MMR = "HD_MMR"; - public static String HD_TEMPLATE = "HD_TEMPLATE"; - - public void setFlags(int flagsAsInt) { - this.flagsAsInt = flagsAsInt; - - /** extract HD_MMR */ - flags.put(HD_MMR, new Integer(flagsAsInt & 1)); - - /** extract HD_TEMPLATE */ - flags.put(HD_TEMPLATE, new Integer((flagsAsInt >> 1) & 3)); - - if (JBIG2StreamDecoder.debug) - System.out.println(flags); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pattern/PatternDictionarySegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pattern/PatternDictionarySegment.java deleted file mode 100644 index 22eee9fdef..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/pattern/PatternDictionarySegment.java +++ /dev/null @@ -1,147 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* PatternDictionarySegment.java -* --------------- - */ -package org.jpedal.jbig2.segment.pattern; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.image.JBIG2Bitmap; -import org.jpedal.jbig2.segment.Segment; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.io.IOException; - -public class PatternDictionarySegment extends Segment { - - PatternDictionaryFlags patternDictionaryFlags = new PatternDictionaryFlags(); - private int width; - private int height; - private int grayMax; - private JBIG2Bitmap[] bitmaps; - private int size; - - public PatternDictionarySegment(JBIG2StreamDecoder streamDecoder) { - super(streamDecoder); - } - - public void readSegment() throws IOException, JBIG2Exception { - /** read text region Segment flags */ - readPatternDictionaryFlags(); - - width = decoder.readByte(); - height = decoder.readByte(); - - if (JBIG2StreamDecoder.debug) - System.out.println("pattern dictionary size = " + width + " , " + height); - - short[] buf = new short[4]; - decoder.readByte(buf); - grayMax = BinaryOperation.getInt32(buf); - - if (JBIG2StreamDecoder.debug) - System.out.println("grey max = " + grayMax); - - boolean useMMR = patternDictionaryFlags.getFlagValue(PatternDictionaryFlags.HD_MMR) == 1; - int template = patternDictionaryFlags.getFlagValue(PatternDictionaryFlags.HD_TEMPLATE); - - if (!useMMR) { - arithmeticDecoder.resetGenericStats(template, null); - arithmeticDecoder.start(); - } - - short[] genericBAdaptiveTemplateX = new short[4], genericBAdaptiveTemplateY = new short[4]; - - genericBAdaptiveTemplateX[0] = (short) -width; - genericBAdaptiveTemplateY[0] = 0; - genericBAdaptiveTemplateX[1] = -3; - genericBAdaptiveTemplateY[1] = -1; - genericBAdaptiveTemplateX[2] = 2; - genericBAdaptiveTemplateY[2] = -2; - genericBAdaptiveTemplateX[3] = -2; - genericBAdaptiveTemplateY[3] = -2; - - size = grayMax + 1; - - JBIG2Bitmap bitmap = new JBIG2Bitmap(size * width, height, arithmeticDecoder, huffmanDecoder, mmrDecoder); - bitmap.clear(0); - bitmap.readBitmap(useMMR, template, false, false, null, genericBAdaptiveTemplateX, genericBAdaptiveTemplateY, segmentHeader.getSegmentDataLength() - 7); - - JBIG2Bitmap bitmaps[] = new JBIG2Bitmap[size]; - - int x = 0; - for (int i = 0; i < size; i++) { - bitmaps[i] = bitmap.getSlice(x, 0, width, height); - x += width; - } - - this.bitmaps = bitmaps; - } - - - public JBIG2Bitmap[] getBitmaps() { - return bitmaps; - } - - private void readPatternDictionaryFlags() throws IOException { - short patternDictionaryFlagsField = decoder.readByte(); - - patternDictionaryFlags.setFlags(patternDictionaryFlagsField); - - if (JBIG2StreamDecoder.debug) - System.out.println("pattern Dictionary flags = " + patternDictionaryFlagsField); - } - - public PatternDictionaryFlags getPatternDictionaryFlags() { - return patternDictionaryFlags; - } - - public int getSize() { - return size; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/RegionFlags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/RegionFlags.java deleted file mode 100644 index 2ed41fb7e0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/RegionFlags.java +++ /dev/null @@ -1,68 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* RegionFlags.java -* --------------- - */ -package org.jpedal.jbig2.segment.region; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Flags; - -public class RegionFlags extends Flags { - - public static String EXTERNAL_COMBINATION_OPERATOR = "EXTERNAL_COMBINATION_OPERATOR"; - - public void setFlags(int flagsAsInt) { - this.flagsAsInt = flagsAsInt; - - /** extract EXTERNAL_COMBINATION_OPERATOR */ - flags.put(EXTERNAL_COMBINATION_OPERATOR, new Integer(flagsAsInt & 7)); - - if (JBIG2StreamDecoder.debug) - System.out.println(flags); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/RegionSegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/RegionSegment.java deleted file mode 100644 index c81161546c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/RegionSegment.java +++ /dev/null @@ -1,100 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* RegionSegment.java -* --------------- - */ -package org.jpedal.jbig2.segment.region; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Segment; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.io.IOException; - -public abstract class RegionSegment extends Segment { - protected int regionBitmapWidth, regionBitmapHeight; - protected int regionBitmapXLocation, regionBitmapYLocation; - - protected RegionFlags regionFlags = new RegionFlags(); - - public RegionSegment(JBIG2StreamDecoder streamDecoder) { - super(streamDecoder); - } - - public void readSegment() throws IOException, JBIG2Exception { - short[] buff = new short[4]; - decoder.readByte(buff); - regionBitmapWidth = BinaryOperation.getInt32(buff); - - buff = new short[4]; - decoder.readByte(buff); - regionBitmapHeight = BinaryOperation.getInt32(buff); - - if (JBIG2StreamDecoder.debug) - System.out.println("Bitmap size = " + regionBitmapWidth + 'x' + regionBitmapHeight); - - buff = new short[4]; - decoder.readByte(buff); - regionBitmapXLocation = BinaryOperation.getInt32(buff); - - buff = new short[4]; - decoder.readByte(buff); - regionBitmapYLocation = BinaryOperation.getInt32(buff); - - if (JBIG2StreamDecoder.debug) - System.out.println("Bitmap location = " + regionBitmapXLocation + ',' + regionBitmapYLocation); - - /** extract region Segment flags */ - short regionFlagsField = decoder.readByte(); - - regionFlags.setFlags(regionFlagsField); - - if (JBIG2StreamDecoder.debug) - System.out.println("region Segment flags = " + regionFlagsField); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/generic/GenericRegionFlags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/generic/GenericRegionFlags.java deleted file mode 100644 index df6618db1d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/generic/GenericRegionFlags.java +++ /dev/null @@ -1,77 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* GenericRegionFlags.java -* --------------- - */ -package org.jpedal.jbig2.segment.region.generic; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Flags; - -public class GenericRegionFlags extends Flags { - - public static String MMR = "MMR"; - public static String GB_TEMPLATE = "GB_TEMPLATE"; - public static String TPGDON = "TPGDON"; - - public void setFlags(int flagsAsInt) { - this.flagsAsInt = flagsAsInt; - - /** extract MMR */ - flags.put(MMR, new Integer(flagsAsInt & 1)); - - /** extract GB_TEMPLATE */ - flags.put(GB_TEMPLATE, new Integer((flagsAsInt >> 1) & 3)); - - /** extract TPGDON */ - flags.put(TPGDON, new Integer((flagsAsInt >> 3) & 1)); - - - if (JBIG2StreamDecoder.debug) - System.out.println(flags); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/generic/GenericRegionSegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/generic/GenericRegionSegment.java deleted file mode 100644 index 509b267a48..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/generic/GenericRegionSegment.java +++ /dev/null @@ -1,197 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* GenericRegionSegment.java -* --------------- - */ -package org.jpedal.jbig2.segment.region.generic; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.image.JBIG2Bitmap; -import org.jpedal.jbig2.segment.pageinformation.PageInformationFlags; -import org.jpedal.jbig2.segment.pageinformation.PageInformationSegment; -import org.jpedal.jbig2.segment.region.RegionFlags; -import org.jpedal.jbig2.segment.region.RegionSegment; - -import java.io.IOException; - -public class GenericRegionSegment extends RegionSegment { - private GenericRegionFlags genericRegionFlags = new GenericRegionFlags(); - - private boolean inlineImage; - - private boolean unknownLength = false; - - public GenericRegionSegment(JBIG2StreamDecoder streamDecoder, boolean inlineImage) { - super(streamDecoder); - - this.inlineImage = inlineImage; - } - - public void readSegment() throws IOException, JBIG2Exception { - - if (JBIG2StreamDecoder.debug) - System.out.println("==== Reading Immediate Generic Region ===="); - - super.readSegment(); - - /** read text region Segment flags */ - readGenericRegionFlags(); - - boolean useMMR = genericRegionFlags.getFlagValue(GenericRegionFlags.MMR) != 0; - int template = genericRegionFlags.getFlagValue(GenericRegionFlags.GB_TEMPLATE); - - short[] genericBAdaptiveTemplateX = new short[4]; - short[] genericBAdaptiveTemplateY = new short[4]; - - if (!useMMR) { - if (template == 0) { - genericBAdaptiveTemplateX[0] = readATValue(); - genericBAdaptiveTemplateY[0] = readATValue(); - genericBAdaptiveTemplateX[1] = readATValue(); - genericBAdaptiveTemplateY[1] = readATValue(); - genericBAdaptiveTemplateX[2] = readATValue(); - genericBAdaptiveTemplateY[2] = readATValue(); - genericBAdaptiveTemplateX[3] = readATValue(); - genericBAdaptiveTemplateY[3] = readATValue(); - } else { - genericBAdaptiveTemplateX[0] = readATValue(); - genericBAdaptiveTemplateY[0] = readATValue(); - } - - arithmeticDecoder.resetGenericStats(template, null); - arithmeticDecoder.start(); - } - - boolean typicalPredictionGenericDecodingOn = genericRegionFlags.getFlagValue(GenericRegionFlags.TPGDON) != 0; - int length = segmentHeader.getSegmentDataLength(); - - if (length == -1) { - /** - * length of data is unknown, so it needs to be determined through examination of the data. - * See 7.2.7 - Segment data length of the JBIG2 specification. - */ - - unknownLength = true; - - short match1; - short match2; - - if (useMMR) { - // look for 0x00 0x00 (0, 0) - - match1 = 0; - match2 = 0; - } else { - // look for 0xFF 0xAC (255, 172) - - match1 = 255; - match2 = 172; - } - - int bytesRead = 0; - while (true) { - short bite1 = decoder.readByte(); - bytesRead++; - - if (bite1 == match1) { - short bite2 = decoder.readByte(); - bytesRead++; - - if (bite2 == match2) { - length = bytesRead - 2; - break; - } - } - } - - decoder.movePointer(-bytesRead); - } - - JBIG2Bitmap bitmap = new JBIG2Bitmap(regionBitmapWidth, regionBitmapHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - bitmap.clear(0); - bitmap.readBitmap(useMMR, template, typicalPredictionGenericDecodingOn, false, null, genericBAdaptiveTemplateX, genericBAdaptiveTemplateY, useMMR ? 0 : length - 18); - - - if (inlineImage) { - PageInformationSegment pageSegment = decoder.findPageSegement(segmentHeader.getPageAssociation()); - JBIG2Bitmap pageBitmap = pageSegment.getPageBitmap(); - - int extCombOp = regionFlags.getFlagValue(RegionFlags.EXTERNAL_COMBINATION_OPERATOR); - - if (pageSegment.getPageBitmapHeight() == -1 && regionBitmapYLocation + regionBitmapHeight > pageBitmap.getHeight()) { - pageBitmap.expand(regionBitmapYLocation + regionBitmapHeight, - pageSegment.getPageInformationFlags().getFlagValue(PageInformationFlags.DEFAULT_PIXEL_VALUE)); - } - - pageBitmap.combine(bitmap, regionBitmapXLocation, regionBitmapYLocation, extCombOp); - } else { - bitmap.setBitmapNumber(getSegmentHeader().getSegmentNumber()); - decoder.appendBitmap(bitmap); - } - - - if (unknownLength) { - decoder.movePointer(4); - } - - } - - private void readGenericRegionFlags() throws IOException { - /** extract text region Segment flags */ - short genericRegionFlagsField = decoder.readByte(); - - genericRegionFlags.setFlags(genericRegionFlagsField); - - if (JBIG2StreamDecoder.debug) - System.out.println("generic region Segment flags = " + genericRegionFlagsField); - } - - public GenericRegionFlags getGenericRegionFlags() { - return genericRegionFlags; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/halftone/HalftoneRegionFlags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/halftone/HalftoneRegionFlags.java deleted file mode 100644 index f2a898b8be..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/halftone/HalftoneRegionFlags.java +++ /dev/null @@ -1,85 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* HalftoneRegionFlags.java -* --------------- - */ -package org.jpedal.jbig2.segment.region.halftone; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Flags; - -public class HalftoneRegionFlags extends Flags { - - public static String H_MMR = "H_MMR"; - public static String H_TEMPLATE = "H_TEMPLATE"; - public static String H_ENABLE_SKIP = "H_ENABLE_SKIP"; - public static String H_COMB_OP = "H_COMB_OP"; - public static String H_DEF_PIXEL = "H_DEF_PIXEL"; - - public void setFlags(int flagsAsInt) { - this.flagsAsInt = flagsAsInt; - - /** extract H_MMR */ - flags.put(H_MMR, new Integer(flagsAsInt & 1)); - - /** extract H_TEMPLATE */ - flags.put(H_TEMPLATE, new Integer((flagsAsInt >> 1) & 3)); - - /** extract H_ENABLE_SKIP */ - flags.put(H_ENABLE_SKIP, new Integer((flagsAsInt >> 3) & 1)); - - /** extract H_COMB_OP */ - flags.put(H_COMB_OP, new Integer((flagsAsInt >> 4) & 7)); - - /** extract H_DEF_PIXEL */ - flags.put(H_DEF_PIXEL, new Integer((flagsAsInt >> 7) & 1)); - - - if (JBIG2StreamDecoder.debug) - System.out.println(flags); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/halftone/HalftoneRegionSegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/halftone/HalftoneRegionSegment.java deleted file mode 100644 index 27434c4c14..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/halftone/HalftoneRegionSegment.java +++ /dev/null @@ -1,242 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* HalftoneRegionSegment.java -* --------------- - */ -package org.jpedal.jbig2.segment.region.halftone; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.image.JBIG2Bitmap; -import org.jpedal.jbig2.segment.Segment; -import org.jpedal.jbig2.segment.pageinformation.PageInformationSegment; -import org.jpedal.jbig2.segment.pattern.PatternDictionarySegment; -import org.jpedal.jbig2.segment.region.RegionFlags; -import org.jpedal.jbig2.segment.region.RegionSegment; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.io.IOException; - -public class HalftoneRegionSegment extends RegionSegment { - private HalftoneRegionFlags halftoneRegionFlags = new HalftoneRegionFlags(); - - private boolean inlineImage; - - public HalftoneRegionSegment(JBIG2StreamDecoder streamDecoder, boolean inlineImage) { - super(streamDecoder); - - this.inlineImage = inlineImage; - } - - public void readSegment() throws IOException, JBIG2Exception { - super.readSegment(); - - /** read text region Segment flags */ - readHalftoneRegionFlags(); - - short[] buf = new short[4]; - decoder.readByte(buf); - int gridWidth = BinaryOperation.getInt32(buf); - - buf = new short[4]; - decoder.readByte(buf); - int gridHeight = BinaryOperation.getInt32(buf); - - buf = new short[4]; - decoder.readByte(buf); - int gridX = BinaryOperation.getInt32(buf); - - buf = new short[4]; - decoder.readByte(buf); - int gridY = BinaryOperation.getInt32(buf); - - if (JBIG2StreamDecoder.debug) - System.out.println("grid pos and size = " + gridX + ',' + gridY + ' ' + gridWidth + ',' + gridHeight); - - buf = new short[2]; - decoder.readByte(buf); - int stepX = BinaryOperation.getInt16(buf); - - buf = new short[2]; - decoder.readByte(buf); - int stepY = BinaryOperation.getInt16(buf); - - if (JBIG2StreamDecoder.debug) - System.out.println("step size = " + stepX + ',' + stepY); - - int[] referedToSegments = segmentHeader.getReferredToSegments(); - if (referedToSegments.length != 1) { - System.out.println("Error in halftone Segment. refSegs should == 1"); - } - - Segment segment = decoder.findSegment(referedToSegments[0]); - if (segment.getSegmentHeader().getSegmentType() != Segment.PATTERN_DICTIONARY) { - if (JBIG2StreamDecoder.debug) - System.out.println("Error in halftone Segment. bad symbol dictionary reference"); - } - - PatternDictionarySegment patternDictionarySegment = (PatternDictionarySegment) segment; - - int bitsPerValue = 0, i = 1; - while (i < patternDictionarySegment.getSize()) { - bitsPerValue++; - i <<= 1; - } - - JBIG2Bitmap bitmap = patternDictionarySegment.getBitmaps()[0]; - int patternWidth = bitmap.getWidth(); - int patternHeight = bitmap.getHeight(); - - if (JBIG2StreamDecoder.debug) - System.out.println("pattern size = " + patternWidth + ',' + patternHeight); - - boolean useMMR = halftoneRegionFlags.getFlagValue(HalftoneRegionFlags.H_MMR) != 0; - int template = halftoneRegionFlags.getFlagValue(HalftoneRegionFlags.H_TEMPLATE); - - if (!useMMR) { - arithmeticDecoder.resetGenericStats(template, null); - arithmeticDecoder.start(); - } - - int halftoneDefaultPixel = halftoneRegionFlags.getFlagValue(HalftoneRegionFlags.H_DEF_PIXEL); - bitmap = new JBIG2Bitmap(regionBitmapWidth, regionBitmapHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - bitmap.clear(halftoneDefaultPixel); - - boolean enableSkip = halftoneRegionFlags.getFlagValue(HalftoneRegionFlags.H_ENABLE_SKIP) != 0; - - JBIG2Bitmap skipBitmap = null; - if (enableSkip) { - skipBitmap = new JBIG2Bitmap(gridWidth, gridHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - skipBitmap.clear(0); - for (int y = 0; y < gridHeight; y++) { - for (int x = 0; x < gridWidth; x++) { - int xx = gridX + y * stepY + x * stepX; - int yy = gridY + y * stepX - x * stepY; - - if (((xx + patternWidth) >> 8) <= 0 || (xx >> 8) >= regionBitmapWidth || ((yy + patternHeight) >> 8) <= 0 || (yy >> 8) >= regionBitmapHeight) { - skipBitmap.setPixel(y, x, 1); - } - } - } - } - - int[] grayScaleImage = new int[gridWidth * gridHeight]; - - short[] genericBAdaptiveTemplateX = new short[4], genericBAdaptiveTemplateY = new short[4]; - - genericBAdaptiveTemplateX[0] = (short) (template <= 1 ? 3 : 2); - genericBAdaptiveTemplateY[0] = -1; - genericBAdaptiveTemplateX[1] = -3; - genericBAdaptiveTemplateY[1] = -1; - genericBAdaptiveTemplateX[2] = 2; - genericBAdaptiveTemplateY[2] = -2; - genericBAdaptiveTemplateX[3] = -2; - genericBAdaptiveTemplateY[3] = -2; - - JBIG2Bitmap grayBitmap; - - for (int j = bitsPerValue - 1; j >= 0; --j) { - grayBitmap = new JBIG2Bitmap(gridWidth, gridHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - - grayBitmap.readBitmap(useMMR, template, false, enableSkip, skipBitmap, genericBAdaptiveTemplateX, genericBAdaptiveTemplateY, -1); - - i = 0; - for (int row = 0; row < gridHeight; row++) { - for (int col = 0; col < gridWidth; col++) { - int bit = grayBitmap.getPixel(col, row) ^ (grayScaleImage[i] & 1); - grayScaleImage[i] = (grayScaleImage[i] << 1) | bit; - i++; - } - } - } - - int combinationOperator = halftoneRegionFlags.getFlagValue(HalftoneRegionFlags.H_COMB_OP); - - i = 0; - for (int col = 0; col < gridHeight; col++) { - int xx = gridX + col * stepY; - int yy = gridY + col * stepX; - for (int row = 0; row < gridWidth; row++) { - if (!(enableSkip && skipBitmap.getPixel(col, row) == 1)) { - JBIG2Bitmap patternBitmap = patternDictionarySegment.getBitmaps()[grayScaleImage[i]]; - bitmap.combine(patternBitmap, xx >> 8, yy >> 8, combinationOperator); - } - - xx += stepX; - yy -= stepY; - - i++; - } - } - - if (inlineImage) { - PageInformationSegment pageSegment = decoder.findPageSegement(segmentHeader.getPageAssociation()); - JBIG2Bitmap pageBitmap = pageSegment.getPageBitmap(); - - int externalCombinationOperator = regionFlags.getFlagValue(RegionFlags.EXTERNAL_COMBINATION_OPERATOR); - pageBitmap.combine(bitmap, regionBitmapXLocation, regionBitmapYLocation, externalCombinationOperator); - } else { - bitmap.setBitmapNumber(getSegmentHeader().getSegmentNumber()); - decoder.appendBitmap(bitmap); - } - - } - - private void readHalftoneRegionFlags() throws IOException { - /** extract text region Segment flags */ - short halftoneRegionFlagsField = decoder.readByte(); - - halftoneRegionFlags.setFlags(halftoneRegionFlagsField); - - if (JBIG2StreamDecoder.debug) - System.out.println("generic region Segment flags = " + halftoneRegionFlagsField); - } - - public HalftoneRegionFlags getHalftoneRegionFlags() { - return halftoneRegionFlags; - } -} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/refinement/RefinementRegionFlags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/refinement/RefinementRegionFlags.java deleted file mode 100644 index 14a16a7562..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/refinement/RefinementRegionFlags.java +++ /dev/null @@ -1,72 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* RefinementRegionFlags.java -* --------------- - */ -package org.jpedal.jbig2.segment.region.refinement; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Flags; - -public class RefinementRegionFlags extends Flags { - - public static String GR_TEMPLATE = "GR_TEMPLATE"; - public static String TPGDON = "TPGDON"; - - public void setFlags(int flagsAsInt) { - this.flagsAsInt = flagsAsInt; - - /** extract GR_TEMPLATE */ - flags.put(GR_TEMPLATE, new Integer(flagsAsInt & 1)); - - /** extract TPGDON */ - flags.put(TPGDON, new Integer((flagsAsInt >> 1) & 1)); - - if (JBIG2StreamDecoder.debug) - System.out.println(flags); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/refinement/RefinementRegionSegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/refinement/RefinementRegionSegment.java deleted file mode 100644 index 656d7fbde7..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/refinement/RefinementRegionSegment.java +++ /dev/null @@ -1,160 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* RefinementRegionSegment.java -* --------------- - */ -package org.jpedal.jbig2.segment.region.refinement; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.image.JBIG2Bitmap; -import org.jpedal.jbig2.segment.pageinformation.PageInformationFlags; -import org.jpedal.jbig2.segment.pageinformation.PageInformationSegment; -import org.jpedal.jbig2.segment.region.RegionFlags; -import org.jpedal.jbig2.segment.region.RegionSegment; - -import java.io.IOException; - -public class RefinementRegionSegment extends RegionSegment { - private RefinementRegionFlags refinementRegionFlags = new RefinementRegionFlags(); - - private boolean inlineImage; - - private int noOfReferedToSegments; - - int[] referedToSegments; - - public RefinementRegionSegment(JBIG2StreamDecoder streamDecoder, boolean inlineImage, int[] referedToSegments, int noOfReferedToSegments) { - super(streamDecoder); - - this.inlineImage = inlineImage; - this.referedToSegments = referedToSegments; - this.noOfReferedToSegments = noOfReferedToSegments; - } - - public void readSegment() throws IOException, JBIG2Exception { - if (JBIG2StreamDecoder.debug) - System.out.println("==== Reading Generic Refinement Region ===="); - - super.readSegment(); - - /** read text region segment flags */ - readGenericRegionFlags(); - - short[] genericRegionAdaptiveTemplateX = new short[2]; - short[] genericRegionAdaptiveTemplateY = new short[2]; - - int template = refinementRegionFlags.getFlagValue(RefinementRegionFlags.GR_TEMPLATE); - if (template == 0) { - genericRegionAdaptiveTemplateX[0] = readATValue(); - genericRegionAdaptiveTemplateY[0] = readATValue(); - genericRegionAdaptiveTemplateX[1] = readATValue(); - genericRegionAdaptiveTemplateY[1] = readATValue(); - } - - if (noOfReferedToSegments == 0 || inlineImage) { - PageInformationSegment pageSegment = decoder.findPageSegement(segmentHeader.getPageAssociation()); - JBIG2Bitmap pageBitmap = pageSegment.getPageBitmap(); - - if (pageSegment.getPageBitmapHeight() == -1 && regionBitmapYLocation + regionBitmapHeight > pageBitmap.getHeight()) { - pageBitmap.expand(regionBitmapYLocation + regionBitmapHeight, pageSegment.getPageInformationFlags().getFlagValue(PageInformationFlags.DEFAULT_PIXEL_VALUE)); - } - } - - if (noOfReferedToSegments > 1) { - if (JBIG2StreamDecoder.debug) - System.out.println("Bad reference in JBIG2 generic refinement Segment"); - - return; - } - - JBIG2Bitmap referedToBitmap; - if (noOfReferedToSegments == 1) { - referedToBitmap = decoder.findBitmap(referedToSegments[0]); - } else { - PageInformationSegment pageSegment = decoder.findPageSegement(segmentHeader.getPageAssociation()); - JBIG2Bitmap pageBitmap = pageSegment.getPageBitmap(); - - referedToBitmap = pageBitmap.getSlice(regionBitmapXLocation, regionBitmapYLocation, regionBitmapWidth, regionBitmapHeight); - } - - arithmeticDecoder.resetRefinementStats(template, null); - arithmeticDecoder.start(); - - boolean typicalPredictionGenericRefinementOn = refinementRegionFlags.getFlagValue(RefinementRegionFlags.TPGDON) != 0; - - JBIG2Bitmap bitmap = new JBIG2Bitmap(regionBitmapWidth, regionBitmapHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - - bitmap.readGenericRefinementRegion(template, typicalPredictionGenericRefinementOn, referedToBitmap, 0, 0, genericRegionAdaptiveTemplateX, genericRegionAdaptiveTemplateY); - - if (inlineImage) { - PageInformationSegment pageSegment = decoder.findPageSegement(segmentHeader.getPageAssociation()); - JBIG2Bitmap pageBitmap = pageSegment.getPageBitmap(); - - int extCombOp = regionFlags.getFlagValue(RegionFlags.EXTERNAL_COMBINATION_OPERATOR); - - pageBitmap.combine(bitmap, regionBitmapXLocation, regionBitmapYLocation, extCombOp); - } else { - bitmap.setBitmapNumber(getSegmentHeader().getSegmentNumber()); - decoder.appendBitmap(bitmap); - } - } - - private void readGenericRegionFlags() throws IOException { - /** extract text region Segment flags */ - short refinementRegionFlagsField = decoder.readByte(); - - refinementRegionFlags.setFlags(refinementRegionFlagsField); - - if (JBIG2StreamDecoder.debug) - System.out.println("generic region Segment flags = " + refinementRegionFlagsField); - } - - public RefinementRegionFlags getGenericRegionFlags() { - return refinementRegionFlags; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/text/TextRegionFlags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/text/TextRegionFlags.java deleted file mode 100644 index 1e090ff2aa..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/text/TextRegionFlags.java +++ /dev/null @@ -1,103 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* TextRegionFlags.java -* --------------- - */ -package org.jpedal.jbig2.segment.region.text; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Flags; - -public class TextRegionFlags extends Flags { - - public static String SB_HUFF = "SB_HUFF"; - public static String SB_REFINE = "SB_REFINE"; - public static String LOG_SB_STRIPES = "LOG_SB_STRIPES"; - public static String REF_CORNER = "REF_CORNER"; - public static String TRANSPOSED = "TRANSPOSED"; - public static String SB_COMB_OP = "SB_COMB_OP"; - public static String SB_DEF_PIXEL = "SB_DEF_PIXEL"; - public static String SB_DS_OFFSET = "SB_DS_OFFSET"; - public static String SB_R_TEMPLATE = "SB_R_TEMPLATE"; - - public void setFlags(int flagsAsInt) { - this.flagsAsInt = flagsAsInt; - - /** extract SB_HUFF */ - flags.put(SB_HUFF, new Integer(flagsAsInt & 1)); - - /** extract SB_REFINE */ - flags.put(SB_REFINE, new Integer((flagsAsInt >> 1) & 1)); - - /** extract LOG_SB_STRIPES */ - flags.put(LOG_SB_STRIPES, new Integer((flagsAsInt >> 2) & 3)); - - /** extract REF_CORNER */ - flags.put(REF_CORNER, new Integer((flagsAsInt >> 4) & 3)); - - /** extract TRANSPOSED */ - flags.put(TRANSPOSED, new Integer((flagsAsInt >> 6) & 1)); - - /** extract SB_COMB_OP */ - flags.put(SB_COMB_OP, new Integer((flagsAsInt >> 7) & 3)); - - /** extract SB_DEF_PIXEL */ - flags.put(SB_DEF_PIXEL, new Integer((flagsAsInt >> 9) & 1)); - - int sOffset = (flagsAsInt >> 10) & 0x1f; - if ((sOffset & 0x10) != 0) { - sOffset |= -1 - 0x0f; - } - flags.put(SB_DS_OFFSET, new Integer(sOffset)); - - /** extract SB_R_TEMPLATE */ - flags.put(SB_R_TEMPLATE, new Integer((flagsAsInt >> 15) & 1)); - - if (JBIG2StreamDecoder.debug) - System.out.println(flags); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/text/TextRegionHuffmanFlags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/text/TextRegionHuffmanFlags.java deleted file mode 100644 index e75a26a6b5..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/text/TextRegionHuffmanFlags.java +++ /dev/null @@ -1,96 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* TextRegionHuffmanFlags.java -* --------------- - */ -package org.jpedal.jbig2.segment.region.text; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Flags; - -public class TextRegionHuffmanFlags extends Flags { - - public static String SB_HUFF_FS = "SB_HUFF_FS"; - public static String SB_HUFF_DS = "SB_HUFF_DS"; - public static String SB_HUFF_DT = "SB_HUFF_DT"; - public static String SB_HUFF_RDW = "SB_HUFF_RDW"; - public static String SB_HUFF_RDH = "SB_HUFF_RDH"; - public static String SB_HUFF_RDX = "SB_HUFF_RDX"; - public static String SB_HUFF_RDY = "SB_HUFF_RDY"; - public static String SB_HUFF_RSIZE = "SB_HUFF_RSIZE"; - - public void setFlags(int flagsAsInt) { - this.flagsAsInt = flagsAsInt; - - /** extract SB_HUFF_FS */ - flags.put(SB_HUFF_FS, new Integer(flagsAsInt & 3)); - - /** extract SB_HUFF_DS */ - flags.put(SB_HUFF_DS, new Integer((flagsAsInt >> 2) & 3)); - - /** extract SB_HUFF_DT */ - flags.put(SB_HUFF_DT, new Integer((flagsAsInt >> 4) & 3)); - - /** extract SB_HUFF_RDW */ - flags.put(SB_HUFF_RDW, new Integer((flagsAsInt >> 6) & 3)); - - /** extract SB_HUFF_RDH */ - flags.put(SB_HUFF_RDH, new Integer((flagsAsInt >> 8) & 3)); - - /** extract SB_HUFF_RDX */ - flags.put(SB_HUFF_RDX, new Integer((flagsAsInt >> 10) & 3)); - - /** extract SB_HUFF_RDY */ - flags.put(SB_HUFF_RDY, new Integer((flagsAsInt >> 12) & 3)); - - /** extract SB_HUFF_RSIZE */ - flags.put(SB_HUFF_RSIZE, new Integer((flagsAsInt >> 14) & 1)); - - if (JBIG2StreamDecoder.debug) - System.out.println(flags); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/text/TextRegionSegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/text/TextRegionSegment.java deleted file mode 100644 index 08d1e4baea..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/region/text/TextRegionSegment.java +++ /dev/null @@ -1,341 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * TextRegionSegment.java - * --------------- - */ -package org.jpedal.jbig2.segment.region.text; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.HuffmanDecoder; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.image.JBIG2Bitmap; -import org.jpedal.jbig2.segment.Segment; -import org.jpedal.jbig2.segment.pageinformation.PageInformationSegment; -import org.jpedal.jbig2.segment.region.RegionFlags; -import org.jpedal.jbig2.segment.region.RegionSegment; -import org.jpedal.jbig2.segment.symboldictionary.SymbolDictionarySegment; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class TextRegionSegment extends RegionSegment { - private TextRegionFlags textRegionFlags = new TextRegionFlags(); - - private TextRegionHuffmanFlags textRegionHuffmanFlags = new TextRegionHuffmanFlags(); - - private int noOfSymbolInstances; - - private boolean inlineImage; - - private short[] symbolRegionAdaptiveTemplateX = new short[2], symbolRegionAdaptiveTemplateY = new short[2]; - - public TextRegionSegment(JBIG2StreamDecoder streamDecoder, boolean inlineImage) { - super(streamDecoder); - - this.inlineImage = inlineImage; - } - - public void readSegment() throws IOException, JBIG2Exception { - if (JBIG2StreamDecoder.debug) - System.out.println("==== Reading Text Region ===="); - - super.readSegment(); - - /** read text region Segment flags */ - readTextRegionFlags(); - - short[] buff = new short[4]; - decoder.readByte(buff); - noOfSymbolInstances = BinaryOperation.getInt32(buff); - - if (JBIG2StreamDecoder.debug) - System.out.println("noOfSymbolInstances = " + noOfSymbolInstances); - - int noOfReferredToSegments = segmentHeader.getReferredToSegmentCount(); - int[] referredToSegments = segmentHeader.getReferredToSegments(); - - List codeTables = new ArrayList(); - List segmentsReferenced = new ArrayList(); - int noOfSymbols = 0; - - if (JBIG2StreamDecoder.debug) - System.out.println("noOfReferredToSegments = " + noOfReferredToSegments); - - for (int i = 0; i < noOfReferredToSegments; i++) { - Segment seg = decoder.findSegment(referredToSegments[i]); - int type = seg.getSegmentHeader().getSegmentType(); - - if (type == Segment.SYMBOL_DICTIONARY) { - segmentsReferenced.add(seg); - noOfSymbols += ((SymbolDictionarySegment) seg).getNoOfExportedSymbols(); - } else if (type == Segment.TABLES) { - codeTables.add(seg); - } - } - - int symbolCodeLength = 0; - int count = 1; - - while (count < noOfSymbols) { - symbolCodeLength++; - count <<= 1; - } - - int currentSymbol = 0; - JBIG2Bitmap[] symbols = new JBIG2Bitmap[noOfSymbols]; - for (Segment seg : segmentsReferenced) { - if (seg.getSegmentHeader().getSegmentType() == Segment.SYMBOL_DICTIONARY) { - JBIG2Bitmap[] bitmaps = ((SymbolDictionarySegment) seg).getBitmaps(); - for (JBIG2Bitmap bitmap : bitmaps) { - symbols[currentSymbol] = bitmap; - currentSymbol++; - } - } - } - - int[][] huffmanFSTable = null; - int[][] huffmanDSTable = null; - int[][] huffmanDTTable = null; - - int[][] huffmanRDWTable = null; - int[][] huffmanRDHTable = null; - - int[][] huffmanRDXTable = null; - int[][] huffmanRDYTable = null; - int[][] huffmanRSizeTable = null; - - boolean sbHuffman = textRegionFlags.getFlagValue(TextRegionFlags.SB_HUFF) != 0; - - int i; - if (sbHuffman) { - int sbHuffFS = textRegionHuffmanFlags.getFlagValue(TextRegionHuffmanFlags.SB_HUFF_FS); - if (sbHuffFS == 0) { - huffmanFSTable = HuffmanDecoder.huffmanTableF; - } else if (sbHuffFS == 1) { - huffmanFSTable = HuffmanDecoder.huffmanTableG; - } - - int sbHuffDS = textRegionHuffmanFlags.getFlagValue(TextRegionHuffmanFlags.SB_HUFF_DS); - if (sbHuffDS == 0) { - huffmanDSTable = HuffmanDecoder.huffmanTableH; - } else if (sbHuffDS == 1) { - huffmanDSTable = HuffmanDecoder.huffmanTableI; - } else if (sbHuffDS == 2) { - huffmanDSTable = HuffmanDecoder.huffmanTableJ; - } - int sbHuffDT = textRegionHuffmanFlags.getFlagValue(TextRegionHuffmanFlags.SB_HUFF_DT); - if (sbHuffDT == 0) { - huffmanDTTable = HuffmanDecoder.huffmanTableK; - } else if (sbHuffDT == 1) { - huffmanDTTable = HuffmanDecoder.huffmanTableL; - } else if (sbHuffDT == 2) { - huffmanDTTable = HuffmanDecoder.huffmanTableM; - } - - int sbHuffRDW = textRegionHuffmanFlags.getFlagValue(TextRegionHuffmanFlags.SB_HUFF_RDW); - if (sbHuffRDW == 0) { - huffmanRDWTable = HuffmanDecoder.huffmanTableN; - } else if (sbHuffRDW == 1) { - huffmanRDWTable = HuffmanDecoder.huffmanTableO; - } - - int sbHuffRDH = textRegionHuffmanFlags.getFlagValue(TextRegionHuffmanFlags.SB_HUFF_RDH); - if (sbHuffRDH == 0) { - huffmanRDHTable = HuffmanDecoder.huffmanTableN; - } else if (sbHuffRDH == 1) { - huffmanRDHTable = HuffmanDecoder.huffmanTableO; - } - - int sbHuffRDX = textRegionHuffmanFlags.getFlagValue(TextRegionHuffmanFlags.SB_HUFF_RDX); - if (sbHuffRDX == 0) { - huffmanRDXTable = HuffmanDecoder.huffmanTableN; - } else if (sbHuffRDX == 1) { - huffmanRDXTable = HuffmanDecoder.huffmanTableO; - } - int sbHuffRDY = textRegionHuffmanFlags.getFlagValue(TextRegionHuffmanFlags.SB_HUFF_RDY); - if (sbHuffRDY == 0) { - huffmanRDYTable = HuffmanDecoder.huffmanTableN; - } else if (sbHuffRDY == 1) { - huffmanRDYTable = HuffmanDecoder.huffmanTableO; - } - - int sbHuffRSize = textRegionHuffmanFlags.getFlagValue(TextRegionHuffmanFlags.SB_HUFF_RSIZE); - if (sbHuffRSize == 0) { - huffmanRSizeTable = HuffmanDecoder.huffmanTableA; - } - } - - int[][] runLengthTable = new int[36][4]; - int[][] symbolCodeTable = new int[noOfSymbols + 1][4]; - if (sbHuffman) { - - decoder.consumeRemainingBits(); - - for (i = 0; i < 32; i++) { - runLengthTable[i] = new int[]{i, decoder.readBits(4), 0, 0}; - } - - runLengthTable[32] = new int[]{0x103, decoder.readBits(4), 2, 0}; - - runLengthTable[33] = new int[]{0x203, decoder.readBits(4), 3, 0}; - - runLengthTable[34] = new int[]{0x20b, decoder.readBits(4), 7, 0}; - - runLengthTable[35] = new int[]{0, 0, HuffmanDecoder.jbig2HuffmanEOT}; - - runLengthTable = HuffmanDecoder.buildTable(runLengthTable, 35); - - for (i = 0; i < noOfSymbols; i++) { - symbolCodeTable[i] = new int[]{i, 0, 0, 0}; - } - - i = 0; - while (i < noOfSymbols) { - int j = huffmanDecoder.decodeInt(runLengthTable).intResult(); - if (j > 0x200) { - for (j -= 0x200; j != 0 && i < noOfSymbols; j--) { - symbolCodeTable[i++][1] = 0; - } - } else if (j > 0x100) { - for (j -= 0x100; j != 0 && i < noOfSymbols; j--) { - symbolCodeTable[i][1] = symbolCodeTable[i - 1][1]; - i++; - } - } else { - symbolCodeTable[i++][1] = j; - } - } - - symbolCodeTable[noOfSymbols][1] = 0; - symbolCodeTable[noOfSymbols][2] = HuffmanDecoder.jbig2HuffmanEOT; - symbolCodeTable = HuffmanDecoder.buildTable(symbolCodeTable, noOfSymbols); - - decoder.consumeRemainingBits(); - } else { - symbolCodeTable = null; - arithmeticDecoder.resetIntStats(symbolCodeLength); - arithmeticDecoder.start(); - } - - boolean symbolRefine = textRegionFlags.getFlagValue(TextRegionFlags.SB_REFINE) != 0; - int logStrips = textRegionFlags.getFlagValue(TextRegionFlags.LOG_SB_STRIPES); - int defaultPixel = textRegionFlags.getFlagValue(TextRegionFlags.SB_DEF_PIXEL); - int combinationOperator = textRegionFlags.getFlagValue(TextRegionFlags.SB_COMB_OP); - boolean transposed = textRegionFlags.getFlagValue(TextRegionFlags.TRANSPOSED) != 0; - int referenceCorner = textRegionFlags.getFlagValue(TextRegionFlags.REF_CORNER); - int sOffset = textRegionFlags.getFlagValue(TextRegionFlags.SB_DS_OFFSET); - int template = textRegionFlags.getFlagValue(TextRegionFlags.SB_R_TEMPLATE); - - if (symbolRefine) { - arithmeticDecoder.resetRefinementStats(template, null); - } - - JBIG2Bitmap bitmap = new JBIG2Bitmap(regionBitmapWidth, regionBitmapHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - - bitmap.readTextRegion(sbHuffman, symbolRefine, noOfSymbolInstances, logStrips, noOfSymbols, symbolCodeTable, symbolCodeLength, symbols, defaultPixel, combinationOperator, transposed, referenceCorner, sOffset, huffmanFSTable, huffmanDSTable, huffmanDTTable, huffmanRDWTable, huffmanRDHTable, huffmanRDXTable, huffmanRDYTable, huffmanRSizeTable, template, symbolRegionAdaptiveTemplateX, symbolRegionAdaptiveTemplateY, decoder); - - if (inlineImage) { - PageInformationSegment pageSegment = decoder.findPageSegement(segmentHeader.getPageAssociation()); - JBIG2Bitmap pageBitmap = pageSegment.getPageBitmap(); - - if (JBIG2StreamDecoder.debug) - System.out.println(pageBitmap + " " + bitmap); - - int externalCombinationOperator = regionFlags.getFlagValue(RegionFlags.EXTERNAL_COMBINATION_OPERATOR); - pageBitmap.combine(bitmap, regionBitmapXLocation, regionBitmapYLocation, externalCombinationOperator); - } else { - bitmap.setBitmapNumber(getSegmentHeader().getSegmentNumber()); - decoder.appendBitmap(bitmap); - } - - decoder.consumeRemainingBits(); - } - - private void readTextRegionFlags() throws IOException { - /** extract text region Segment flags */ - short[] textRegionFlagsField = new short[2]; - decoder.readByte(textRegionFlagsField); - - int flags = BinaryOperation.getInt16(textRegionFlagsField); - textRegionFlags.setFlags(flags); - - if (JBIG2StreamDecoder.debug) - System.out.println("text region Segment flags = " + flags); - - boolean sbHuff = textRegionFlags.getFlagValue(TextRegionFlags.SB_HUFF) != 0; - if (sbHuff) { - /** extract text region Segment Huffman flags */ - short[] textRegionHuffmanFlagsField = new short[2]; - decoder.readByte(textRegionHuffmanFlagsField); - - flags = BinaryOperation.getInt16(textRegionHuffmanFlagsField); - textRegionHuffmanFlags.setFlags(flags); - - if (JBIG2StreamDecoder.debug) - System.out.println("text region segment Huffman flags = " + flags); - } - - boolean sbRefine = textRegionFlags.getFlagValue(TextRegionFlags.SB_REFINE) != 0; - int sbrTemplate = textRegionFlags.getFlagValue(TextRegionFlags.SB_R_TEMPLATE); - if (sbRefine && sbrTemplate == 0) { - symbolRegionAdaptiveTemplateX[0] = readATValue(); - symbolRegionAdaptiveTemplateY[0] = readATValue(); - symbolRegionAdaptiveTemplateX[1] = readATValue(); - symbolRegionAdaptiveTemplateY[1] = readATValue(); - } - } - - public TextRegionFlags getTextRegionFlags() { - return textRegionFlags; - } - - public TextRegionHuffmanFlags getTextRegionHuffmanFlags() { - return textRegionHuffmanFlags; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/stripes/EndOfStripeSegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/stripes/EndOfStripeSegment.java deleted file mode 100644 index 62cd5845ee..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/stripes/EndOfStripeSegment.java +++ /dev/null @@ -1,69 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* EndOfStripeSegment.java -* --------------- - */ -package org.jpedal.jbig2.segment.stripes; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Segment; - -import java.io.IOException; - -public class EndOfStripeSegment extends Segment { - - public EndOfStripeSegment(JBIG2StreamDecoder streamDecoder) { - super(streamDecoder); - } - - public void readSegment() throws IOException, JBIG2Exception { - for (int i = 0; i < this.getSegmentHeader().getSegmentDataLength(); i++) { - decoder.readByte(); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/symboldictionary/SymbolDictionaryFlags.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/symboldictionary/SymbolDictionaryFlags.java deleted file mode 100644 index 84e33de484..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/symboldictionary/SymbolDictionaryFlags.java +++ /dev/null @@ -1,104 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* SymbolDictionaryFlags.java -* --------------- - */ -package org.jpedal.jbig2.segment.symboldictionary; - -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.segment.Flags; - -public class SymbolDictionaryFlags extends Flags { - - public static String SD_HUFF = "SD_HUFF"; - public static String SD_REF_AGG = "SD_REF_AGG"; - public static String SD_HUFF_DH = "SD_HUFF_DH"; - public static String SD_HUFF_DW = "SD_HUFF_DW"; - public static String SD_HUFF_BM_SIZE = "SD_HUFF_BM_SIZE"; - public static String SD_HUFF_AGG_INST = "SD_HUFF_AGG_INST"; - public static String BITMAP_CC_USED = "BITMAP_CC_USED"; - public static String BITMAP_CC_RETAINED = "BITMAP_CC_RETAINED"; - public static String SD_TEMPLATE = "SD_TEMPLATE"; - public static String SD_R_TEMPLATE = "SD_R_TEMPLATE"; - - public void setFlags(int flagsAsInt) { - this.flagsAsInt = flagsAsInt; - - /** extract SD_HUFF */ - flags.put(SD_HUFF, new Integer(flagsAsInt & 1)); - - /** extract SD_REF_AGG */ - flags.put(SD_REF_AGG, new Integer((flagsAsInt >> 1) & 1)); - - /** extract SD_HUFF_DH */ - flags.put(SD_HUFF_DH, new Integer((flagsAsInt >> 2) & 3)); - - /** extract SD_HUFF_DW */ - flags.put(SD_HUFF_DW, new Integer((flagsAsInt >> 4) & 3)); - - /** extract SD_HUFF_BM_SIZE */ - flags.put(SD_HUFF_BM_SIZE, new Integer((flagsAsInt >> 6) & 1)); - - /** extract SD_HUFF_AGG_INST */ - flags.put(SD_HUFF_AGG_INST, new Integer((flagsAsInt >> 7) & 1)); - - /** extract BITMAP_CC_USED */ - flags.put(BITMAP_CC_USED, new Integer((flagsAsInt >> 8) & 1)); - - /** extract BITMAP_CC_RETAINED */ - flags.put(BITMAP_CC_RETAINED, new Integer((flagsAsInt >> 9) & 1)); - - /** extract SD_TEMPLATE */ - flags.put(SD_TEMPLATE, new Integer((flagsAsInt >> 10) & 3)); - - /** extract SD_R_TEMPLATE */ - flags.put(SD_R_TEMPLATE, new Integer((flagsAsInt >> 12) & 1)); - - if (JBIG2StreamDecoder.debug) - System.out.println(flags); - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/symboldictionary/SymbolDictionarySegment.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/symboldictionary/SymbolDictionarySegment.java deleted file mode 100644 index bbf67ee6bd..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/symboldictionary/SymbolDictionarySegment.java +++ /dev/null @@ -1,510 +0,0 @@ -/** - * =========================================== - * Java Pdf Extraction Decoding Access Library - * =========================================== - * - * Project Info: http://www.jpedal.org - * (C) Copyright 1997-2008, IDRsolutions and Contributors. - * Main Developer: Simon Barnett - * - * This file is part of JPedal - * - * Copyright (c) 2008, IDRsolutions - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the IDRsolutions nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Other JBIG2 image decoding implementations include - * jbig2dec (http://jbig2dec.sourceforge.net/) - * xpdf (http://www.foolabs.com/xpdf/) - * - * The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf - * - * All three of the above resources were used in the writing of this software, with methodologies, - * processes and inspiration taken from all three. - * - * --------------- - * SymbolDictionarySegment.java - * --------------- - */ -package org.jpedal.jbig2.segment.symboldictionary; - -import org.jpedal.jbig2.JBIG2Exception; -import org.jpedal.jbig2.decoders.ArithmeticDecoderStats; -import org.jpedal.jbig2.decoders.DecodeIntResult; -import org.jpedal.jbig2.decoders.HuffmanDecoder; -import org.jpedal.jbig2.decoders.JBIG2StreamDecoder; -import org.jpedal.jbig2.image.JBIG2Bitmap; -import org.jpedal.jbig2.segment.Segment; -import org.jpedal.jbig2.segment.tables.JBIG2CodeTable; -import org.jpedal.jbig2.util.BinaryOperation; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -public class SymbolDictionarySegment extends Segment { - - private int noOfExportedSymbols; - private int noOfNewSymbols; - - short[] symbolDictionaryAdaptiveTemplateX = new short[4], symbolDictionaryAdaptiveTemplateY = new short[4]; - short[] symbolDictionaryRAdaptiveTemplateX = new short[2], symbolDictionaryRAdaptiveTemplateY = new short[2]; - - private JBIG2Bitmap[] bitmaps; - - private SymbolDictionaryFlags symbolDictionaryFlags = new SymbolDictionaryFlags(); - - private ArithmeticDecoderStats genericRegionStats; - private ArithmeticDecoderStats refinementRegionStats; - - public SymbolDictionarySegment(JBIG2StreamDecoder streamDecoder) { - super(streamDecoder); - } - - public void readSegment() throws IOException, JBIG2Exception { - - if (JBIG2StreamDecoder.debug) - System.out.println("==== Read Segment Symbol Dictionary ===="); - - /** read symbol dictionary flags */ - readSymbolDictionaryFlags(); - - List codeTables = new ArrayList(); - int numberOfInputSymbols = 0; - int noOfReferredToSegments = segmentHeader.getReferredToSegmentCount(); - int[] referredToSegments = segmentHeader.getReferredToSegments(); - - for (int i = 0; i < noOfReferredToSegments; i++) { - Segment seg = decoder.findSegment(referredToSegments[i]); - int type = seg.getSegmentHeader().getSegmentType(); - - if (type == Segment.SYMBOL_DICTIONARY) { - numberOfInputSymbols += ((SymbolDictionarySegment) seg).noOfExportedSymbols; - } else if (type == Segment.TABLES) { - codeTables.add(seg); - } - } - - int symbolCodeLength = 0; - int i = 1; - while (i < numberOfInputSymbols + noOfNewSymbols) { - symbolCodeLength++; - i <<= 1; - } - - JBIG2Bitmap[] bitmaps = new JBIG2Bitmap[numberOfInputSymbols + noOfNewSymbols]; - - int k = 0; - SymbolDictionarySegment inputSymbolDictionary = null; - for (i = 0; i < noOfReferredToSegments; i++) { - Segment seg = decoder.findSegment(referredToSegments[i]); - if (seg.getSegmentHeader().getSegmentType() == Segment.SYMBOL_DICTIONARY) { - inputSymbolDictionary = (SymbolDictionarySegment) seg; - for (int j = 0; j < inputSymbolDictionary.noOfExportedSymbols; j++) { - bitmaps[k++] = inputSymbolDictionary.bitmaps[j]; - } - } - } - - int[][] huffmanDHTable = null; - int[][] huffmanDWTable = null; - - int[][] huffmanBMSizeTable = null; - int[][] huffmanAggInstTable = null; - - boolean sdHuffman = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF) != 0; - int sdHuffmanDifferenceHeight = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF_DH); - int sdHuffmanDiferrenceWidth = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF_DW); - int sdHuffBitmapSize = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF_BM_SIZE); - int sdHuffAggregationInstances = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF_AGG_INST); - - i = 0; - if (sdHuffman) { - if (sdHuffmanDifferenceHeight == 0) { - huffmanDHTable = HuffmanDecoder.huffmanTableD; - } else if (sdHuffmanDifferenceHeight == 1) { - huffmanDHTable = HuffmanDecoder.huffmanTableE; - } else { - huffmanDHTable = ((JBIG2CodeTable) codeTables.get(i++)).getHuffTable(); - } - - if (sdHuffmanDiferrenceWidth == 0) { - huffmanDWTable = HuffmanDecoder.huffmanTableB; - } else if (sdHuffmanDiferrenceWidth == 1) { - huffmanDWTable = HuffmanDecoder.huffmanTableC; - } else { - huffmanDWTable = ((JBIG2CodeTable) codeTables.get(i++)).getHuffTable(); - } - - if (sdHuffBitmapSize == 0) { - huffmanBMSizeTable = HuffmanDecoder.huffmanTableA; - } else { - huffmanBMSizeTable = ((JBIG2CodeTable) codeTables.get(i++)).getHuffTable(); - } - - if (sdHuffAggregationInstances == 0) { - huffmanAggInstTable = HuffmanDecoder.huffmanTableA; - } else { - huffmanAggInstTable = ((JBIG2CodeTable) codeTables.get(i++)).getHuffTable(); - } - } - - int contextUsed = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.BITMAP_CC_USED); - int sdTemplate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_TEMPLATE); - - if (!sdHuffman) { - if (contextUsed != 0 && inputSymbolDictionary != null) { - arithmeticDecoder.resetGenericStats(sdTemplate, inputSymbolDictionary.genericRegionStats); - } else { - arithmeticDecoder.resetGenericStats(sdTemplate, null); - } - arithmeticDecoder.resetIntStats(symbolCodeLength); - arithmeticDecoder.start(); - } - - int sdRefinementAggregate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_REF_AGG); - int sdRefinementTemplate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_R_TEMPLATE); - if (sdRefinementAggregate != 0) { - if (contextUsed != 0 && inputSymbolDictionary != null) { - arithmeticDecoder.resetRefinementStats(sdRefinementTemplate, inputSymbolDictionary.refinementRegionStats); - } else { - arithmeticDecoder.resetRefinementStats(sdRefinementTemplate, null); - } - } - - int deltaWidths[] = new int[noOfNewSymbols]; - - int deltaHeight = 0; - i = 0; - - while (i < noOfNewSymbols) { - - int instanceDeltaHeight; - - if (sdHuffman) { - instanceDeltaHeight = huffmanDecoder.decodeInt(huffmanDHTable).intResult(); - } else { - instanceDeltaHeight = arithmeticDecoder.decodeInt(arithmeticDecoder.iadhStats).intResult(); - } - - if (instanceDeltaHeight < 0 && -instanceDeltaHeight >= deltaHeight) { - if (JBIG2StreamDecoder.debug) - System.out.println("Bad delta-height value in JBIG2 symbol dictionary"); - } - - deltaHeight += instanceDeltaHeight; - int symbolWidth = 0; - int totalWidth = 0; - int j = i; - - while (true) { - - int deltaWidth; - - DecodeIntResult decodeIntResult; - if (sdHuffman) { - decodeIntResult = huffmanDecoder.decodeInt(huffmanDWTable); - } else { - decodeIntResult = arithmeticDecoder.decodeInt(arithmeticDecoder.iadwStats); - } - - if (!decodeIntResult.booleanResult()) - break; - - deltaWidth = decodeIntResult.intResult(); - - if (deltaWidth < 0 && -deltaWidth >= symbolWidth) { - if (JBIG2StreamDecoder.debug) - System.out.println("Bad delta-width value in JBIG2 symbol dictionary"); - } - - symbolWidth += deltaWidth; - - if (sdHuffman && sdRefinementAggregate == 0) { - deltaWidths[i] = symbolWidth; - totalWidth += symbolWidth; - - } else if (sdRefinementAggregate == 1) { - - int refAggNum; - - if (sdHuffman) { - refAggNum = huffmanDecoder.decodeInt(huffmanAggInstTable).intResult(); - } else { - refAggNum = arithmeticDecoder.decodeInt(arithmeticDecoder.iaaiStats).intResult(); - } - - if (refAggNum == 1) { - - int symbolID, referenceDX, referenceDY; - - if (sdHuffman) { - symbolID = decoder.readBits(symbolCodeLength); - referenceDX = huffmanDecoder.decodeInt(HuffmanDecoder.huffmanTableO).intResult(); - referenceDY = huffmanDecoder.decodeInt(HuffmanDecoder.huffmanTableO).intResult(); - - decoder.consumeRemainingBits(); - arithmeticDecoder.start(); - } else { - symbolID = (int) arithmeticDecoder.decodeIAID(symbolCodeLength, arithmeticDecoder.iaidStats); - referenceDX = arithmeticDecoder.decodeInt(arithmeticDecoder.iardxStats).intResult(); - referenceDY = arithmeticDecoder.decodeInt(arithmeticDecoder.iardyStats).intResult(); - } - - JBIG2Bitmap referredToBitmap = bitmaps[symbolID]; - - JBIG2Bitmap bitmap = new JBIG2Bitmap(symbolWidth, deltaHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - bitmap.readGenericRefinementRegion(sdRefinementTemplate, false, referredToBitmap, referenceDX, referenceDY, symbolDictionaryRAdaptiveTemplateX, - symbolDictionaryRAdaptiveTemplateY); - - bitmaps[numberOfInputSymbols + i] = bitmap; - - } else { - JBIG2Bitmap bitmap = new JBIG2Bitmap(symbolWidth, deltaHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - bitmap.readTextRegion(sdHuffman, true, refAggNum, 0, numberOfInputSymbols + i, null, symbolCodeLength, bitmaps, 0, 0, false, 1, 0, - HuffmanDecoder.huffmanTableF, HuffmanDecoder.huffmanTableH, HuffmanDecoder.huffmanTableK, HuffmanDecoder.huffmanTableO, HuffmanDecoder.huffmanTableO, - HuffmanDecoder.huffmanTableO, HuffmanDecoder.huffmanTableO, HuffmanDecoder.huffmanTableA, sdRefinementTemplate, symbolDictionaryRAdaptiveTemplateX, - symbolDictionaryRAdaptiveTemplateY, decoder); - - bitmaps[numberOfInputSymbols + i] = bitmap; - } - } else { - JBIG2Bitmap bitmap = new JBIG2Bitmap(symbolWidth, deltaHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - bitmap.readBitmap(false, sdTemplate, false, false, null, symbolDictionaryAdaptiveTemplateX, symbolDictionaryAdaptiveTemplateY, 0); - bitmaps[numberOfInputSymbols + i] = bitmap; - } - - i++; - } - - if (sdHuffman && sdRefinementAggregate == 0) { - int bmSize = huffmanDecoder.decodeInt(huffmanBMSizeTable).intResult(); - decoder.consumeRemainingBits(); - - JBIG2Bitmap collectiveBitmap = new JBIG2Bitmap(totalWidth, deltaHeight, arithmeticDecoder, huffmanDecoder, mmrDecoder); - - if (bmSize == 0) { - - int padding = totalWidth % 8; - int bytesPerRow = (int) Math.ceil(totalWidth / 8d); - - //short[] bitmap = new short[totalWidth]; - //decoder.readByte(bitmap); - int size = deltaHeight * ((totalWidth + 7) >> 3); - short[] bitmap = new short[size]; - decoder.readByte(bitmap); - - short[][] logicalMap = new short[deltaHeight][bytesPerRow]; - int count = 0; - for (int row = 0; row < deltaHeight; row++) { - for (int col = 0; col < bytesPerRow; col++) { - logicalMap[row][col] = bitmap[count]; - count++; - } - } - - int collectiveBitmapRow = 0, collectiveBitmapCol = 0; - - for (int row = 0; row < deltaHeight; row++) { - for (int col = 0; col < bytesPerRow; col++) { - if (col == (bytesPerRow - 1)) { // this is the last - // byte in the row - short currentByte = logicalMap[row][col]; - for (int bitPointer = 7; bitPointer >= padding; bitPointer--) { - short mask = (short) (1 << bitPointer); - int bit = (currentByte & mask) >> bitPointer; - - collectiveBitmap.setPixel(collectiveBitmapCol, collectiveBitmapRow, bit); - collectiveBitmapCol++; - } - collectiveBitmapRow++; - collectiveBitmapCol = 0; - } else { - short currentByte = logicalMap[row][col]; - for (int bitPointer = 7; bitPointer >= 0; bitPointer--) { - short mask = (short) (1 << bitPointer); - int bit = (currentByte & mask) >> bitPointer; - - collectiveBitmap.setPixel(collectiveBitmapCol, collectiveBitmapRow, bit); - collectiveBitmapCol++; - } - } - } - } - - } else { - collectiveBitmap.readBitmap(true, 0, false, false, null, null, null, bmSize); - } - - int x = 0; - while (j < i) { - bitmaps[numberOfInputSymbols + j] = collectiveBitmap.getSlice(x, 0, deltaWidths[j], deltaHeight); - x += deltaWidths[j]; - - j++; - } - } - } - - this.bitmaps = new JBIG2Bitmap[noOfExportedSymbols]; - - int j = i = 0; - boolean export = false; - while (i < numberOfInputSymbols + noOfNewSymbols) { - - int run; - if (sdHuffman) { - run = huffmanDecoder.decodeInt(HuffmanDecoder.huffmanTableA).intResult(); - } else { - run = arithmeticDecoder.decodeInt(arithmeticDecoder.iaexStats).intResult(); - } - - if (export) { - for (int cnt = 0; cnt < run; cnt++) { - this.bitmaps[j++] = bitmaps[i++]; - } - } else { - i += run; - } - - export = !export; - } - - int contextRetained = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.BITMAP_CC_RETAINED); - if (!sdHuffman && contextRetained == 1) { - genericRegionStats = genericRegionStats.copy(); - if (sdRefinementAggregate == 1) { - refinementRegionStats = refinementRegionStats.copy(); - } - } - - /** consume any remaining bits */ - decoder.consumeRemainingBits(); - } - - private void readSymbolDictionaryFlags() throws IOException { - /** extract symbol dictionary flags */ - short[] symbolDictionaryFlagsField = new short[2]; - decoder.readByte(symbolDictionaryFlagsField); - - int flags = BinaryOperation.getInt16(symbolDictionaryFlagsField); - symbolDictionaryFlags.setFlags(flags); - - if (JBIG2StreamDecoder.debug) - System.out.println("symbolDictionaryFlags = " + flags); - - // symbol dictionary AT flags - int sdHuff = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_HUFF); - int sdTemplate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_TEMPLATE); - if (sdHuff == 0) { - if (sdTemplate == 0) { - symbolDictionaryAdaptiveTemplateX[0] = readATValue(); - symbolDictionaryAdaptiveTemplateY[0] = readATValue(); - symbolDictionaryAdaptiveTemplateX[1] = readATValue(); - symbolDictionaryAdaptiveTemplateY[1] = readATValue(); - symbolDictionaryAdaptiveTemplateX[2] = readATValue(); - symbolDictionaryAdaptiveTemplateY[2] = readATValue(); - symbolDictionaryAdaptiveTemplateX[3] = readATValue(); - symbolDictionaryAdaptiveTemplateY[3] = readATValue(); - } else { - symbolDictionaryAdaptiveTemplateX[0] = readATValue(); - symbolDictionaryAdaptiveTemplateY[0] = readATValue(); - } - } - - // symbol dictionary refinement AT flags - int refAgg = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_REF_AGG); - int sdrTemplate = symbolDictionaryFlags.getFlagValue(SymbolDictionaryFlags.SD_R_TEMPLATE); - if (refAgg != 0 && sdrTemplate == 0) { - symbolDictionaryRAdaptiveTemplateX[0] = readATValue(); - symbolDictionaryRAdaptiveTemplateY[0] = readATValue(); - symbolDictionaryRAdaptiveTemplateX[1] = readATValue(); - symbolDictionaryRAdaptiveTemplateY[1] = readATValue(); - } - - /** extract no of exported symbols */ - short[] noOfExportedSymbolsField = new short[4]; - decoder.readByte(noOfExportedSymbolsField); - - int noOfExportedSymbols = BinaryOperation.getInt32(noOfExportedSymbolsField); - this.noOfExportedSymbols = noOfExportedSymbols; - - if (JBIG2StreamDecoder.debug) - System.out.println("noOfExportedSymbols = " + noOfExportedSymbols); - - /** extract no of new symbols */ - short[] noOfNewSymbolsField = new short[4]; - decoder.readByte(noOfNewSymbolsField); - - int noOfNewSymbols = BinaryOperation.getInt32(noOfNewSymbolsField); - this.noOfNewSymbols = noOfNewSymbols; - - if (JBIG2StreamDecoder.debug) - System.out.println("noOfNewSymbols = " + noOfNewSymbols); - } - - public int getNoOfExportedSymbols() { - return noOfExportedSymbols; - } - - public void setNoOfExportedSymbols(int noOfExportedSymbols) { - this.noOfExportedSymbols = noOfExportedSymbols; - } - - public int getNoOfNewSymbols() { - return noOfNewSymbols; - } - - public void setNoOfNewSymbols(int noOfNewSymbols) { - this.noOfNewSymbols = noOfNewSymbols; - } - - public JBIG2Bitmap[] getBitmaps() { - return bitmaps; - } - - public SymbolDictionaryFlags getSymbolDictionaryFlags() { - return symbolDictionaryFlags; - } - - public void setSymbolDictionaryFlags(SymbolDictionaryFlags symbolDictionaryFlags) { - this.symbolDictionaryFlags = symbolDictionaryFlags; - } - - private ArithmeticDecoderStats getGenericRegionStats() { - return genericRegionStats; - } - - private void setGenericRegionStats(ArithmeticDecoderStats genericRegionStats) { - this.genericRegionStats = genericRegionStats; - } - - private void setRefinementRegionStats(ArithmeticDecoderStats refinementRegionStats) { - this.refinementRegionStats = refinementRegionStats; - } - - private ArithmeticDecoderStats getRefinementRegionStats() { - return refinementRegionStats; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/tables/JBIG2CodeTable.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/tables/JBIG2CodeTable.java deleted file mode 100644 index 2af55d1027..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/segment/tables/JBIG2CodeTable.java +++ /dev/null @@ -1,57 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* JBIG2CodeTable.java -* --------------- - */ -package org.jpedal.jbig2.segment.tables; - -public class JBIG2CodeTable { - - public static int[][] getHuffTable() { - return null; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/util/BinaryOperation.java b/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/util/BinaryOperation.java deleted file mode 100644 index bb5294f4d1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/jpedal/jbig2/util/BinaryOperation.java +++ /dev/null @@ -1,88 +0,0 @@ -/** -* =========================================== -* Java Pdf Extraction Decoding Access Library -* =========================================== - * -* Project Info: http://www.jpedal.org -* (C) Copyright 1997-2008, IDRsolutions and Contributors. -* Main Developer: Simon Barnett -* -* This file is part of JPedal -* -* Copyright (c) 2008, IDRsolutions -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in the -* documentation and/or other materials provided with the distribution. -* * Neither the name of the IDRsolutions nor the -* names of its contributors may be used to endorse or promote products -* derived from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY IDRsolutions ``AS IS'' AND ANY -* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL IDRsolutions BE LIABLE FOR ANY -* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* Other JBIG2 image decoding implementations include -* jbig2dec (http://jbig2dec.sourceforge.net/) -* xpdf (http://www.foolabs.com/xpdf/) -* -* The final draft JBIG2 specification can be found at http://www.jpeg.org/public/fcd14492.pdf -* -* All three of the above resources were used in the writing of this software, with methodologies, -* processes and inspiration taken from all three. -* -* --------------- -* BinaryOperation.java -* --------------- - */ -package org.jpedal.jbig2.util; - -public class BinaryOperation { - - public static final int LEFT_SHIFT = 0; - public static final int RIGHT_SHIFT = 1; - - public static int getInt32(short[] number) { - return (number[0] << 24) | (number[1] << 16) | (number[2] << 8) | number[3]; - } - - public static int getInt16(short[] number) { - return (number[0] << 8) | number[1]; - } - - public static long bit32Shift(long number, int shift, int direction) { - if (direction == LEFT_SHIFT) - number <<= shift; - else - number >>= shift; - - long mask = 0xffffffffl; // 1111 1111 1111 1111 1111 1111 1111 1111 - return (number & mask); - } - - public static int bit8Shift(int number, int shift, int direction) { - if (direction == LEFT_SHIFT) - number <<= shift; - else - number >>= shift; - - int mask = 0xff; // 1111 1111 - return (number & mask); - } - - public static int getInt32(byte[] number) { - return (number[0] << 24) | (number[1] << 16) | (number[2] << 8) | number[3]; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/AttributeCondition.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/AttributeCondition.java deleted file mode 100644 index e23f0d0d08..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/AttributeCondition.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium, - * (Massachusetts Institute of Technology, Institut National de - * Recherche en Informatique et en Automatique, Keio University). All - * Rights Reserved. This program is distributed under the W3C's Software - * Intellectual Property License. This program is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. - * See W3C License http://www.w3.org/Consortium/Legal/ for more details. - * - * $Id: AttributeCondition.java,v 1.5 2002/06/17 14:10:09 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.5 $ - * @author Philippe Le Hegaret - * @see Condition#SAC_ATTRIBUTE_CONDITION - * @see Condition#SAC_ONE_OF_ATTRIBUTE_CONDITION - * @see Condition#SAC_BEGIN_HYPHEN_ATTRIBUTE_CONDITION - * @see Condition#SAC_ID_CONDITION - * @see Condition#SAC_CLASS_CONDITION - * @see Condition#SAC_PSEUDO_CLASS_CONDITION - */ -public interface AttributeCondition extends Condition { - - /** - * Returns the - * namespace - * URI of this attribute condition. - *

      NULL if : - *

        - *
      • this attribute condition can match any namespace. - *
      • this attribute is an id attribute. - *
      - */ - public String getNamespaceURI(); - - /** - * Returns the - * local part - * of the - * qualified - * name of this attribute. - *

      NULL if : - *

        - *
      • this attribute condition can match any attribute. - *

      • this attribute is a class attribute. - *

      • this attribute is an id attribute. - *

      • this attribute is a pseudo-class attribute. - *

      - */ - public String getLocalName(); - - /** - * Returns true if the attribute must have an explicit value - * in the original document, false otherwise. - */ - public boolean getSpecified(); - - /** - * Returns the value of the attribute. - * If this attribute is a class or a pseudo class attribute, you'll get - * the class name (or psedo class name) without the '.' or ':'. - */ - public String getValue(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CSSException.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CSSException.java deleted file mode 100644 index 255bcd88e3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CSSException.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * The original version of this interface comes from SAX : - * http://www.megginson.com/SAX/ - * - * $Id: CSSException.java,v 1.3 2002/06/17 14:09:36 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.3 $ - * @author Philippe Le Hegaret - */ -public class CSSException extends RuntimeException { - - protected String s; - - /** - * this error is unspecified. - */ - public static final short SAC_UNSPECIFIED_ERR = 0; - - /** - * If the operation is not supported - */ - public static final short SAC_NOT_SUPPORTED_ERR = 1; - - /** - * If an invalid or illegal string is specified - */ - public static final short SAC_SYNTAX_ERR = 2; - - /* - * Default message for unspecified error. - */ - protected static final String S_SAC_UNSPECIFIED_ERR - = "unknown error"; - /* - * Default message for not supported error. - */ - protected static final String S_SAC_NOT_SUPPORTED_ERR - = "not supported"; - /* - * Default message for syntax error. - */ - protected static final String S_SAC_SYNTAX_ERR - = "syntax error"; - - /** - * The internal exception. - */ - protected Exception e; - - protected short code; - - /** - * Creates a new CSSException - */ - public CSSException() { - } - - /** - * Creates a new CSSException - */ - public CSSException(String s) { - this.code = SAC_UNSPECIFIED_ERR; - this.s = s; - } - - /** - * Creates a new CSSException with an embeded exception. - * @param a the embeded exception. - */ - public CSSException(Exception e) { - this.code = SAC_UNSPECIFIED_ERR; - this.e = e; - } - - /** - * Creates a new CSSException with a specific code. - * @param a the embeded exception. - */ - public CSSException(short code) { - this.code = code; - } - - /** - * Creates a new CSSException with an embeded exception and a specified - * message. - * @param code the specified code. - * @param e the embeded exception. - */ - public CSSException(short code, String s, Exception e) { - this.code = code; - this.s = s; - this.e = e; - } - - /** - * Returns the detail message of this throwable object. - * - * @return the detail message of this Throwable, or null if this Throwable - * does not have a detail message. - */ - public String getMessage() { - if (s != null) { - return s; - } else if (e != null) { - return e.getMessage(); - } else { - switch (code) { - case SAC_UNSPECIFIED_ERR: - return S_SAC_UNSPECIFIED_ERR; - case SAC_NOT_SUPPORTED_ERR: - return S_SAC_NOT_SUPPORTED_ERR; - case SAC_SYNTAX_ERR: - return S_SAC_SYNTAX_ERR; - default: - return null; - } - } - } - - /** - * returns the error code for this exception. - */ - public short getCode() { - return code; - } - - /** - * Returns the internal exception if any, null otherwise. - */ - public Exception getException() { - return e; - } - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CSSParseException.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CSSParseException.java deleted file mode 100644 index 89a4e1fd71..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CSSParseException.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * The original version of this interface comes from SAX : - * http://www.megginson.com/SAX/ - * - * $Id: CSSParseException.java,v 1.3 2000/02/15 02:07:34 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * Encapsulate a CSS parse error or warning. - * - *

      This exception will include information for locating the error - * in the original CSS document. Note that although the application - * will receive a CSSParseException as the argument to the handlers - * in the ErrorHandler interface, the application is not actually - * required to throw the exception; instead, it can simply read the - * information in it and take a different action.

      - * - *

      Since this exception is a subclass of CSSException, it - * inherits the ability to wrap another exception.

      - * - * @version $Revision: 1.3 $ - * @author Philippe Le Hegaret - */ -public class CSSParseException extends CSSException { - - private String uri; - private int lineNumber; - private int columnNumber; - - /** - * Create a new CSSParseException from a message and a Locator. - * - *

      This constructor is especially useful when an application is - * creating its own exception from within a DocumentHandler - * callback.

      - * - * @param message The error or warning message. - * @param locator The locator object for the error or warning. - * @see Locator - * @see Parser#setLocale - */ - public CSSParseException(String message, Locator locator) { - super(message); - this.code = SAC_SYNTAX_ERR; - this.uri = locator.getURI(); - this.lineNumber = locator.getLineNumber(); - this.columnNumber = locator.getColumnNumber(); - } - - - /** - - * Wrap an existing exception in a CSSParseException. - * - *

      This constructor is especially useful when an application is - * creating its own exception from within a DocumentHandler - * callback, and needs to wrap an existing exception that is not a - * subclass of CSSException.

      - * - * @param message The error or warning message, or null to - * use the message from the embedded exception. - * @param locator The locator object for the error or warning. - * @param e Any exception - * @see Locator - * @see Parser#setLocale - */ - public CSSParseException(String message, Locator locator, - Exception e) { - super(SAC_SYNTAX_ERR, message, e); - this.uri = locator.getURI(); - this.lineNumber = locator.getLineNumber(); - this.columnNumber = locator.getColumnNumber(); - } - - - /** - * Create a new CSSParseException. - * - *

      This constructor is most useful for parser writers.

      - * - *

      the parser must resolve the URI fully before creating the exception.

      - * - * @param message The error or warning message. - * @param uri The URI of the document that generated the error or warning. - * @param lineNumber The line number of the end of the text that - * caused the error or warning. - * @param columnNumber The column number of the end of the text that - * cause the error or warning. - * @see Parser#setLocale - */ - public CSSParseException(String message, String uri, - int lineNumber, int columnNumber) { - super(message); - this.code = SAC_SYNTAX_ERR; - this.uri = uri; - this.lineNumber = lineNumber; - this.columnNumber = columnNumber; - } - - /** - * Create a new CSSParseException with an embedded exception. - * - *

      This constructor is most useful for parser writers who - * need to wrap an exception that is not a subclass of - * CSSException.

      - * - *

      The parser must resolve the URI fully before creating the - * exception.

      - * - * @param message The error or warning message, or null to use - * the message from the embedded exception. - * @param uri The URI of the document that generated - * the error or warning. - * @param lineNumber The line number of the end of the text that - * caused the error or warning. - * @param columnNumber The column number of the end of the text that - * cause the error or warning. - * @param e Another exception to embed in this one. - * @see Parser#setLocale - */ - public CSSParseException(String message, String uri, - int lineNumber, int columnNumber, Exception e) { - super(SAC_SYNTAX_ERR, message, e); - this.uri = uri; - this.lineNumber = lineNumber; - this.columnNumber = columnNumber; - } - - /** - * Get the URI of the document where the exception occurred. - * - *

      The URI will be resolved fully.

      - * - * @return A string containing the URI, or null - * if none is available. - * @see Locator#getURI - */ - public String getURI() { - return this.uri; - } - - - /** - * The line number of the end of the text where the exception occurred. - * - * @return An integer representing the line number, or -1 - * if none is available. - * @see Locator#getLineNumber - */ - public int getLineNumber() { - return this.lineNumber; - } - - - /** - * The column number of the end of the text where the exception occurred. - * - *

      The first column in a line is position 1.

      - * - * @return An integer representing the column number, or -1 - * if none is available. - * @see Locator#getColumnNumber - */ - public int getColumnNumber() { - return this.columnNumber; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CharacterDataSelector.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CharacterDataSelector.java deleted file mode 100644 index 708b3fbfde..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CharacterDataSelector.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: CharacterDataSelector.java,v 1.3 1999/09/26 10:05:32 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.3 $ - * @author Philippe Le Hegaret - * @see Selector#SAC_TEXT_NODE_SELECTOR - * @see Selector#SAC_CDATA_SECTION_NODE_SELECTOR - * @see Selector#SAC_COMMENT_NODE_SELECTOR - */ -public interface CharacterDataSelector extends SimpleSelector { - - /** - * Returns the character data. - */ - public String getData(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CombinatorCondition.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CombinatorCondition.java deleted file mode 100644 index 26c63d0c8e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/CombinatorCondition.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: CombinatorCondition.java,v 1.3 2000/03/08 20:55:41 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.3 $ - * @author Philippe Le Hegaret - * @see Condition#SAC_AND_CONDITION - * @see Condition#SAC_OR_CONDITION - */ -public interface CombinatorCondition extends Condition { - - /** - * Returns the first condition. - */ - public Condition getFirstCondition(); - - /** - * Returns the second condition. - */ - public Condition getSecondCondition(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Condition.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Condition.java deleted file mode 100644 index 8e75436612..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Condition.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium, - * (Massachusetts Institute of Technology, Institut National de - * Recherche en Informatique et en Automatique, Keio University). All - * Rights Reserved. This program is distributed under the W3C's Software - * Intellectual Property License. This program is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. - * See W3C License http://www.w3.org/Consortium/Legal/ for more details. - * - * $Id: Condition.java,v 1.8 2000/02/14 15:54:12 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.8 $ - * @author Philippe Le Hegaret - */ -public interface Condition { - - /** - * This condition checks exactly two conditions. - * example: - *
      -     *   .part1:lang(fr)
      -     * 
      - * @see CombinatorCondition - */ - public static final short SAC_AND_CONDITION = 0; - - /** - * This condition checks one of two conditions. - * @see CombinatorCondition - */ - public static final short SAC_OR_CONDITION = 1; - - /** - * This condition checks that a condition can't be applied to a node. - * @see NegativeCondition - */ - public static final short SAC_NEGATIVE_CONDITION = 2; - - /** - * This condition checks a specified position. - * example: - *
      -     *   :first-child
      -     * 
      - * @see PositionalCondition - */ - public static final short SAC_POSITIONAL_CONDITION = 3; - - /** - * This condition checks an attribute. - * example: - *
      -     *   [simple]
      -     *   [restart="never"]
      -     * 
      - * @see AttributeCondition - */ - public static final short SAC_ATTRIBUTE_CONDITION = 4; - /** - * This condition checks an id attribute. - * example: - *
      -     *   #myId
      -     * 
      - * @see AttributeCondition - */ - public static final short SAC_ID_CONDITION = 5; - /** - * This condition checks the language of the node. - * example: - *
      -     *   :lang(fr)
      -     * 
      - * @see LangCondition - */ - public static final short SAC_LANG_CONDITION = 6; - /** - * This condition checks for a value in a space-separated values in a - * specified attribute - * example: - *
      -     *   [values~="10"]
      -     * 
      - * @see AttributeCondition - */ - public static final short SAC_ONE_OF_ATTRIBUTE_CONDITION = 7; - /** - * This condition checks if the value is in a hypen-separated list of values - * in a specified attribute. - * example: - *
      -     *   [languages|="fr"]
      -     * 
      - * @see AttributeCondition - */ - public static final short SAC_BEGIN_HYPHEN_ATTRIBUTE_CONDITION = 8; - /** - * This condition checks for a specified class. - * example: - *
      -     *   .example
      -     * 
      - * @see AttributeCondition - */ - public static final short SAC_CLASS_CONDITION = 9; - /** - * This condition checks for the link pseudo class. - * example: - *
      -     *   :link
      -     *   :visited
      -     *   :hover
      -     * 
      - * @see AttributeCondition - */ - public static final short SAC_PSEUDO_CLASS_CONDITION = 10; - /** - * This condition checks if a node is the only one in the node list. - */ - public static final short SAC_ONLY_CHILD_CONDITION = 11; - /** - * This condition checks if a node is the only one of his type. - */ - public static final short SAC_ONLY_TYPE_CONDITION = 12; - /** - * This condition checks the content of a node. - * @see ContentCondition - */ - public static final short SAC_CONTENT_CONDITION = 13; - - /** - * An integer indicating the type of Condition. - */ - public short getConditionType(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ConditionFactory.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ConditionFactory.java deleted file mode 100644 index 13a1a40823..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ConditionFactory.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium, - * (Massachusetts Institute of Technology, Institut National de - * Recherche en Informatique et en Automatique, Keio University). All - * Rights Reserved. This program is distributed under the W3C's Software - * Intellectual Property License. This program is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. - * See W3C License http://www.w3.org/Consortium/Legal/ for more details. - * - * $Id: ConditionFactory.java,v 1.2 2000/02/15 02:07:34 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.2 $ - * @author Philippe Le Hegaret - */ -public interface ConditionFactory { - - /** - * Creates an and condition - * - * @param first the first condition - * @param second the second condition - * @return A combinator condition - * @exception CSSException if this exception is not supported. - */ - CombinatorCondition createAndCondition(Condition first, Condition second) - throws CSSException; - - /** - * Creates an or condition - * - * @param first the first condition - * @param second the second condition - * @return A combinator condition - * @exception CSSException if this exception is not supported. - */ - CombinatorCondition createOrCondition(Condition first, Condition second) - throws CSSException; - - /** - * Creates a negative condition - * - * @param condition the condition - * @return A negative condition - * @exception CSSException if this exception is not supported. - */ - NegativeCondition createNegativeCondition(Condition condition) - throws CSSException; - - /** - * Creates a positional condition - * - * @param position the position of the node in the list. - * @param typeNode true if the list should contain - * only nodes of the same type (element, text node, ...). - * @param type true true if the list should contain - * only nodes of the same node (for element, same localName - * and same namespaceURI). - * @return A positional condition - * @exception CSSException if this exception is not supported. - */ - PositionalCondition createPositionalCondition(int position, - boolean typeNode, - boolean type) - throws CSSException; - - /** - * Creates an attribute condition - * - * @param localName the localName of the attribute - * @param namespaceURI the namespace URI of the attribute - * @param specified true if the attribute must be specified - * in the document. - * @param value the value of this attribute. - * @return An attribute condition - * @exception CSSException if this exception is not supported. - */ - AttributeCondition createAttributeCondition(String localName, - String namespaceURI, - boolean specified, - String value) - throws CSSException; - - /** - * Creates an id condition - * - * @param value the value of the id. - * @return An Id condition - * @exception CSSException if this exception is not supported. - */ - AttributeCondition createIdCondition(String value) - throws CSSException; - - /** - * Creates a lang condition - * - * @param value the value of the language. - * @return A lang condition - * @exception CSSException if this exception is not supported. - */ - LangCondition createLangCondition(String lang) - throws CSSException; - - /** - * Creates a "one of" attribute condition - * - * @param localName the localName of the attribute - * @param namespaceURI the namespace URI of the attribute - * @param specified true if the attribute must be specified - * in the document. - * @param value the value of this attribute. - * @return A "one of" attribute condition - * @exception CSSException if this exception is not supported. - */ - AttributeCondition createOneOfAttributeCondition(String localName, - String namespaceURI, - boolean specified, - String value) - throws CSSException; - - /** - * Creates a "begin hyphen" attribute condition - * - * @param localName the localName of the attribute - * @param namespaceURI the namespace URI of the attribute - * @param specified true if the attribute must be specified - * in the document. - * @param value the value of this attribute. - * @return A "begin hyphen" attribute condition - * @exception CSSException if this exception is not supported. - */ - AttributeCondition createBeginHyphenAttributeCondition(String localName, - String namespaceURI, - boolean specified, - String value) - throws CSSException; - - /** - * Creates a class condition - * - * @param localName the localName of the attribute - * @param namespaceURI the namespace URI of the attribute - * @param specified true if the attribute must be specified - * in the document. - * @param value the name of the class. - * @return A class condition - * @exception CSSException if this exception is not supported. - */ - AttributeCondition createClassCondition(String namespaceURI, - String value) - throws CSSException; - - /** - * Creates a pseudo class condition - * - * @param namespaceURI the namespace URI of the attribute - * @param value the name of the pseudo class - * @return A pseudo class condition - * @exception CSSException if this exception is not supported. - */ - AttributeCondition createPseudoClassCondition(String namespaceURI, - String value) - throws CSSException; - - /** - * Creates a "only one" child condition - * - * @return A "only one" child condition - * @exception CSSException if this exception is not supported. - */ - Condition createOnlyChildCondition() throws CSSException; - - - /** - * Creates a "only one" type condition - * - * @return A "only one" type condition - * @exception CSSException if this exception is not supported. - */ - Condition createOnlyTypeCondition() throws CSSException; - - /** - * Creates a content condition - * - * @param data the data in the content - * @return A content condition - * @exception CSSException if this exception is not supported. - */ - ContentCondition createContentCondition(String data) - throws CSSException; - - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ConditionalSelector.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ConditionalSelector.java deleted file mode 100644 index 28f89a55b1..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ConditionalSelector.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: ConditionalSelector.java,v 1.2 1999/09/25 12:32:36 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.2 $ - * @author Philippe Le Hegaret - * @see Selector#SAC_CONDITIONAL_SELECTOR - */ -public interface ConditionalSelector extends SimpleSelector { - - /** - * Returns the simple selector. - *

      The simple selector can't be a ConditionalSelector.

      - */ - public SimpleSelector getSimpleSelector(); - - /** - * Returns the condition to be applied on the simple selector. - */ - public Condition getCondition(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ContentCondition.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ContentCondition.java deleted file mode 100644 index 3893bb7d33..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ContentCondition.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: ContentCondition.java,v 1.1 1999/09/26 09:54:37 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.1 $ - * @author Philippe Le Hegaret - * @see Condition#SAC_CONTENT_CONDITION - */ -public interface ContentCondition extends Condition { - /** - * Returns the content. - */ - public String getData(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/DescendantSelector.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/DescendantSelector.java deleted file mode 100644 index 0f864e4dfc..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/DescendantSelector.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: DescendantSelector.java,v 1.1 2000/07/15 22:08:32 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.1 $ - * @author Philippe Le Hegaret - * @see Selector#SAC_DESCENDANT_SELECTOR - * @see Selector#SAC_CHILD_SELECTOR - */ -public interface DescendantSelector extends Selector { - - /** - * Returns the parent selector. - */ - public Selector getAncestorSelector(); - - /* - * Returns the simple selector. - */ - public SimpleSelector getSimpleSelector(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/DocumentHandler.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/DocumentHandler.java deleted file mode 100644 index 45899d5743..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/DocumentHandler.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: DocumentHandler.java,v 1.4 2000/02/16 21:29:35 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * This is the main interface that most CSS applications implement: if the - * application needs to be informed of basic parsing events, it implements this - * interface and registers an instance with the CSS parser using the - * setCSSHandler method. - * - * @version $Revision: 1.4 $ - * @author Philippe Le Hegaret - */ -public interface DocumentHandler { - - /** - * Receive notification of the beginning of a style sheet. - * - * The CSS parser will invoke this method only once, before any other - * methods in this interface. - * - * @param uri The URI of the style sheet. @@TODO can be NULL ! (inline style sheet) - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void startDocument(InputSource source) - throws CSSException; - - /** - * Receive notification of the end of a document. - * - * The CSS parser will invoke this method only once, and it will be the - * last method invoked during the parse. The parser shall not invoke this - * method until it has either abandoned parsing (because of an - * unrecoverable error) or reached the end of input. - * - * @param uri The URI of the style sheet. - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void endDocument(InputSource source) throws CSSException; - - /** - * Receive notification of a comment. - * If the comment appears in a declaration (e.g. color: /* comment * / blue;), - * the parser notifies the comment before the declaration. - * - * @param text The comment. - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void comment(String text) throws CSSException; - - /** - * Receive notification of an unknown rule t-rule not supported by this - * parser. - * - * @param at-rule The complete ignored at-rule. - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void ignorableAtRule(String atRule) throws CSSException; - - /** - * Receive notification of an unknown rule t-rule not supported by this - * parser. - * - * @param prefix null if this is the default namespace - * @param uri The URI for this namespace. - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void namespaceDeclaration(String prefix, String uri) - throws CSSException; - - /** - * Receive notification of a import statement in the style sheet. - * - * @param uri The URI of the imported style sheet. - * @param media The intended destination media for style information. - * @param defaultNamepaceURI The default namespace URI for the imported - * style sheet. - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void importStyle(String uri, SACMediaList media, - String defaultNamespaceURI) - throws CSSException; - - /** - * Receive notification of the beginning of a media statement. - * - * The Parser will invoke this method at the beginning of every media - * statement in the style sheet. there will be a corresponding endMedia() - * event for every startElement() event. - * - * @param media The intended destination media for style information. - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void startMedia(SACMediaList media) throws CSSException; - - /** - * Receive notification of the end of a media statement. - * - * @param media The intended destination media for style information. - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void endMedia(SACMediaList media) throws CSSException; - - /** - * Receive notification of the beginning of a page statement. - * - * The Parser will invoke this method at the beginning of every page - * statement in the style sheet. there will be a corresponding endPage() - * event for every startPage() event. - * - * @param name the name of the page (if any, null otherwise) - * @param pseudo_page the pseudo page (if any, null otherwise) - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void startPage(String name, String pseudo_page) throws CSSException; - - /** - * Receive notification of the end of a media statement. - * - * @param media The intended destination medium for style information. - * @param pseudo_page the pseudo page (if any, null otherwise) - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void endPage(String name, String pseudo_page) throws CSSException; - - /** - * Receive notification of the beginning of a font face statement. - * - * The Parser will invoke this method at the beginning of every font face - * statement in the style sheet. there will be a corresponding endFontFace() - * event for every startFontFace() event. - * - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void startFontFace() throws CSSException; - - /** - * Receive notification of the end of a font face statement. - * - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void endFontFace() throws CSSException; - - /** - * Receive notification of the beginning of a rule statement. - * - * @param selectors All intended selectors for all declarations. - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void startSelector(SelectorList selectors) throws CSSException; - - /** - * Receive notification of the end of a rule statement. - * - * @param selectors All intended selectors for all declarations. - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void endSelector(SelectorList selectors) throws CSSException; - - /** - * Receive notification of a declaration. - * - * @param name the name of the property. - * @param value the value of the property. All whitespace are stripped. - * @param important is this property important ? - * @exception CSSException Any CSS exception, possibly wrapping another - * exception. - */ - public void property(String name, LexicalUnit value, boolean important) - throws CSSException; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ElementSelector.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ElementSelector.java deleted file mode 100644 index 20d60032ef..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ElementSelector.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium, - * (Massachusetts Institute of Technology, Institut National de - * Recherche en Informatique et en Automatique, Keio University). All - * Rights Reserved. This program is distributed under the W3C's Software - * Intellectual Property License. This program is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. - * See W3C License http://www.w3.org/Consortium/Legal/ for more details. - * - * $Id: ElementSelector.java,v 1.6 2000/02/14 15:54:12 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.6 $ - * @author Philippe Le Hegaret - * @see Selector#SAC_ELEMENT_NODE_SELECTOR - */ -public interface ElementSelector extends SimpleSelector { - - /** - * Returns the - * namespace - * URI of this element selector. - *

      NULL if this element selector can match any namespace.

      - */ - public String getNamespaceURI(); - - /** - * Returns the - * local part - * of the - * qualified - * name of this element. - *

      NULL if this element selector can match any element.

      - * - */ - public String getLocalName(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ErrorHandler.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ErrorHandler.java deleted file mode 100644 index 393a132aee..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ErrorHandler.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * The original version of this interface comes from SAX : - * http://www.megginson.com/SAX/ - * - * $Id: ErrorHandler.java,v 1.2 1999/09/26 10:10:34 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * Basic interface for CSS error handlers. - * - *

      If a CSS application needs to implement customized error - * handling, it must implement this interface and then register an - * instance with the CSS parser using the parser's setErrorHandler - * method. The parser will then report all errors and warnings - * through this interface.

      - * - *

      The parser shall use this interface instead of throwing an - * exception: it is up to the application whether to throw an - * exception for different types of errors and warnings. Note, - * however, that there is no requirement that the parser continue to - * provide useful information after a call to fatalError (in other - * words, a CSS driver class could catch an exception and report a - * fatalError).

      - * - *

      The HandlerBase class provides a default implementation of this - * interface, ignoring warnings and recoverable errors and throwing a - * SAXParseException for fatal errors. An application may extend - * that class rather than implementing the complete interface - * itself.

      - * - * @version $Revision: 1.2 $ - * @author Philippe Le Hegaret - */ -public interface ErrorHandler { - - - /** - * Receive notification of a warning. - * - *

      CSS parsers will use this method to report conditions that - * are not errors or fatal errors as defined by the XML 1.0 - * recommendation. The default behaviour is to take no action.

      - * - *

      The CSS parser must continue to provide normal parsing events - * after invoking this method: it should still be possible for the - * application to process the document through to the end.

      - * - * @param exception The warning information encapsulated in a - * CSS parse exception. - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @see CSSParseException - */ - public void warning(CSSParseException exception) throws CSSException; - - /** - * Receive notification of a recoverable error. - * - *

      This corresponds to the definition of "error" in section 1.2 - * of the W3C XML 1.0 Recommendation. For example, a validating - * parser would use this callback to report the violation of a - * validity constraint. The default behaviour is to take no - * action.

      - * - *

      The CSS parser must continue to provide normal parsing events - * after invoking this method: it should still be possible for the - * application to process the document through to the end. If the - * application cannot do so, then the parser should report a fatal - * error even if the XML 1.0 recommendation does not require it to - * do so.

      - * - * @param exception The error information encapsulated in a - * CSS parse exception. - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @see CSSParseException - */ - public void error(CSSParseException exception) throws CSSException; - - /** - * Receive notification of a non-recoverable error. - * - *

      This corresponds to the definition of "fatal error" in - * section 1.2 of the W3C XML 1.0 Recommendation. For example, a - * parser would use this callback to report the violation of a - * well-formedness constraint.

      - * - *

      The application must assume that the document is unusable - * after the parser has invoked this method, and should continue - * (if at all) only for the sake of collecting addition error - * messages: in fact, CSS parsers are free to stop reporting any - * other events once this method has been invoked.

      - * - * @param exception The error information encapsulated in a - * CSS parse exception. - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @see CSSParseException - */ - public void fatalError(CSSParseException exception) throws CSSException; - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/InputSource.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/InputSource.java deleted file mode 100644 index c622845d52..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/InputSource.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * The original version of this interface comes from SAX : - * http://www.megginson.com/SAX/ - * - * $Id: InputSource.java,v 1.2 1999/09/26 10:09:48 plehegar Exp $ - */ -package org.w3c.css.sac; - -import java.io.InputStream; -import java.io.Reader; - -/** - * A single input source for a CSS source. - * - *

      This class allows a CSS application to encapsulate information about an - * input source in a single object, which may include a URI, a byte stream - * (possibly with a specified encoding), and/or a character stream.

      - * - *

      The CSS parser will use the InputSource object to determine how - * to read CSS input. If there is a character stream available, the - * parser will read that stream directly; if not, the parser will use - * a byte stream, if available; if neither a character stream nor a - * byte stream is available, the parser will attempt to open a URI - * connection to the resource identified by the URI.

      - * - *

      An InputSource object belongs to the application: the CSS parser - * shall never modify it in any way (it may modify a copy if - * necessary).

      - * - * @version $Revision: 1.2 $ - * @author Philippe Le Hegaret - */ -public class InputSource { - - private String uri; - private InputStream byteStream; - private String encoding; - private Reader characterStream; - private String title; - private String media; - - /** - * Zero-argument default constructor. - * - * @see #setURI - * @see #setByteStream - * @see #setCharacterStream - * @see #setEncoding - */ - public InputSource() { - } - - /** - * Create a new input source with a URI. - * - *

      The URI must be full resolved.

      - * - * @param uri The URI. - * @see #setURI - * @see #setByteStream - * @see #setEncoding - * @see #setCharacterStream - */ - public InputSource(String uri) { - setURI(uri); - } - - /** - * Create a new input source with a character stream. - * - *

      Application writers may use setURI() to provide a base - * for resolving relative URIs, and setPublicId to include a - * public identifier.

      - * - *

      The character stream shall not include a byte order mark.

      - * - * @see #setURI - * @see #setByteStream - * @see #setCharacterStream - */ - public InputSource(Reader characterStream) { - setCharacterStream(characterStream); - } - - /** - * Set the URI for this input source. - * - *

      The URI is optional if there is a byte stream or a character stream, - * but it is still useful to provide one, since the application can use it - * to resolve relative URIs and can include it in error messages and - * warnings (the parser will attempt to open a connection to the URI only - * if there is no byte stream or character stream specified).

      - * - *

      If the application knows the character encoding of the - * object pointed to by the URI, it can register - * the encoding using the setEncoding method.

      - * - *

      The URI must be fully resolved.

      - * - * @param uri The URI as a string. - * @see #setEncoding - * @see #getURI - * @see Locator#getURI - * @see CSSParseException#getURI - */ - public void setURI(String uri) { - this.uri = uri; - } - - /** - * Get the URI for this input source. - * - *

      The getEncoding method will return the character encoding - * of the object pointed to, or null if unknown.

      - * - *

      The URI will be fully resolved.

      - * - * @return The URI. - * @see #setURI - * @see #getEncoding - */ - public String getURI() { - return uri; - } - - /** - * Set the byte stream for this input source. - * - *

      The SAX parser will ignore this if there is also a character - * stream specified, but it will use a byte stream in preference - * to opening a URI connection itself.

      - * - *

      If the application knows the character encoding of the - * byte stream, it should set it with the setEncoding method.

      - * - * @param byteStream A byte stream containing an CSS document or - * other entity. - * @see #setEncoding - * @see #getByteStream - * @see #getEncoding - */ - public void setByteStream(InputStream byteStream) { - this.byteStream = byteStream; - } - - /** - * Get the byte stream for this input source. - * - *

      The getEncoding method will return the character - * encoding for this byte stream, or null if unknown.

      - * - * @return The byte stream, or null if none was supplied. - * @see #getEncoding - * @see #setByteStream - */ - public InputStream getByteStream() { - return byteStream; - } - - /** - * Set the character encoding, if known. - * - *

      The encoding must be a string acceptable for an - * CHARSET encoding declaration (see section 4.4 of the CSS - * recommendation Level 2).

      - * - *

      This method has no effect when the application provides a - * character stream.

      - * - * @param encoding A string describing the character encoding. - * @see #setURI - * @see #setByteStream - * @see #getEncoding - */ - public void setEncoding(String encoding) { - this.encoding = encoding; - } - - /** - * Get the character encoding for a byte stream or URI. - * - * @return The encoding, or null if none was supplied. - * @see #setByteStream - * @see #getURI - * @see #getByteStream - */ - public String getEncoding() { - return encoding; - } - - /** - * Set the character stream for this input source. - * - *

      If there is a character stream specified, the SAX parser - * will ignore any byte stream and will not attempt to open - * a URI connection to the URI.

      - * - * @param characterStream The character stream containing the - * CSS document or other entity. - * @see #getCharacterStream - */ - public void setCharacterStream(Reader characterStream) { - this.characterStream = characterStream; - } - - /** - * Get the character stream for this input source. - * - * @return The character stream, or null if none was supplied. - * @see #setCharacterStream - */ - public Reader getCharacterStream() { - return characterStream; - } - - /** - * Set the title for this input source. - * @param title The advisory title. See the title attribute definition - * for the LINK - * element in HTML 4.0, and the title pseudo-attribute for the XML - * style sheet processing instruction. - */ - public void setTitle(String title) { - this.title = title; - } - - /** - * Returns the title for this input source. - */ - public String getTitle() { - return title; - } - - /** - * Set the media for this input source. - * @param media A comma separated list with all media. - */ - public void setMedia(String media) { - this.media = media; - } - - /** - * Returns the media associated to the input source or null - * if media are currently unknown. - * @return the media associated to this input source. - */ - public String getMedia() { - if (media == null) { - return "all"; - } - return media; - } -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/LangCondition.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/LangCondition.java deleted file mode 100644 index d793864f38..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/LangCondition.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: LangCondition.java,v 1.1 1999/09/26 09:54:37 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.1 $ - * @author Philippe Le Hegaret - * @see Condition#SAC_LANG_CONDITION - */ -public interface LangCondition extends Condition { - /** - * Returns the language - */ - public String getLang(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/LexicalUnit.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/LexicalUnit.java deleted file mode 100644 index d2edc717ad..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/LexicalUnit.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: LexicalUnit.java,v 1.9 2000/03/08 20:55:33 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * This is a lexical unit for CSS values. - *

      Remarks: Not all the following lexical units are supported (or - * will be supported) by CSS. - *

      All examples are CSS2 compliant. - * - * @version $Revision: 1.9 $ - * @author Philippe Le Hegaret - */ -public interface LexicalUnit { - - /** - * , - */ - public static final short SAC_OPERATOR_COMMA = 0; - /** - * + - */ - public static final short SAC_OPERATOR_PLUS = 1; - /** - * - - */ - public static final short SAC_OPERATOR_MINUS = 2; - /** - * * - */ - public static final short SAC_OPERATOR_MULTIPLY = 3; - /** - * / - */ - public static final short SAC_OPERATOR_SLASH = 4; - /** - * % - */ - public static final short SAC_OPERATOR_MOD = 5; - /** - * ^ - */ - public static final short SAC_OPERATOR_EXP = 6; - /** - * < - */ - public static final short SAC_OPERATOR_LT = 7; - /** - * > - */ - public static final short SAC_OPERATOR_GT = 8; - /** - * <= - */ - public static final short SAC_OPERATOR_LE = 9; - /** - * >= - */ - public static final short SAC_OPERATOR_GE = 10; - /** - * ~ - */ - public static final short SAC_OPERATOR_TILDE = 11; - - /** - * identifier inherit. - */ - public static final short SAC_INHERIT = 12; - /** - * Integers. - * @see #getIntegerValue - */ - public static final short SAC_INTEGER = 13; - /** - * reals. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_REAL = 14; - /** - * Relative lengthem. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_EM = 15; - /** - * Relative lengthex. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_EX = 16; - /** - * Relative length px. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_PIXEL = 17; - /** - * Absolute length in. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_INCH = 18; - /** - * Absolute length cm. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_CENTIMETER = 19; - /** - * Absolute length mm. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_MILLIMETER = 20; - /** - * Absolute length pt. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_POINT = 21; - /** - * Absolute length pc. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_PICA = 22; - /** - * Percentage. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_PERCENTAGE = 23; - /** - * URI: uri(...). - * @see #getStringValue - */ - public static final short SAC_URI = 24; - /** - * function counter. - * @see #getFunctionName - * @see #getParameters - */ - public static final short SAC_COUNTER_FUNCTION = 25; - /** - * function counters. - * @see #getFunctionName - * @see #getParameters - */ - public static final short SAC_COUNTERS_FUNCTION = 26; - /** - * RGB Colors. - * rgb(0, 0, 0) and #000 - * @see #getFunctionName - * @see #getParameters - */ - public static final short SAC_RGBCOLOR = 27; - /** - * Angle deg. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_DEGREE = 28; - /** - * Angle grad. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_GRADIAN = 29; - /** - * Angle rad. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_RADIAN = 30; - /** - * Time ms. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_MILLISECOND = 31; - /** - * Time s. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_SECOND = 32; - /** - * Frequency Hz. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_HERTZ = 33; - /** - * Frequency kHz. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_KILOHERTZ = 34; - - /** - * any identifier except inherit. - * @see #getStringValue - */ - public static final short SAC_IDENT = 35; - /** - * A string. - * @see #getStringValue - */ - public static final short SAC_STRING_VALUE = 36; - /** - * Attribute: attr(...). - * @see #getStringValue - */ - public static final short SAC_ATTR = 37; - /** - * function rect. - * @see #getFunctionName - * @see #getParameters - */ - public static final short SAC_RECT_FUNCTION = 38; - /** - * A unicode range. @@TO BE DEFINED - */ - public static final short SAC_UNICODERANGE = 39; - - /** - * sub expressions - * (a) (a + b) (normal/none) - * @see #getSubValues - */ - public static final short SAC_SUB_EXPRESSION = 40; - - /** - * unknown function. - * @see #getFunctionName - * @see #getParameters - */ - public static final short SAC_FUNCTION = 41; - /** - * unknown dimension. - * @see #getFloatValue - * @see #getDimensionUnitText - */ - public static final short SAC_DIMENSION = 42; - - /** - * An integer indicating the type of LexicalUnit. - */ - public short getLexicalUnitType(); - - /** - * Returns the next value or null if any. - */ - public LexicalUnit getNextLexicalUnit(); - - /** - * Returns the previous value or null if any. - */ - public LexicalUnit getPreviousLexicalUnit(); - - /** - * Returns the integer value. - * @see #SAC_INTEGER - */ - public int getIntegerValue(); - - - /** - * Returns the float value. - *

      If the type of LexicalUnit is one of SAC_DEGREE, - * SAC_GRADIAN, SAC_RADIAN, SAC_MILLISECOND, SAC_SECOND, SAC_HERTZ - * or SAC_KILOHERTZ, the value can never be negative.

      - * - * @see #SAC_REAL - * @see #SAC_DIMENSION - * @see #SAC_EM - * @see #SAC_EX - * @see #SAC_PIXEL - * @see #SAC_INCH - * @see #SAC_CENTIMETER - * @see #SAC_MILLIMETER - * @see #SAC_POINT - * @see #SAC_PICA - * @see #SAC_PERCENTAGE - * @see #SAC_DEGREE - * @see #SAC_GRADIAN - * @see #SAC_RADIAN - * @see #SAC_MILLISECOND - * @see #SAC_SECOND - * @see #SAC_HERTZ - * @see #SAC_KILOHERTZ - */ - public float getFloatValue(); - - /** - * Returns the string representation of the unit. - *

      if this lexical unit represents a float, the dimension is an empty - * string.

      - * @see #SAC_REAL - * @see #SAC_DIMENSION - * @see #SAC_EM - * @see #SAC_EX - * @see #SAC_PIXEL - * @see #SAC_INCH - * @see #SAC_CENTIMETER - * @see #SAC_MILLIMETER - * @see #SAC_POINT - * @see #SAC_PICA - * @see #SAC_PERCENTAGE - * @see #SAC_DEGREE - * @see #SAC_GRADIAN - * @see #SAC_RADIAN - * @see #SAC_MILLISECOND - * @see #SAC_SECOND - * @see #SAC_HERTZ - * @see #SAC_KILOHERTZ - */ - public String getDimensionUnitText(); - - /** - * Returns the name of the function. - * @see #SAC_COUNTER_FUNCTION - * @see #SAC_COUNTERS_FUNCTION - * @see #SAC_RECT_FUNCTION - * @see #SAC_FUNCTION - * @see #SAC_RGBCOLOR - */ - public String getFunctionName(); - - /** - * The function parameters including operators (like the comma). - * #000 is converted to rgb(0, 0, 0) - * can return null if SAC_FUNCTION. - * @see #SAC_COUNTER_FUNCTION - * @see #SAC_COUNTERS_FUNCTION - * @see #SAC_RECT_FUNCTION - * @see #SAC_FUNCTION - * @see #SAC_RGBCOLOR - */ - public LexicalUnit getParameters(); - - /** - * Returns the string value. - *

      If the type is SAC_URI, the return value doesn't contain - * uri(....) or quotes. - *

      If the type is SAC_ATTR, the return value doesn't contain - * attr(....). - * - * @see #SAC_URI - * @see #SAC_ATTR - * @see #SAC_IDENT - * @see #SAC_STRING_VALUE - * @see #SAC_UNICODERANGE @@TO BE DEFINED - */ - public String getStringValue(); - - /** - * Returns a list of values inside the sub expression. - * @see #SAC_SUB_EXPRESSION - */ - public LexicalUnit getSubValues(); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Locator.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Locator.java deleted file mode 100644 index 0395f09009..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Locator.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * The original version of this interface comes from SAX : - * http://www.megginson.com/SAX/ - * - * $Id: Locator.java,v 1.1 1999/09/26 09:58:46 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * Interface for associating a CSS event with a document location. - * - *

      If a SAX parser provides location information to the SAX - * application, it does so by implementing this interface and then - * passing an instance to the application using the document - * handler's setDocumentLocator method. The application can use the - * object to obtain the location of any other document handler event - * in the CSS source document.

      - * - *

      Note that the results returned by the object will be valid only - * during the scope of each document handler method: the application - * will receive unpredictable results if it attempts to use the - * locator at any other time.

      - * - *

      CSS parsers are not required to supply a locator, but they are - * very strong encouraged to do so. If the parser supplies a - * locator, it must do so before reporting any other document events. - * If no locator has been set by the time the application receives - * the startDocument event, the application should assume that a - * locator is not available.

      - * - * @version $Revision: 1.1 $ - * @author Philippe Le Hegaret - */ -public interface Locator { - - /** - * Return the URI for the current document event. - * - *

      The parser must resolve the URI fully before passing it to the - * application.

      - * - * @return A string containing the URI, or null - * if none is available. - */ - public String getURI(); - - /** - * Return the line number where the current document event ends. - * Note that this is the line position of the first character - * after the text associated with the document event. - * @return The line number, or -1 if none is available. - * @see #getColumnNumber - */ - public int getLineNumber(); - - /** - * Return the column number where the current document event ends. - * Note that this is the column number of the first - * character after the text associated with the document - * event. The first column in a line is position 1. - * @return The column number, or -1 if none is available. - * @see #getLineNumber - */ - public int getColumnNumber(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/NegativeCondition.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/NegativeCondition.java deleted file mode 100644 index a6165d964e..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/NegativeCondition.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: NegativeCondition.java,v 1.2 1999/09/26 10:15:58 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.2 $ - * @author Philippe Le Hegaret - * @see Condition#SAC_NEGATIVE_CONDITION - */ -public interface NegativeCondition extends Condition { - - /** - * Returns the condition. - */ - public Condition getCondition(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/NegativeSelector.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/NegativeSelector.java deleted file mode 100644 index 0aef283bd2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/NegativeSelector.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: NegativeSelector.java,v 1.2 1999/09/25 12:32:36 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.2 $ - * @author Philippe Le Hegaret - * @see Selector#SAC_NEGATIVE_SELECTOR - */ -public interface NegativeSelector extends SimpleSelector { - - /** - * Returns the simple selector. - */ - public SimpleSelector getSimpleSelector(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Parser.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Parser.java deleted file mode 100644 index 194d8e4707..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Parser.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * The original version of this interface comes from SAX : - * http://www.megginson.com/SAX/ - * - * $Id: Parser.java,v 1.13 2000/10/27 20:45:21 plehegar Exp $ - */ -package org.w3c.css.sac; - -import java.io.IOException; -import java.util.Locale; - -/** - * Basic interface for CSS (Simple API for CSS) parsers. - * - *

      All CSS parsers must implement this basic interface: it allows - * applications to register handlers for different types of events - * and to initiate a parse from a URI, or a character stream.

      - * - *

      All CSS parsers must also implement a zero-argument constructor - * (though other constructors are also allowed).

      - * - *

      CSS parsers are reusable but not re-entrant: the application - * may reuse a parser object (possibly with a different input source) - * once the first parse has completed successfully, but it may not - * invoke the parse() methods recursively within a parse.

      - * - * @version $Revision: 1.13 $ - * @author Philippe Le Hegaret - * @see DocumentHandler - * @see ErrorHandler - * @see InputSource - */ -public interface Parser { - - /** - * Allow an application to request a locale for errors and warnings. - * - *

      CSS parsers are not required to provide localisation for errors - * and warnings; if they cannot support the requested locale, - * however, they must throw a CSS exception. Applications may - * not request a locale change in the middle of a parse.

      - * - * @param locale A Java Locale object. - * @exception CSSException Throws an exception - * (using the previous or default locale) if the - * requested locale is not supported. - * @see CSSException - * @see CSSParseException - */ - public void setLocale(Locale locale) throws CSSException; - - /** - * Allow an application to register a document event handler. - * - *

      If the application does not register a document handler, all - * document events reported by the CSS parser will be silently - * ignored (this is the default behaviour implemented by - * HandlerBase).

      - * - *

      Applications may register a new or different handler in the - * middle of a parse, and the CSS parser must begin using the new - * handler immediately.

      - * - * @param handler The document handler. - * @see DocumentHandler - */ - public void setDocumentHandler(DocumentHandler handler); - - public void setSelectorFactory(SelectorFactory selectorFactory); - public void setConditionFactory(ConditionFactory conditionFactory); - - /** - * Allow an application to register an error event handler. - * - *

      If the application does not register an error event handler, - * all error events reported by the CSS parser will be silently - * ignored, except for fatalError, which will throw a CSSException - * (this is the default behaviour implemented by HandlerBase).

      - * - *

      Applications may register a new or different handler in the - * middle of a parse, and the CSS parser must begin using the new - * handler immediately.

      - * - * @param handler The error handler. - * @see ErrorHandler - * @see CSSException - */ - public void setErrorHandler(ErrorHandler handler); - - /** - * Parse a CSS document. - * - *

      The application can use this method to instruct the CSS parser - * to begin parsing an CSS document from any valid input - * source (a character stream, a byte stream, or a URI).

      - * - *

      Applications may not invoke this method while a parse is in - * progress (they should create a new Parser instead for each - * additional CSS document). Once a parse is complete, an - * application may reuse the same Parser object, possibly with a - * different input source.

      - * - * @param source The input source for the top-level of the - * CSS document. - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @exception java.io.IOException An IO exception from the parser, - * possibly from a byte stream or character stream - * supplied by the application. - * @see InputSource - * @see #parseStyleSheet(java.lang.String) - * @see #setDocumentHandler - * @see #setErrorHandler - */ - public void parseStyleSheet(InputSource source) - throws CSSException, IOException; - - - /** - * Parse a CSS document from a URI. - * - *

      This method is a shortcut for the common case of reading a document - * from a URI. It is the exact equivalent of the following:

      - * - *
      -     * parse(new InputSource(uri));
      -     * 
      - * - *

      The URI must be fully resolved by the application before it is passed - * to the parser.

      - * - * @param uri The URI. - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @exception java.io.IOException An IO exception from the parser, - * possibly from a byte stream or character stream - * supplied by the application. - * @see #parseStyleSheet(InputSource) - */ - public void parseStyleSheet(String uri) throws CSSException, IOException; - - /** - * Parse a CSS style declaration (without '{' and '}'). - * - * @param styleValue The declaration. - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @exception java.io.IOException An IO exception from the parser, - * possibly from a byte stream or character stream - * supplied by the application. - */ - public void parseStyleDeclaration(InputSource source) - throws CSSException, IOException; - - - /** - * Parse a CSS rule. - * - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @exception java.io.IOException An IO exception from the parser, - * possibly from a byte stream or character stream - * supplied by the application. - */ - public void parseRule(InputSource source) throws CSSException, IOException; - - /** - * Returns a string about which CSS language is supported by this - * parser. For CSS Level 1, it returns "http://www.w3.org/TR/REC-CSS1", for - * CSS Level 2, it returns "http://www.w3.org/TR/REC-CSS2". Note that a - * "CSSx" parser can return lexical unit other than those allowed by CSS - * Level x but this usage is not recommended. - */ - public String getParserVersion(); - - /** - * Parse a comma separated list of selectors. - * - * - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @exception java.io.IOException An IO exception from the parser, - * possibly from a byte stream or character stream - * supplied by the application. - */ - public SelectorList parseSelectors(InputSource source) - throws CSSException, IOException; - - - /** - * Parse a CSS property value. - * - * - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @exception java.io.IOException An IO exception from the parser, - * possibly from a byte stream or character stream - * supplied by the application. - */ - public LexicalUnit parsePropertyValue(InputSource source) - throws CSSException, IOException; - - - /** - * Parse a CSS priority value (e.g. "!important"). - * - * - * @exception CSSException Any CSS exception, possibly - * wrapping another exception. - * @exception java.io.IOException An IO exception from the parser, - * possibly from a byte stream or character stream - * supplied by the application. - */ - public boolean parsePriority(InputSource source) - throws CSSException, IOException; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/PositionalCondition.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/PositionalCondition.java deleted file mode 100644 index ed5eb8c7e2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/PositionalCondition.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: PositionalCondition.java,v 1.4 2000/02/14 15:54:12 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.4 $ - * @author Philippe Le Hegaret - * @see Condition#SAC_POSITIONAL_CONDITION - */ -public interface PositionalCondition extends Condition { - - /** - * Returns the position in the tree. - *

      A negative value means from the end of the child node list. - *

      The child node list begins at 0. - */ - public int getPosition(); - - /** - * true if the child node list only shows nodes of the same - * type of the selector (only elements, only PIS, ...) - */ - public boolean getTypeNode(); - - /** - * true if the node should have the same node type (for - * element, same namespaceURI and same localName). - */ - public boolean getType(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ProcessingInstructionSelector.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ProcessingInstructionSelector.java deleted file mode 100644 index 214685b842..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/ProcessingInstructionSelector.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: ProcessingInstructionSelector.java,v 1.2 1999/09/25 12:32:36 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * This simple matches a - * processing instruction. - * - * @version $Revision: 1.2 $ - * @author Philippe Le Hegaret - * @see Selector#SAC_PROCESSING_INSTRUCTION_NODE_SELECTOR - */ -public interface ProcessingInstructionSelector extends SimpleSelector { - - /** - * Returns the target - * of the processing instruction. - */ - public String getTarget(); - - /** - * Returns the character data. - */ - public String getData(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SACMediaList.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SACMediaList.java deleted file mode 100644 index 822d2d3d8d..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SACMediaList.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: SACMediaList.java,v 1.1 2000/02/16 21:27:32 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.1 $ - * @author Philippe Le Hegaret - */ -public interface SACMediaList { - - /** - * Returns the length of this media list - */ - public int getLength(); - - /** - * Returns the medium at the specified index, or null if this - * is not a valid index. - */ - public String item(int index); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Selector.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Selector.java deleted file mode 100644 index fd54fdefb0..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/Selector.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium, - * (Massachusetts Institute of Technology, Institut National de - * Recherche en Informatique et en Automatique, Keio University). All - * Rights Reserved. This program is distributed under the W3C's Software - * Intellectual Property License. This program is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. - * See W3C License http://www.w3.org/Consortium/Legal/ for more details. - * - * $Id: Selector.java,v 1.12 2000/07/15 22:08:45 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * This interface defines a selector. - *

      Remarks: Not all the following selectors are supported (or will be - * supported) by CSS. - *

      All examples are CSS2 compliant. - * - * @version $Revision: 1.12 $ - * @author Philippe Le Hegaret - */ -public interface Selector { - - /* simple selectors */ - - /** - * This is a conditional selector. - * example: - *

      -     *   simple[role="private"]
      -     *   .part1
      -     *   H1#myId
      -     *   P:lang(fr).p1
      -     * 
      - * - * @see ConditionalSelector - */ - public static final short SAC_CONDITIONAL_SELECTOR = 0; - - /** - * This selector matches any node. - * @see SimpleSelector - */ - public static final short SAC_ANY_NODE_SELECTOR = 1; - - /** - * This selector matches the root node. - * @see SimpleSelector - */ - public static final short SAC_ROOT_NODE_SELECTOR = 2; - - /** - * This selector matches only node that are different from a specified one. - * @see NegativeSelector - */ - public static final short SAC_NEGATIVE_SELECTOR = 3; - - /** - * This selector matches only element node. - * example: - *
      -     *   H1
      -     *   animate
      -     * 
      - * @see ElementSelector - */ - public static final short SAC_ELEMENT_NODE_SELECTOR = 4; - - /** - * This selector matches only text node. - * @see CharacterDataSelector - */ - public static final short SAC_TEXT_NODE_SELECTOR = 5; - - /** - * This selector matches only cdata node. - * @see CharacterDataSelector - */ - public static final short SAC_CDATA_SECTION_NODE_SELECTOR = 6; - - /** - * This selector matches only processing instruction node. - * @see ProcessingInstructionSelector - */ - public static final short SAC_PROCESSING_INSTRUCTION_NODE_SELECTOR = 7; - - /** - * This selector matches only comment node. - * @see CharacterDataSelector - */ - public static final short SAC_COMMENT_NODE_SELECTOR = 8; - /** - * This selector matches the 'first line' pseudo element. - * example: - *
      -     *   :first-line
      -     * 
      - * @see ElementSelector - */ - public static final short SAC_PSEUDO_ELEMENT_SELECTOR = 9; - - /* combinator selectors */ - - /** - * This selector matches an arbitrary descendant of some ancestor element. - * example: - *
      -     *   E F
      -     * 
      - * @see DescendantSelector - */ - public static final short SAC_DESCENDANT_SELECTOR = 10; - - /** - * This selector matches a childhood relationship between two elements. - * example: - *
      -     *   E > F
      -     * 
      - * @see DescendantSelector - */ - public static final short SAC_CHILD_SELECTOR = 11; - /** - * This selector matches two selectors who shared the same parent in the - * document tree and the element represented by the first sequence - * immediately precedes the element represented by the second one. - * example: - *
      -     *   E + F
      -     * 
      - * @see SiblingSelector - */ - public static final short SAC_DIRECT_ADJACENT_SELECTOR = 12; - - /** - * An integer indicating the type of Selector - */ - public short getSelectorType(); - -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SelectorFactory.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SelectorFactory.java deleted file mode 100644 index cace5bb1a3..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SelectorFactory.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium, - * (Massachusetts Institute of Technology, Institut National de - * Recherche en Informatique et en Automatique, Keio University). All - * Rights Reserved. This program is distributed under the W3C's Software - * Intellectual Property License. This program is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. - * See W3C License http://www.w3.org/Consortium/Legal/ for more details. - * - * $Id: SelectorFactory.java,v 1.3 2000/07/27 21:19:21 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.3 $ - * @author Philippe Le Hegaret - * @see org.w3c.css.sac.Selector - */ -public interface SelectorFactory { - - /** - * Creates a conditional selector. - * - * @param selector a selector. - * @param condition a condition - * @return the conditional selector. - * @exception CSSException If this selector is not supported. - */ - ConditionalSelector createConditionalSelector(SimpleSelector selector, - Condition condition) - throws CSSException; - - /** - * Creates an any node selector. - * - * @return the any node selector. - * @exception CSSException If this selector is not supported. - */ - SimpleSelector createAnyNodeSelector() throws CSSException; - - /** - * Creates an root node selector. - * - * @return the root node selector. - * @exception CSSException If this selector is not supported. - */ - SimpleSelector createRootNodeSelector() throws CSSException; - - /** - * Creates an negative selector. - * - * @param selector a selector. - * @return the negative selector. - * @exception CSSException If this selector is not supported. - */ - NegativeSelector createNegativeSelector(SimpleSelector selector) - throws CSSException; - - /** - * Creates an element selector. - * - * @param namespaceURI the namespace - * URI of the element selector. - * @param tagName the local - * part of the element name. NULL if this element - * selector can match any element.

      - * @return the element selector - * @exception CSSException If this selector is not supported. - */ - ElementSelector createElementSelector(String namespaceURI, String tagName) - throws CSSException; - - /** - * Creates a text node selector. - * - * @param data the data - * @return the text node selector - * @exception CSSException If this selector is not supported. - */ - CharacterDataSelector createTextNodeSelector(String data) - throws CSSException; - - /** - * Creates a cdata section node selector. - * - * @param data the data - * @return the cdata section node selector - * @exception CSSException If this selector is not supported. - */ - CharacterDataSelector createCDataSectionSelector(String data) - throws CSSException; - - /** - * Creates a processing instruction node selector. - * - * @param target the target - * @param data the data - * @return the processing instruction node selector - * @exception CSSException If this selector is not supported. - */ - ProcessingInstructionSelector - createProcessingInstructionSelector(String target, - String data) - throws CSSException; - - /** - * Creates a comment node selector. - * - * @param data the data - * @return the comment node selector - * @exception CSSException If this selector is not supported. - */ - CharacterDataSelector createCommentSelector(String data) - throws CSSException; - - /** - * Creates a pseudo element selector. - * - * @param pseudoName the pseudo element name. NULL if this - * element selector can match any pseudo element.

      - * @return the element selector - * @exception CSSException If this selector is not supported. - */ - ElementSelector createPseudoElementSelector(String namespaceURI, - String pseudoName) - throws CSSException; - - /** - * Creates a descendant selector. - * - * @param parent the parent selector - * @param descendant the descendant selector - * @return the combinator selector. - * @exception CSSException If this selector is not supported. - */ - DescendantSelector createDescendantSelector(Selector parent, - SimpleSelector descendant) - throws CSSException; - - /** - * Creates a child selector. - * - * @param parent the parent selector - * @param child the child selector - * @return the combinator selector. - * @exception CSSException If this selector is not supported. - */ - DescendantSelector createChildSelector(Selector parent, - SimpleSelector child) - throws CSSException; - - /** - * Creates a sibling selector. - * - * @param nodeType the type of nodes in the siblings list. - * @param child the child selector - * @param adjacent the direct adjacent selector - * @return the sibling selector with nodeType - equals to org.w3c.dom.Node.ELEMENT_NODE - * @exception CSSException If this selector is not supported. - */ - SiblingSelector createDirectAdjacentSelector(short nodeType, - Selector child, - SimpleSelector directAdjacent) - throws CSSException; -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SelectorList.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SelectorList.java deleted file mode 100644 index 4028e4615c..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SelectorList.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: SelectorList.java,v 1.1 1999/09/26 10:06:45 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * The SelectorList interface provides the abstraction of an ordered collection - * of selectors, without defining or constraining how this collection is - * implemented. - * - * @version $Revision: 1.1 $ - * @author Philippe Le Hegaret - */ -public interface SelectorList { - - /** - * Returns the length of this selector list - */ - public int getLength(); - - /** - * Returns the selector at the specified index, or null if this - * is not a valid index. - */ - public Selector item(int index); -} - diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SiblingSelector.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SiblingSelector.java deleted file mode 100644 index 075b711359..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SiblingSelector.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: SiblingSelector.java,v 1.3 2000/07/27 21:19:21 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * @version $Revision: 1.3 $ - * @author Philippe Le Hegaret - * @see Selector#SAC_DIRECT_ADJACENT_SELECTOR - */ -public interface SiblingSelector extends Selector { - - public static final short ANY_NODE = 201; - - /** - * The node type to considered in the siblings list. - * All DOM node types are supported. In order to support the "any" node - * type, the code ANY_NODE is added to the DOM node types. - */ - public short getNodeType(); - - /** - * Returns the first selector. - */ - public Selector getSelector(); - - /* - * Returns the second selector. - */ - public SimpleSelector getSiblingSelector(); -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SimpleSelector.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SimpleSelector.java deleted file mode 100644 index 6860b7a75a..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/SimpleSelector.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (c) COPYRIGHT 1999 World Wide Web Consortium - * (Massachusetts Institute of Technology, Institut National de Recherche - * en Informatique et en Automatique, Keio University). - * All Rights Reserved. http://www.w3.org/Consortium/Legal/ - * - * $Id: SimpleSelector.java,v 1.2 1999/09/30 16:54:22 plehegar Exp $ - */ -package org.w3c.css.sac; - -/** - * This interface is only for constraints on selectors. - * - *

      A ConditionalSelector can only accept a simple selector or a - * negative selector.

      - * - * @version $Revision: 1.2 $ - * @author Philippe Le Hegaret */ -public interface SimpleSelector extends Selector { - // empty -} diff --git a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/helpers/ParserFactory.java b/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/helpers/ParserFactory.java deleted file mode 100644 index 0847eee5b2..0000000000 --- a/mucommander-viewer-pdf/src/main/java/org/w3c/css/sac/helpers/ParserFactory.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 1999 World Wide Web Consortium, - * (Massachusetts Institute of Technology, Institut National de - * Recherche en Informatique et en Automatique, Keio University). All - * Rights Reserved. This program is distributed under the W3C's Software - * Intellectual Property License. This program is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. - * See W3C License http://www.w3.org/Consortium/Legal/ for more details. - * - * $Id: ParserFactory.java,v 1.1 2000/02/14 15:54:49 plehegar Exp $ - */ -package org.w3c.css.sac.helpers; - -import org.w3c.css.sac.Parser; - -/** - * @version $Revision: 1.1 $ - * @author Philippe Le Hegaret - */ -public class ParserFactory { - - /** - * Create a parser with given selectors factory and conditions factory. - */ - public Parser makeParser() - throws ClassNotFoundException, - IllegalAccessException, - InstantiationException, - NullPointerException, - ClassCastException { - String className = System.getProperty("org.w3c.css.sac.parser"); - if (className == null) { - throw new NullPointerException("No value for sac.parser property"); - } else { - return (Parser)(Class.forName(className).newInstance()); - } - } -} diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_a_24.png deleted file mode 100644 index d83f78b9b0..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_a_32.png deleted file mode 100644 index 11f07a1efd..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_i_24.png deleted file mode 100644 index ad8145fbed..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_i_32.png deleted file mode 100644 index fcacc85540..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_r_24.png deleted file mode 100644 index a33bcfc35e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_r_32.png deleted file mode 100644 index b1d65225a4..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/actual_size_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/app_icon4_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/app_icon4_24.png deleted file mode 100644 index c57fa7fad7..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/app_icon4_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_a_24.png deleted file mode 100644 index d42e09f9a1..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_a_32.png deleted file mode 100644 index f9f5869c61..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_i_24.png deleted file mode 100644 index be09c48887..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_i_32.png deleted file mode 100644 index 7449235f0b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_r_24.png deleted file mode 100644 index 7ba5a3a86f..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_r_32.png deleted file mode 100644 index 98399bff6e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_s_24.png deleted file mode 100644 index e1f47ca7f6..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/arrow_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/back_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/back_a_32.png deleted file mode 100644 index ce4fcb5f7d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/back_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/back_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/back_i_32.png deleted file mode 100644 index b7741ef442..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/back_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/back_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/back_r_32.png deleted file mode 100644 index d996f61ed0..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/back_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_a_24.png deleted file mode 100644 index c80903482b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_a_32.png deleted file mode 100644 index 268fa068e6..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_i_24.png deleted file mode 100644 index b43d8a7d87..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_i_32.png deleted file mode 100644 index 09238f7658..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_r_24.png deleted file mode 100644 index 992b95b885..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_r_32.png deleted file mode 100644 index 3ebce38f71..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_s_24.png deleted file mode 100644 index 7211fb1174..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/circle_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/first_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/first_a_32.png deleted file mode 100644 index fd7fe7dc80..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/first_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/first_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/first_i_32.png deleted file mode 100644 index 31169d4234..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/first_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/first_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/first_r_32.png deleted file mode 100644 index 1fe824a1c1..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/first_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_a_24.png deleted file mode 100644 index ef09b8dcf0..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_a_32.png deleted file mode 100644 index 10a93823cd..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_i_24.png deleted file mode 100644 index 1bb186fb9d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_i_32.png deleted file mode 100644 index c916a9c730..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_r_24.png deleted file mode 100644 index 81ad8b0562..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_r_32.png deleted file mode 100644 index e119739b0d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_page_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_a_24.png deleted file mode 100644 index 594a51b4f8..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_a_32.png deleted file mode 100644 index 743ad91e42..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_i_24.png deleted file mode 100644 index 6ca13daa2e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_i_32.png deleted file mode 100644 index e7517054a6..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_n_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_n_32.png deleted file mode 100644 index e7517054a6..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_n_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_r_24.png deleted file mode 100644 index faf7e59694..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_r_32.png deleted file mode 100644 index 0c95641a15..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_width_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_a_24.png deleted file mode 100644 index 764f2ae10a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_a_32.png deleted file mode 100644 index 65f60a2fd3..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_i_24.png deleted file mode 100644 index a45096705a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_i_32.png deleted file mode 100644 index 4af6ba5c3a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_r_24.png deleted file mode 100644 index 4dee8d56ef..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_r_32.png deleted file mode 100644 index 76d65fcfc0..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fit_window_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/font-engine_d.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/font-engine_d.png deleted file mode 100644 index 2fe366a718..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/font-engine_d.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/font-engine_n.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/font-engine_n.png deleted file mode 100644 index 51258e2016..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/font-engine_n.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_a_24.png deleted file mode 100644 index 8a4147118c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_a_32.png deleted file mode 100644 index 4ce9aa3a37..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_i_24.png deleted file mode 100644 index a28deaf22c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_i_32.png deleted file mode 100644 index af2bb785d6..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_r_24.png deleted file mode 100644 index a5a00e1fa4..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_r_32.png deleted file mode 100644 index 7f60b12849..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/form_highlight_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/forward_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/forward_a_32.png deleted file mode 100644 index 492d6dd91d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/forward_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/forward_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/forward_i_32.png deleted file mode 100644 index f749ede941..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/forward_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/forward_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/forward_r_32.png deleted file mode 100644 index 6157149792..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/forward_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_a_24.png deleted file mode 100644 index 90a8100764..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_a_32.png deleted file mode 100644 index a830b1c698..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_i_24.png deleted file mode 100644 index 5a70f7c651..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_i_32.png deleted file mode 100644 index 0c708bd2f2..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_r_24.png deleted file mode 100644 index 1cf588bac8..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_r_32.png deleted file mode 100644 index 151a4e3673..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_s_24.png deleted file mode 100644 index 2fadf4aad8..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_s_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_s_32.png deleted file mode 100644 index 0c708bd2f2..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/freetext_annot_s_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fullscreen_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fullscreen_a_32.png deleted file mode 100644 index 00fc4a3a90..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fullscreen_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fullscreen_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fullscreen_i_32.png deleted file mode 100644 index 8e8d4488a3..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fullscreen_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fullscreen_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fullscreen_r_32.png deleted file mode 100644 index 1e5f270831..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/fullscreen_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/hand_closed.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/hand_closed.gif deleted file mode 100644 index 7271fa28fb..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/hand_closed.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/hand_open.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/hand_open.gif deleted file mode 100644 index d543b5eeea..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/hand_open.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_a_24.png deleted file mode 100644 index 399e3f1b0e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_a_32.png deleted file mode 100644 index b1b3d126e1..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_c_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_c_a_32.png deleted file mode 100644 index 9b9bd99a2d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_c_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_c_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_c_i_32.png deleted file mode 100644 index e80ebb0568..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_c_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_c_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_c_r_32.png deleted file mode 100644 index f25388ab21..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_c_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_i_24.png deleted file mode 100644 index a676a1855e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_i_32.png deleted file mode 100644 index 5a579abe53..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_r_24.png deleted file mode 100644 index bbd7fbf444..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_r_32.png deleted file mode 100644 index 63123cd08c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_s_24.png deleted file mode 100644 index 84217b9a87..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/highlight_annot_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_back_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_back_a_32.png deleted file mode 100644 index f0cd93f771..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_back_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_back_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_back_i_32.png deleted file mode 100644 index ddbfaa0b74..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_back_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_back_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_back_r_32.png deleted file mode 100644 index 6ab71b17db..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_back_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_forward_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_forward_a_32.png deleted file mode 100644 index 1ca12f7c5a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_forward_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_forward_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_forward_i_32.png deleted file mode 100644 index 87c0321bd2..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_forward_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_forward_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_forward_r_32.png deleted file mode 100644 index d7f14e5c43..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/history_forward_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icelogo.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icelogo.png deleted file mode 100644 index 3db6a9bbf9..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icelogo.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icepdf-app-icon-32x32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icepdf-app-icon-32x32.png deleted file mode 100644 index d745bb2b0a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icepdf-app-icon-32x32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icepdf-app-icon-64x64.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icepdf-app-icon-64x64.png deleted file mode 100644 index dc72ed4ab3..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icepdf-app-icon-64x64.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icepdf-splash.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icepdf-splash.png deleted file mode 100644 index 06fc3e1fab..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/icepdf-splash.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_a_24.png deleted file mode 100644 index 6998e44d98..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_a_32.png deleted file mode 100644 index 14bb7aee23..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_i_24.png deleted file mode 100644 index 3f778d1d3f..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_i_32.png deleted file mode 100644 index 93b1fe5345..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_r_24.png deleted file mode 100644 index 62bd3fecec..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_r_32.png deleted file mode 100644 index 5e3912dee7..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_s_24.png deleted file mode 100644 index 5e484be49a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/ink_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/last_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/last_a_32.png deleted file mode 100644 index 8abe1c8837..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/last_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/last_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/last_i_32.png deleted file mode 100644 index 84bad0a08e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/last_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/last_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/last_r_32.png deleted file mode 100644 index ca53cf1556..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/last_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_a_24.png deleted file mode 100644 index 5724df7bc0..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_a_32.png deleted file mode 100644 index 7fdac64af7..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_i_24.png deleted file mode 100644 index f867bb8dc2..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_i_32.png deleted file mode 100644 index a12054afc3..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_r_24.png deleted file mode 100644 index 4497703d58..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_r_32.png deleted file mode 100644 index 1f7b517925..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_s_24.png deleted file mode 100644 index 36a8a99d08..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/line_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_a_24.png deleted file mode 100644 index 3d5cffdcd8..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_a_32.png deleted file mode 100644 index 3586473a69..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_i_24.png deleted file mode 100644 index ab17148fe9..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_i_32.png deleted file mode 100644 index 9750e08a42..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_r_24.png deleted file mode 100644 index dede5ad45d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_r_32.png deleted file mode 100644 index f3c9f4bf24..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_s_24.png deleted file mode 100644 index e7057ea6a2..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_annot_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_d.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_d.gif deleted file mode 100644 index 67ad9478da..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_d.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_n.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_n.gif deleted file mode 100644 index 4d3da060c0..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_n.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_r.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_r.gif deleted file mode 100644 index e025d4aded..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/link_r.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/menu_spacer.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/menu_spacer.gif deleted file mode 100644 index 0e6644237b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/menu_spacer.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/minus.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/minus.gif deleted file mode 100644 index 3cd53b36cd..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/minus.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_a_24.png deleted file mode 100644 index cd26e50746..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_a_32.png deleted file mode 100644 index bd05e6dc4b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_i_24.png deleted file mode 100644 index 9bfdc5e1e5..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_i_32.png deleted file mode 100644 index 82fea7b73e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_r_24.png deleted file mode 100644 index a50a89c2be..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_r_32.png deleted file mode 100644 index 80f6fd595b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/open_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page.gif deleted file mode 100644 index 46c7eeb884..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_down_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_down_a_24.png deleted file mode 100644 index a4a492588a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_down_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_down_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_down_i_24.png deleted file mode 100644 index b8d9fa0d75..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_down_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_down_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_down_r_24.png deleted file mode 100644 index 64375c00ba..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_down_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_first_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_first_a_24.png deleted file mode 100644 index 6760ab1986..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_first_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_first_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_first_i_24.png deleted file mode 100644 index af07fbdfbc..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_first_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_first_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_first_r_24.png deleted file mode 100644 index b8a6a337d7..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_first_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_last_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_last_a_24.png deleted file mode 100644 index 75d366927f..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_last_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_last_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_last_i_24.png deleted file mode 100644 index 4399d7865e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_last_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_last_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_last_r_24.png deleted file mode 100644 index e10ae95925..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_last_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_up_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_up_a_24.png deleted file mode 100644 index 391749e0d7..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_up_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_up_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_up_i_24.png deleted file mode 100644 index 80654694b4..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_up_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_up_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_up_r_24.png deleted file mode 100644 index 69d4781edd..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/page_up_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/pan_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/pan_a_32.png deleted file mode 100644 index 80c5cbbc6b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/pan_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/pan_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/pan_i_32.png deleted file mode 100644 index ee740f4aeb..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/pan_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/pan_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/pan_r_32.png deleted file mode 100644 index fac1986308..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/pan_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/plus.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/plus.gif deleted file mode 100644 index 366be26543..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/plus.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_a_24.png deleted file mode 100644 index 5a5ec0b469..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_a_32.png deleted file mode 100644 index c2aae0c6b0..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_i_24.png deleted file mode 100644 index 420d25a6e2..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_i_32.png deleted file mode 100644 index 829d7de42a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_r_24.png deleted file mode 100644 index 0cd1d22212..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_r_32.png deleted file mode 100644 index 3377c46072..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/print_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_a_24.png deleted file mode 100644 index e5a9e1bebf..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_a_32.png deleted file mode 100644 index 21f318076b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_i_24.png deleted file mode 100644 index 2ce3e6cf5c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_i_32.png deleted file mode 100644 index 1c00b95419..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_r_24.png deleted file mode 100644 index 900ed5f632..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_r_32.png deleted file mode 100644 index 904d182f92..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_left_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_a_24.png deleted file mode 100644 index 27ec62a757..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_a_32.png deleted file mode 100644 index b3097276dd..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_i_24.png deleted file mode 100644 index 6da2842b7c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_i_32.png deleted file mode 100644 index a3317ded21..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_r_24.png deleted file mode 100644 index 55efeffa19..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_r_32.png deleted file mode 100644 index 389a31c4f8..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/rotate_right_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_a_24.png deleted file mode 100644 index 9b8606d2f9..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_a_32.png deleted file mode 100644 index a036b6a84f..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_i_24.png deleted file mode 100644 index d53b1b1096..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_i_32.png deleted file mode 100644 index e1e011c511..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_r_24.png deleted file mode 100644 index bb7eab276c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_r_32.png deleted file mode 100644 index 6771a7d91c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/save_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/search_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/search_a_32.png deleted file mode 100644 index b740c054ab..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/search_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/search_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/search_i_32.png deleted file mode 100644 index 6b2f7a3e6a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/search_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/search_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/search_r_32.png deleted file mode 100644 index 55a4097235..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/search_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/select_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/select_a_32.png deleted file mode 100644 index ae066975b4..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/select_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/select_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/select_i_32.png deleted file mode 100644 index b3df07e95c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/select_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/select_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/select_r_32.png deleted file mode 100644 index 77b0ec68c8..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/select_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/selection_text_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/selection_text_a_32.png deleted file mode 100644 index 117e831c85..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/selection_text_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/selection_text_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/selection_text_i_32.png deleted file mode 100644 index 9054bbcf9c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/selection_text_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/selection_text_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/selection_text_r_32.png deleted file mode 100644 index e108773203..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/selection_text_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_caution.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_caution.png deleted file mode 100644 index a2c36794d5..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_caution.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_caution_lg.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_caution_lg.png deleted file mode 100644 index 85feb512c2..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_caution_lg.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_invalid.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_invalid.png deleted file mode 100644 index 18b292eaf6..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_invalid.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_invalid_lg.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_invalid_lg.png deleted file mode 100644 index 795e138f96..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_invalid_lg.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_valid.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_valid.png deleted file mode 100644 index e8ff3cbe87..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_valid.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_valid_lg.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_valid_lg.png deleted file mode 100644 index 305ca54e31..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/signature_valid_lg.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_a_24.png deleted file mode 100644 index bd41b1d75a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_a_32.png deleted file mode 100644 index 191335ba14..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_a_24.png deleted file mode 100644 index cf6da9ae9c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_a_32.png deleted file mode 100644 index 6d9a43854d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_i_24.png deleted file mode 100644 index 5a07e22baf..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_i_32.png deleted file mode 100644 index 60ad89a79e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_r_24.png deleted file mode 100644 index 20a38319f7..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_r_32.png deleted file mode 100644 index c1ed812254..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_column_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_i_24.png deleted file mode 100644 index cd5e31c314..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_i_32.png deleted file mode 100644 index 57166e720d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_r_24.png deleted file mode 100644 index 7d1ee8f5bc..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_r_32.png deleted file mode 100644 index 1f6b5b1f79..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/single_page_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_a_24.png deleted file mode 100644 index 3188ee58c4..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_a_32.png deleted file mode 100644 index cbc7df966c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_i_24.png deleted file mode 100644 index 0d224123fc..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_i_32.png deleted file mode 100644 index 3e92329fd5..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_r_24.png deleted file mode 100644 index e08a1b7dd2..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_r_32.png deleted file mode 100644 index 0dfa220fff..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/square_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_a_24.png deleted file mode 100644 index 6a889acc38..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_i_24.png deleted file mode 100644 index 4891da4cd2..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_i_32.png deleted file mode 100644 index aecb4e0c0d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_r_24.png deleted file mode 100644 index 6301e138e1..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_r_32.png deleted file mode 100644 index 0291b14436..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_s_24.png deleted file mode 100644 index b573d8798b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_s_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_s_32.png deleted file mode 100644 index ec8ecd9afb..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/strikeout_s_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_a_24.png deleted file mode 100644 index 49d6bd24f0..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_a_32.png deleted file mode 100644 index 5b6136b4f1..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_c_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_c_a_32.png deleted file mode 100644 index 5ff14ae874..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_c_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_c_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_c_i_32.png deleted file mode 100644 index 1341c58bba..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_c_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_c_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_c_r_32.png deleted file mode 100644 index c1f7671896..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_c_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_i_24.png deleted file mode 100644 index 9d9c1cb681..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_i_32.png deleted file mode 100644 index f53acca159..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_r_24.png deleted file mode 100644 index 58ad6fe86a..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_r_32.png deleted file mode 100644 index fd2ef31cb6..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_s_24.png deleted file mode 100644 index a9825a057b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/text_annot_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_32.png deleted file mode 100644 index 246c163810..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_a_24.png deleted file mode 100644 index 9d52a1702d..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_a_32.png deleted file mode 100644 index 8895bf34e4..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_a_24.png deleted file mode 100644 index e915b0ad80..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_a_32.png deleted file mode 100644 index ed54c5cb47..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_i_24.png deleted file mode 100644 index d3a0c42f8e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_i_32.png deleted file mode 100644 index 9e3ba5dffe..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_r_24.png deleted file mode 100644 index 876e4e9756..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_r_32.png deleted file mode 100644 index a9e08d15a5..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_column_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_i_24.png deleted file mode 100644 index 5da0587ec0..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_i_32.png deleted file mode 100644 index cb4bd21bed..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_r_24.png deleted file mode 100644 index 8090f3759e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_r_32.png deleted file mode 100644 index 246c163810..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/two_page_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_a_24.png deleted file mode 100644 index 8555c09851..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_a_32.png deleted file mode 100644 index efcdea4715..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_i_24.png deleted file mode 100644 index 5094e4625f..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_i_32.png deleted file mode 100644 index 9e63dfba28..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_r_24.png deleted file mode 100644 index bc1c5b4519..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_r_32.png deleted file mode 100644 index 2672f88304..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_s_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_s_24.png deleted file mode 100644 index a3237b64b3..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/underline_s_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/utility_pane_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/utility_pane_a_32.png deleted file mode 100644 index 6ea7812853..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/utility_pane_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/utility_pane_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/utility_pane_i_32.png deleted file mode 100644 index 4ebf326125..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/utility_pane_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/utility_pane_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/utility_pane_r_32.png deleted file mode 100644 index 5feef166d1..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/utility_pane_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom.gif deleted file mode 100644 index 19a159f1a9..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_dynamic_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_dynamic_a_32.png deleted file mode 100644 index ac3a096e99..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_dynamic_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_dynamic_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_dynamic_i_32.png deleted file mode 100644 index 0294511a5e..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_dynamic_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_dynamic_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_dynamic_r_32.png deleted file mode 100644 index f98118b1f6..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_dynamic_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in.gif deleted file mode 100644 index 0a37c10047..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_a_24.png deleted file mode 100644 index 659382fa07..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_a_32.png deleted file mode 100644 index 2f3c0e139b..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_i_24.png deleted file mode 100644 index 67685afd59..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_i_32.png deleted file mode 100644 index f69ee6ae58..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_r_24.png deleted file mode 100644 index 65712d2de6..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_r_32.png deleted file mode 100644 index 299c575e71..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_in_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_marquis_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_marquis_a_32.png deleted file mode 100644 index 85a4dd4821..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_marquis_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_marquis_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_marquis_i_32.png deleted file mode 100644 index b25dfc577f..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_marquis_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_marquis_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_marquis_r_32.png deleted file mode 100644 index e24d5fb582..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_marquis_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out.gif b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out.gif deleted file mode 100644 index 821f2ac4f9..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out.gif and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_a_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_a_24.png deleted file mode 100644 index 15d8b5a2d8..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_a_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_a_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_a_32.png deleted file mode 100644 index 0390cd5801..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_a_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_i_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_i_24.png deleted file mode 100644 index 87ec23d473..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_i_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_i_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_i_32.png deleted file mode 100644 index 50604045b7..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_i_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_r_24.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_r_24.png deleted file mode 100644 index a927068f0c..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_r_24.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_r_32.png b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_r_32.png deleted file mode 100644 index 30a7ad26d3..0000000000 Binary files a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/images/zoom_out_r_32.png and /dev/null differ diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle.properties deleted file mode 100644 index 370b8e9f3f..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle.properties +++ /dev/null @@ -1,839 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# -## Window toolbar Title -viewer.window.title.default=ICEpdf Viewer -viewer.window.title.open.default=ICEpdf Viewer - [{0}] -#status bar -viewer.statusbar.currentPage=Page {0} / {1} -viewer.common.number.one=1 -viewer.common.number.two=2 -viewer.common.number.three=3 -viewer.common.number.four=4 -viewer.common.number.five=5 -viewer.common.number.six=6 -viewer.common.number.seven=7 -viewer.common.number.eight=8 -viewer.common.number.nine=9 -viewer.common.number.ten=10 -viewer.common.number.eleven=11 -viewer.common.number.twelve=12 -viewer.common.number.thirteen=13 -viewer.common.number.fourteen=14 -viewer.common.number.fifteen=15 -viewer.common.number.sixteen=16 -viewer.common.number.seventeen=17 -viewer.common.number.eighteen=18 -viewer.common.number.nineteen=19 -viewer.common.number.twenty=20 -viewer.common.number.twentyOne=21 -viewer.common.number.twentyTwo=22 -viewer.common.number.twentyThree=23 -viewer.common.number.twentyFour=24 -viewer.common.number.twentyFive=25 -viewer.common.number.twentySix=26 -viewer.common.number.twentySeven=27 -viewer.common.number.thirtySix=36 -viewer.common.number.fortyEight=48 -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label=Hide Toolbar -viewer.toolbar.showToolBar.label=Show Toolbar -viewer.toolbar.showUtilityPane.label=Show Utility Pane -viewer.toolbar.hideUtilityPane.label=Hide Utility Pane -viewer.toolbar.open.label= -viewer.toolbar.open.tooltip=Open Document -viewer.toolbar.saveAs.label=Save As -viewer.toolbar.saveAs.tooltip=Save As... -viewer.toolbar.print.label=Print -viewer.toolbar.print.tooltip=Print Document -viewer.toolbar.search.label=Search -viewer.toolbar.search.tooltip=Search Document -viewer.toolbar.utilityPane.label=Utility Pane -viewer.toolbar.utilityPane.tooltip=Show/Hide Utility Pane -viewer.toolbar.navigation.label= -viewer.toolbar.navigation.pages.tooltip=Number of Pages -viewer.toolbar.navigation.pages.firstPage.label= -viewer.toolbar.navigation.current.tooltip=Current Page Number -viewer.toolbar.navigation.current.firstPage.label= -viewer.toolbar.navigation.firstPage.label= -viewer.toolbar.navigation.firstPage.tooltip=First Page -viewer.toolbar.navigation.previousPage.label= -viewer.toolbar.navigation.previousPage.tooltip=Previous Page -viewer.toolbar.navigation.nextPage.label= -viewer.toolbar.navigation.nextPage.tooltip=Next Page -viewer.toolbar.navigation.lastPage.label= -viewer.toolbar.navigation.lastPage.tooltip=Last Page -viewer.toolbar.pageIndicator=of {0} -viewer.toolbar.zoom.label= -viewer.toolbar.zoom.tooltip=Zoom -viewer.toolbar.zoom.out.label= -viewer.toolbar.zoom.out.tooltip=Zoom Out -viewer.toolbar.zoom.in.label= -viewer.toolbar.zoom.in.tooltip=Zoom In -viewer.toolbar.pageFit.actualsize.label= -viewer.toolbar.pageFit.actualsize.tooltip=Actual Size -viewer.toolbar.pageFit.fitWindow.label= -viewer.toolbar.pageFit.fitWindow.tooltip=Fit in Window -viewer.toolbar.pageFit.fitWidth.label= -viewer.toolbar.pageFit.fitWidth.tooltip=Fit Width -viewer.toolbar.rotation.left.label= -viewer.toolbar.rotation.left.tooltip=Rotate Left -viewer.toolbar.rotation.right.label= -viewer.toolbar.rotation.right.tooltip=Rotate Right -viewer.toolbar.tool.pan.label= -viewer.toolbar.tool.pan.tooltip=Pan Tool -viewer.toolbar.tool.text.label= -viewer.toolbar.tool.text.tooltip=Text Select Tool -viewer.toolbar.tool.select.label= -viewer.toolbar.tool.select.tooltip=Select Tool -viewer.toolbar.tool.link.label= -viewer.toolbar.tool.link.tooltip=Link Annotation Tool -viewer.toolbar.tool.highlight.label=Highlight -viewer.toolbar.tool.highlight.tooltip=Highlight Annotation Tool -viewer.toolbar.tool.strikeOut.label=Strike Out -viewer.toolbar.tool.strikeOut.tooltip=Strike Out Annotation Tool -viewer.toolbar.tool.underline.label=Underline -viewer.toolbar.tool.underline.tooltip=Underline Annotation Tool -viewer.toolbar.tool.line.label=Line -viewer.toolbar.tool.line.tooltip=Line Annotation Tool -viewer.toolbar.tool.lineArrow.label=Line Arrow -viewer.toolbar.tool.lineArrow.tooltip=Line Arrow Annotation Tool -viewer.toolbar.tool.rectangle.label=Rectangle -viewer.toolbar.tool.rectangle.tooltip=Rectangle Annotation Tool -viewer.toolbar.tool.circle.label=Circle -viewer.toolbar.tool.circle.tooltip=Circle Annotation Tool -viewer.toolbar.tool.ink.label=Ink -viewer.toolbar.tool.ink.tooltip=Ink Annotation Tool -viewer.toolbar.tool.freeText.label=Free Text -viewer.toolbar.tool.freeText.tooltip=Free Text Annotation Tool -viewer.toolbar.tool.textAnno.label=Text Annotation -viewer.toolbar.tool.textAnno.tooltip=Text Annotation Tool -viewer.toolbar.tool.plolyLine.label=Poly Line -viewer.toolbar.tool.plolyLine.tooltip=Poly Line Annotation Tool -viewer.toolbar.tool.zoomIn.label= -viewer.toolbar.tool.zoomIn.tooltip=Zoom In Tool -viewer.toolbar.tool.zoomMarquis.label= -viewer.toolbar.tool.zoomMarquis.tooltip=Zoom Marquee Tool -viewer.toolbar.tool.zoomDynamic.label= -viewer.toolbar.tool.zoomDynamic.tooltip=Zoom Dynamic Tool -viewer.toolbar.tool.zoomOut.label= -viewer.toolbar.tool.zoomOut.tooltip=Zoom Out Tool -viewer.toolbar.pageFit.fontEngine.label= -viewer.toolbar.pageFit.fontEngine.tooltip=Enable/Disable Font Engine -viewer.toolbar.tool.forms.highlight.label=Highlight Forms -viewer.toolbar.tool.forms.highlight.tooltip=Show/Hide Form Highlighting -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label= -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip=Single Page View Non-Continuous -viewer.toolbar.pageView.nonContinuous.facingPage.label= -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip=Facing Page View Non-Continuous -viewer.toolbar.pageView.continuous.singlePage.label= -viewer.toolbar.pageView.continuous.singlePage.tooltip=Single Page View Continuous -viewer.toolbar.pageView.continuous.facingPage.label= -viewer.toolbar.pageView.continuous.facingPage.tooltip=Facing Page View Continuous -## File Menu and submenu items -viewer.menu.file.label=File -viewer.menu.file.mnemonic=F -viewer.menu.open.label=Open -viewer.menu.open.recentFiles.label=Open Recent Files -viewer.menu.open.file.label=File... -viewer.menu.open.URL.label=URL... -viewer.menu.close.label=Close -viewer.menu.saveAs.label=Save As... -viewer.menu.exportText.label=Export Text... -viewer.menu.documentProperties.label=Document Properties... -viewer.menu.documentPermission.label=Document Permissions... -viewer.menu.documentInformation.label=Document Information... -viewer.menu.documentFonts.label=Document Fonts... -viewer.menu.printSetup.label=Print Setup... -viewer.menu.print.label=Print... -viewer.menu.exit.label=Exit -## View Menu and submenu items -viewer.menu.edit.label=Edit -viewer.menu.edit.mnemonic=E -viewer.menu.edit.undo.label=Undo -viewer.menu.edit.redo.label=Redo -viewer.menu.edit.copy.label=Copy -viewer.menu.edit.delete.label=Delete -viewer.menu.edit.selectAll.label=Select All -viewer.menu.edit.deselectAll.label=Deselect All -viewer.menu.edit.preferences.label=Preferences -## View Menu and submenu items -viewer.menu.view.label=View -viewer.menu.view.mnemonic=V -viewer.menu.view.actualSize.label=Actual Size -viewer.menu.view.fitInWindow.label=Fit in Window -viewer.menu.view.fitWidth.label=Fit Width -viewer.menu.view.zoomIn.label=Zoom In -viewer.menu.view.zoomOut.label=Zoom Out -viewer.menu.view.rotateLeft.label=Rotate Left -viewer.menu.view.rotateRight.label=Rotate Right -viewer.menu.view.hideToolBar.label=Hide Toolbar -viewer.menu.view.showToolBar.label=Show Toolbar -viewer.menu.view.showUtilityPane.label=Show Utility Pane -viewer.menu.view.hideUtilityPane.label=Hide Utility Pane -## Document Menu and submenu items -viewer.menu.document.label=Document -viewer.menu.document.mnemonic=D -viewer.menu.document.firstPage.label=First Page -viewer.menu.document.previousPage.label=Previous Page -viewer.menu.document.nextPage.label=Next Page -viewer.menu.document.lastPage.label=Last Page -viewer.menu.document.search.label=Search... -viewer.menu.document.gotToPage.label=Go To Page... -## Window Menu and submenu items -viewer.menu.window.label=Window -viewer.menu.window.mnemonic=W -viewer.menu.window.minAll.label=Minimize All -viewer.menu.window.minAll.mnemonic=M -viewer.menu.window.frontAll.label=Bring All to Front -viewer.menu.window.frontAll.mnemonic=B -viewer.menu.window.1.label=1 -viewer.menu.window.1.mnemonic=1 -viewer.menu.window.2.label=2 -viewer.menu.window.2.mnemonic=2 -viewer.menu.window.3.label=3 -viewer.menu.window.3.mnemonic=3 -viewer.menu.window.4.label=4 -viewer.menu.window.4.mnemonic=4 -viewer.menu.window.5.label=5 -viewer.menu.window.5.mnemonic=5 -viewer.menu.window.6.label=6 -viewer.menu.window.6.mnemonic=6 -viewer.menu.window.7.label=7 -viewer.menu.window.7.mnemonic=7 -viewer.menu.window.8.label=8 -viewer.menu.window.8.mnemonic=8 -viewer.menu.window.9.label=9 -viewer.menu.window.9.mnemonic=9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label -## Help Menu and submenu items -viewer.menu.help.label=Help -viewer.menu.help.mnemonic=H -viewer.menu.help.about.label=About ICEpdf viewer... -## Document properties dialog. -viewer.dialog.documentProperties.tab.title=Document Properties -viewer.dialog.documentProperties.tab.description=Description -viewer.dialog.documentProperties.tab.security=Security -viewer.dialog.documentProperties.tab.fonts=Fonts -## Viewer preferences dialog -viewer.dialog.viewerPreferences.title=Viewer Preferences -viewer.dialog.viewerPreferences.section.general.title=General -viewer.dialog.viewerPreferences.section.annotations.title=Annotations -viewer.dialog.viewerPreferences.section.imaging.title=Imaging -viewer.dialog.viewerPreferences.section.fonts.title=Fonts -viewer.dialog.viewerPreferences.section.advanced.title=Advanced -## General preferences dialog -viewer.dialog.viewerPreferences.section.general.selection.border.label=Selection Settings -viewer.dialog.viewerPreferences.section.general.textSelectionColor.label=Text Selection Color: -viewer.dialog.viewerPreferences.section.general.searchHighlightColor.label=Search Highlight Color: -viewer.dialog.viewerPreferences.section.general.pageView.border.label=Page View Settings -viewer.dialog.viewerPreferences.section.general.pageView.shadowColor.label=Page Shadow Color: -viewer.dialog.viewerPreferences.section.general.pageView.paperColor.label=Paper Color: -viewer.dialog.viewerPreferences.section.general.pageView.borderColor.label=Border Color: -viewer.dialog.viewerPreferences.section.general.pageView.backgroundColor.label=Background Color: -## Viewer annotation preferences dialog -viewer.dialog.viewerPreferences.section.annotations.named.border.label=Color Labels -viewer.dialog.viewerPreferences.section.annotations.named.add.label=Add -viewer.dialog.viewerPreferences.section.annotations.named.edit.label=Update -viewer.dialog.viewerPreferences.section.annotations.named.remove.label=remove -viewer.dialog.viewerPreferences.section.annotations.recent.border.label=Recent Colors -viewer.dialog.viewerPreferences.section.annotations.recent.colors.label=Clear Recent Colors: -viewer.dialog.viewerPreferences.section.annotations.recent.colors.button=Clear -## Imaging preferences dialog -viewer.dialog.viewerPreferences.section.imaging.imageReference.border.label=Image References -viewer.dialog.viewerPreferences.section.imaging.imageReference.label=Image Reference Type: -viewer.dialog.viewerPreferences.section.imaging.imageReference.default.label=Default -viewer.dialog.viewerPreferences.section.imaging.imageReference.scaled.label=Scaled -viewer.dialog.viewerPreferences.section.imaging.imageReference.mipMap.label=MIP Map -viewer.dialog.viewerPreferences.section.imaging.imageReference.smothScaled.label=Smooth scaled -viewer.dialog.viewerPreferences.section.imaging.imageReference.blurred.label=Blurred -## fonts preferences dialog -viewer.dialog.viewerPreferences.section.fonts.fontCache.border.label=Font Cache -viewer.dialog.viewerPreferences.section.fonts.fontCache.label=Reset Font Cache: -viewer.dialog.viewerPreferences.section.fonts.fontCache.button.label=Reset -## Advanced preferences dialog. -viewer.dialog.viewerPreferences.section.advanced.commonThreadPool.border.label=Common Thread pool -viewer.dialog.viewerPreferences.section.advanced.commonThreadPool.label=Thread pool Size: -viewer.dialog.viewerPreferences.section.advanced.imageProxy.border.label=Image Proxy -viewer.dialog.viewerPreferences.section.advanced.imageProxy.label=Image Proxy Enable: -viewer.dialog.viewerPreferences.section.advanced.imageProxyEnabled.label=On -viewer.dialog.viewerPreferences.section.advanced.imageProxyDisabled.label=Off -viewer.dialog.viewerPreferences.section.advanced.imageProxyPoolSize.label=Thread pool size: -viewer.dialog.viewerPreferences.section.advanced.restartRequired.label=- Restart is required. -## Annotation colour selection popup menu. -viewer.popup.annotation.color.labels.label=Labels -viewer.popup.annotation.color.standard.label=Standard Colors -viewer.popup.annotation.color.lastused.label=Recent Colors -viewer.popup.annotation.color.morecolors.label=More Colors... -viewer.popup.annotation.color.preferences.label=Preferences... -## General error dialog -viewer.dialog.error.exception.title=ICEsoft ICEpdf - Exception -viewer.dialog.error.exception.msg=\ - There was an error executing your command do to the following exception\n\ - {0}. -## Open File Dialog -viewer.dialog.openFile.title=Open File -viewer.dialog.openFile.error.title=ICEsoft ICEpdf - Open File Error -viewer.dialog.openFile.error.msg=\ - ICEpdf could not open the specified file at {0}\n\ - The file may be corrupt or not a supported file type. -viewer.dialog.openDocument.pdfException.title=ICEsoft ICEpdf - PDF Exception -viewer.dialog.openDocument.pdfException.msg=\ - ICEpdf could not open the specified file {0} \n\ - The file may be corrupt or not a supported file type. -viewer.dialog.openDocument.pdfSecurityException.title=ICEsoft ICEpdf - PDF Security Exception -viewer.dialog.openDocument.pdfSecurityException.msg=\ - ICEpdf could not open the encrypted file at {0}\n\ - This may be the result of an invalid password or a missing JCE Security Provider.\n\n\ - Please refer to ICEpdf Developer's Guide for more information. -viewer.dialog.openDocument.exception.title=ICEsoft ICEpdf - Exception -viewer.dialog.openDocument.exception.msg=\ - ICEpdf could not open the specified file at {0}\n\ - The file may be corrupt or not a supported file type. -viewer.dialog.openURL.exception.title=ICEsoft ICEpdf - URL Exception -viewer.dialog.openURL.exception.msg=\ - ICEpdf could not open the specified file. {0} \n\ - at URL: {1} -viewer.dialog.openURL.downloading.msg=Downloading {0} -## General error dialog -viewer.dialog.information.copyAll.title=ICEsoft ICEpdf - Information -viewer.dialog.information.copyAll.msg=\ - The document has more than {0} pages, please use\n\ - "Export text..." to extract document text. -## Open URL Dialog -viewer.dialog.security.title=Document Security -viewer.dialog.security.msg=This PDF is protected -viewer.dialog.security.password.label=Password: -viewer.dialog.security.okButton.label=Ok -viewer.dialog.security.okButton.mnemonic=O -viewer.dialog.security.cancelButton.label=Cancel -viewer.dialog.security.cancelButton.mnemonic=C -## Open URL Dialog -viewer.dialog.openURL.title=Open URL -### Save a Copy Dialog -viewer.dialog.saveAs.title=Save As -viewer.dialog.saveAs.extensionError.title=ICEsoft ICEpdf - Save Error -viewer.dialog.saveAs.extensionError.msg=\ - ICEpdf could not save to {0} because it is not a supported file type. -viewer.dialog.saveAs.noExtensionError.title=ICEsoft ICEpdf - Save Error -viewer.dialog.saveAs.noExtensionError.msg=Please specify a file extension. -viewer.dialog.saveAs.noneUniqueName.title=ICEsoft ICEpdf - Save Error -viewer.dialog.saveAs.noneUniqueName.msg=\ - The file named {0} already exists. Please specify a unique name. -viewer.dialog.saveAs.noPermission.title=ICEpdf Viewer RI - Save Error -viewer.dialog.saveAs.noPermission.msg=You do not have permission or the credentials to save this document. -viewer.dialog.saveAs.noUpdates.title=ICEpdf Viewer RI -viewer.dialog.saveAs.noUpdates.msg=Document changes will not be saved, please upgrade to ICEpdf PRO. -viewer.dialog.saveOnClose.noUpdates.title=ICEpdf Viewer RI -viewer.dialog.saveOnClose.noUpdates.msg=Do you want to save changes to {0}? -## Export Text Dialog -viewer.dialog.exportText.title=Export Document Text -viewer.dialog.exportText.progress.msg=Extracting PDF Text -viewer.dialog.exportText.noExtensionError.title=ICEsoft ICEpdf - Save Error -viewer.dialog.exportText.noExtensionError.msg=Please specify a file extension. -# Text extraction output file -viewer.exportText.fileStamp.msg=ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg= -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg=\ - Completed {0} out of {1}. -viewer.exportText.fileStamp.progress.oneFile.msg={2} page -viewer.exportText.fileStamp.progress.moreFile.msg={2} pages -# Printing Progress bar -viewer.dialog.printing.status.progress.msg=Page {0} of {1} -viewer.dialog.printing.status.start.msg=Spooling Page(s) to Printer -## Document Permissions Dialog -viewer.dialog.documentPermissions.title=Document Permissions -viewer.dialog.documentPermissions.security.label=Document Security -viewer.dialog.documentPermissions.restrictions.label=Document Restriction Summary -viewer.dialog.documentPermissions.securityMethod.label=Security Method: -viewer.dialog.documentPermissions.userPassword.label=User Password: -viewer.dialog.documentPermissions.ownerPassword.label=Owner Password: -viewer.dialog.documentPermissions.printing.label=Printing: -viewer.dialog.documentPermissions.changing.label=Changing the Document: -viewer.dialog.documentPermissions.copyExtraction.label=Content Copying or Extraction: -viewer.dialog.documentPermissions.comments.label=Authoring Comments and Form Fields: -viewer.dialog.documentPermissions.formFillingIn.label=Form Field Fill-in or Signing: -viewer.dialog.documentPermissions.accessibility.label=Content Accessibility Enabled: -viewer.dialog.documentPermissions.assembly.label=Document Assembly: -viewer.dialog.documentPermissions.encryptionLevel.label=Encryption Level: -viewer.dialog.documentPermissions.securityLevel={0}-bit v{1} R {2} -viewer.dialog.documentPermissions.none=None -viewer.dialog.documentPermissions.no=No -viewer.dialog.documentPermissions.yes=Yes -viewer.dialog.documentPermissions.allowed=Allowed -viewer.dialog.documentPermissions.notAllowed=Not Allowed -viewer.dialog.documentPermissions.fullyAllowed=Fully Allowed -viewer.dialog.documentPermissions.standardSecurity=Adobe Acrobat Standard Security -viewer.dialog.documentPermissions.partial=Partial (Low Quality) -## Document Information Dialog -viewer.dialog.documentInformation.title=Document Information -viewer.dialog.documentInformation.description.label=Description -viewer.dialog.documentInformation.advanced.label=Advanced -viewer.dialog.documentInformation.border.title=Description -viewer.dialog.documentInformation.title.label=Title: -viewer.dialog.documentInformation.subject.label=Subject: -viewer.dialog.documentInformation.author.label=Author: -viewer.dialog.documentInformation.keywords.label=Keywords: -viewer.dialog.documentInformation.creator.label=Creator: -viewer.dialog.documentInformation.producer.label=Producer: -viewer.dialog.documentInformation.created.label=Created: -viewer.dialog.documentInformation.modified.label=Modified: -viewer.dialog.documentInformation.notAvailable=Not Available -## Go to Page Dialog -viewer.dialog.goToPage.title=Go to Page... -viewer.dialog.goToPage.description.label=Page Number -## About Dialog -viewer.dialog.about.title=About ICEpdf Viewer -viewer.dialog.about.pageNumber.label=\n\ -\n\ -Check the ICEpdf web site for the latest news:\n\ -http://www.icepdf.org/ \n\n -## Font Properties Dialog -viewer.dialog.fonts.title=Document Font Properties -viewer.dialog.fonts.border.label=Fonts used by this document -viewer.dialog.fonts.info.type.label=Type: {0} -viewer.dialog.fonts.info.encoding.label=Encoding: {0} -viewer.dialog.fonts.info.substitution.type.label=Actual Type: {0} -viewer.dialog.fonts.info.substitution.path.label=Path: {0} -viewer.dialog.fonts.searching.label=Collecting font data ({0}%). -viewer.dialog.fonts.resetCache.label=Reset Cache -viewer.dialog.fonts.resetCache.tip=Reset font properties cache file and rescan system for new fonts. -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title=Bookmarks -## Utility Pane Bookmarks Tab -viewer.utilityPane.attachments.tab.title=Attachments -viewer.utilityPane.attachments.column.fileName.title=Name -viewer.utilityPane.attachments.column.description.title=Description -viewer.utilityPane.attachments.column.modified.title=Modified -viewer.utilityPane.attachments.column.size.title=Size -viewer.utilityPane.attachments.column.compressedSize.title=Compressed size -viewer.utilityPane.attachments.menu.saveAs.label=Save As... -viewer.utilityPane.attachments.saveAs.replace.title=ICEsoft ICEpdf - Save Error -viewer.utilityPane.attachments.saveAs.replace.msg=\ - The file named {0} already exists. Do you want to replace It? -## Utility Pane Thumbnails -viewer.utilityPane.thumbs.tab.title=Thumbnails -## Layers Pane -viewer.utilityPane.layers.tab.title=Layers -## Signature Pane -viewer.utilityPane.signatures.tab.title=Signatures -viewer.utilityPane.signatures.tab.certTree.error.label=\ - Unsigned Signature Fields Signer certificate could not be validated {0} {1} -viewer.utilityPane.signatures.tab.certTree.rootSigned.label=Signed by {0} {1} -viewer.utilityPane.signatures.tab.certTree.rootValidating.label=Validating signature {0} {1} -viewer.utilityPane.signatures.tab.certTree.cert.invalid.label=Signature is invalid: -viewer.utilityPane.signatures.tab.certTree.cert.unknown.label=Signature is valid: -viewer.utilityPane.signatures.tab.certTree.cert.valid.label=Signature validity is unknown: -viewer.utilityPane.signatures.tab.certTree.doc.modified.label=\ - This version of the document is unaltered but subsequent changes have been made -viewer.utilityPane.signatures.tab.certTree.doc.unmodified.label=Document has not been modified since it was signed -viewer.utilityPane.signatures.tab.certTree.doc.major.label=Document has been altered or corrupted since it was signed -viewer.utilityPane.signatures.tab.certTree.signature.identity.unknown.label=\ - Signer's identity is unknown because it could not be found in your keystore -viewer.utilityPane.signatures.tab.certTree.signature.identity.unchecked.label=\ - Signature is valid, but revocation of the signer's identity could not be checked -viewer.utilityPane.signatures.tab.certTree.signature.identity.valid.label=Signer's identity is valid -viewer.utilityPane.signatures.tab.certTree.signature.time.local.label=Signing time is from the clock on this signer's computer -viewer.utilityPane.signatures.tab.certTree.signature.time.embedded.label=\ - Signature included an embedded timestamp but it could not be validated -viewer.utilityPane.signatures.tab.certTree.signature.details.label=Signature Details -viewer.utilityPane.signatures.tab.certTree.signature.details.reason.label=Reason: {0} -viewer.utilityPane.signatures.tab.certTree.signature.details.location.label=Location: {0} -viewer.utilityPane.signatures.tab.certTree.signature.details.full.label=Certificate Details... -viewer.utilityPane.signatures.tab.certTree.signature.lastChecked.label=Last Checked: {0} -viewer.utilityPane.signatures.tab.certTree.unsigned.label=Unsigned Signature Fields -## Signature certificate view dialog. -viewer.utilityPane.signatures.cert.dialog.title=Certificate Details -viewer.utilityPane.signatures.cert.dialog.closeButton.label=Close -viewer.utilityPane.signatures.cert.dialog.closeButton.mnemonic=C -viewer.utilityPane.signatures.cert.dialog.info.notAvailable.label=N/A -viewer.utilityPane.signatures.cert.dialog.info.unknownSubject.label=N/A Subject -viewer.utilityPane.signatures.cert.dialog.info.unknownIssuer.label=N/A Issuer -viewer.utilityPane.signatures.cert.dialog.info.certificateInfo.label={0} - {1} -viewer.utilityPane.signatures.cert.dialog.info.column1.label=Field -viewer.utilityPane.signatures.cert.dialog.info.column2.label=Value -viewer.utilityPane.signatures.cert.dialog.info.version.label=Version -viewer.utilityPane.signatures.cert.dialog.info.version.value=v{0} -viewer.utilityPane.signatures.cert.dialog.info.serialNumber.label=Serial Number -viewer.utilityPane.signatures.cert.dialog.info.serialNumber.value={0} -viewer.utilityPane.signatures.cert.dialog.info.signatureAlgorithm.label=Signature Algorithm -viewer.utilityPane.signatures.cert.dialog.info.signatureAlgorithm.value={0} -viewer.utilityPane.signatures.cert.dialog.info.issuer.label=Issuer -viewer.utilityPane.signatures.cert.dialog.info.issuer.value=\ - Organization: {0} \nOrganization Unit: {1} \nCommon Name: {2} \nLocal: {3} \nState: {4} \nCountry: {5} \nEmail: {6} -viewer.utilityPane.signatures.cert.dialog.info.validity.label=Validity -viewer.utilityPane.signatures.cert.dialog.info.validity.value=From: {0}\n To: {1} -viewer.utilityPane.signatures.cert.dialog.info.subject.label=Subject -viewer.utilityPane.signatures.cert.dialog.info.subject.value=\ - Organization: {0} \nOrganization Unit: {1} \nCommon Name: {2} \nLocal: {3} \nState: {4} \nCountry: {5} \nEmail: {6} -viewer.utilityPane.signatures.cert.dialog.info.signature.label=Signature -viewer.utilityPane.signatures.cert.dialog.info.md5.label=MD5 Fingerprint -viewer.utilityPane.signatures.cert.dialog.info.md5.value={0} -viewer.utilityPane.signatures.cert.dialog.info.sha1.label=SHA1 Fingerprint -viewer.utilityPane.signatures.cert.dialog.info.sha1.value={0} -viewer.utilityPane.signatures.verify.initializingMessage.label=Validating {0} of {1} Signatures -viewer.utilityPane.signatures.verify.completeMessage.label=Validating process complete -viewer.utilityPane.signatures.verify.validating.label=Validating signature... -## Annotation Tab -viewer.utilityPane.annotation.tab.title=Annotations -## Utility Pane Annotation Link Tab -viewer.utilityPane.annotation.link.appearance.title=Link Annotation -viewer.utilityPane.annotation.link.highlightType=Highlight Style: -viewer.utilityPane.annotation.link.none=None -viewer.utilityPane.annotation.link.invert=Invert` -viewer.utilityPane.annotation.link.outline=Outline -viewer.utilityPane.annotation.link.push=Push -## Utility Pane Annotation text markup Tab -viewer.utilityPane.annotation.textMarkup.appearance.title=Text Markup Annotation -viewer.utilityPane.annotation.textMarkup.highlightType=Type: -viewer.utilityPane.annotation.textMarkup.colorChooserTitle=Markup Color -viewer.utilityPane.annotation.textMarkup.colorLabel=Color: -viewer.utilityPane.annotation.textMarkup.transparencyLabel=Transparency: -## Utility Pane Annotation line Tab -viewer.utilityPane.annotation.line.appearance.title=Line Annotation -viewer.utilityPane.annotation.line.lineThickness=Line Thickness: -viewer.utilityPane.annotation.line.lineStyle=Line Style: -viewer.utilityPane.annotation.line.startStyle=Start: -viewer.utilityPane.annotation.line.endStyle=End: -viewer.utilityPane.annotation.line.colorChooserTitle=Line Color -viewer.utilityPane.annotation.line.colorInternalChooserTitle=Line Internal Color -viewer.utilityPane.annotation.line.colorLabel=Color: -viewer.utilityPane.annotation.line.colorInternalLabel=Fill Color: -viewer.utilityPane.annotation.line.end.none=None -viewer.utilityPane.annotation.line.end.openArrow=Open Arrow -viewer.utilityPane.annotation.line.end.closedArrow=Closed Arrow -viewer.utilityPane.annotation.line.end.diamond=Diamond -viewer.utilityPane.annotation.line.end.square=Square -viewer.utilityPane.annotation.line.end.circle=Circle -viewer.utilityPane.annotation.line.transparencyLabel=Transparency: -## Utility Pane Annotation square Tab -viewer.utilityPane.annotation.square.appearance.title=Square Annotation -viewer.utilityPane.annotation.square.lineThickness=Border Thickness: -viewer.utilityPane.annotation.square.lineStyle=Border Style: -viewer.utilityPane.annotation.square.colorBorderChooserTitle=Border Color -viewer.utilityPane.annotation.square.colorInteriorChooserTitle=Fill Color -viewer.utilityPane.annotation.square.borderTypeLabel=Border Type: -viewer.utilityPane.annotation.square.colorBorderLabel=Border Color: -viewer.utilityPane.annotation.square.colorInteriorLabel=Fill Color: -viewer.utilityPane.annotation.square.fillTypeLabel=Fill Type: -viewer.utilityPane.annotation.square.transparencyLabel=Transparency: -## Utility Pane Annotation free text Tab -viewer.utilityPane.annotation.freeText.appearance.title=FreeText Annotation -viewer.utilityPane.annotation.freeText.font.name=Font Name: -viewer.utilityPane.annotation.freeText.font.style=Font Style: -viewer.utilityPane.annotation.freeText.font.size=Font Size: -viewer.utilityPane.annotation.freeText.font.color=Font Color: -viewer.utilityPane.annotation.freeText.font.color.ChooserTitle=Font Color -viewer.utilityPane.annotation.freeText.border.thickness=Border Thickness: -viewer.utilityPane.annotation.freeText.border.type=Border Type: -viewer.utilityPane.annotation.freeText.border.style=Border Style: -viewer.utilityPane.annotation.freeText.border.color=Border Color: -viewer.utilityPane.annotation.freeText.border.color.ChooserTitle=Border Color -viewer.utilityPane.annotation.freeText.fill.type=Fill Type: -viewer.utilityPane.annotation.freeText.fill.color=Fill Color: -viewer.utilityPane.annotation.freeText.transparencyLabel=Transparency: -viewer.utilityPane.annotation.freeText.fill.color.ChooserTitle=Fill Color -viewer.utilityPane.annotation.freeText.font.dialog=Dialog -viewer.utilityPane.annotation.freeText.font.dialogInput=DialogInput -viewer.utilityPane.annotation.freeText.font.monospaced=Monospaced -viewer.utilityPane.annotation.freeText.font.serif=Serif -viewer.utilityPane.annotation.freeText.font.sanSerif=SansSerif -viewer.utilityPane.annotation.freeText.font.style.plain=Plain -viewer.utilityPane.annotation.freeText.font.style.italic=Italic -viewer.utilityPane.annotation.freeText.font.style.bold=Bold -viewer.utilityPane.annotation.freeText.font.name.helvetica=Helvetica -viewer.utilityPane.annotation.freeText.font.name.helveticaOblique=Helvetica-Oblique -viewer.utilityPane.annotation.freeText.font.name.helveticaBold=Helvetica-Bold -viewer.utilityPane.annotation.freeText.font.name.HelveticaBoldOblique=Helvetica-BoldOblique -viewer.utilityPane.annotation.freeText.font.name.timesItalic=Times-Italic -viewer.utilityPane.annotation.freeText.font.name.timesBold=Times-Bold -viewer.utilityPane.annotation.freeText.font.name.timesBoldItalic=Times-BoldItalic -viewer.utilityPane.annotation.freeText.font.name.timesRoman=Times-Roman -viewer.utilityPane.annotation.freeText.font.name.courier=Courier -viewer.utilityPane.annotation.freeText.font.name.courierOblique=Courier-Oblique -viewer.utilityPane.annotation.freeText.font.name.courierBoldOblique=Courier-BoldOblique -viewer.utilityPane.annotation.freeText.font.name.courierBold=Courier-Bold -## Utility Pane Annotation text Tab -viewer.utilityPane.annotation.text.appearance.title=Text Annotation -viewer.utilityPane.annotation.text.iconName=Icon: -viewer.utilityPane.annotation.text.iconName.comment=Comment -viewer.utilityPane.annotation.text.iconName.check=Check -viewer.utilityPane.annotation.text.iconName.checkMark=CheckMark -viewer.utilityPane.annotation.text.iconName.circle=Circle -viewer.utilityPane.annotation.text.iconName.cross=Cross -viewer.utilityPane.annotation.text.iconName.crossHairs=CrossHairs -viewer.utilityPane.annotation.text.iconName.help=Help -viewer.utilityPane.annotation.text.iconName.insert=Insert -viewer.utilityPane.annotation.text.iconName.key=Key -viewer.utilityPane.annotation.text.iconName.newParagraph=NewParagraph -viewer.utilityPane.annotation.text.iconName.paragraph=Paragraph -viewer.utilityPane.annotation.text.iconName.rightArrow=RightArrow -viewer.utilityPane.annotation.text.iconName.rightPointer=RightPointer -viewer.utilityPane.annotation.text.iconName.star=Star -viewer.utilityPane.annotation.text.iconName.upArrow=UpArrow -viewer.utilityPane.annotation.text.iconName.upLeftArrow=UpLeftArrow -## Utility Pane Annotation circle Tab -viewer.utilityPane.annotation.circle.appearance.title=Circle Annotation -viewer.utilityPane.annotation.circle.lineThickness=Border Thickness: -viewer.utilityPane.annotation.circle.lineStyle=Border Style: -viewer.utilityPane.annotation.circle.colorBorderChooserTitle=Border Color -viewer.utilityPane.annotation.circle.colorInteriorChooserTitle=Interior Color -viewer.utilityPane.annotation.circle.colorBorderLabel=Border Color: -viewer.utilityPane.annotation.circle.colorInteriorLabel=Fill Color: -viewer.utilityPane.annotation.circle.fillTypeLabel=Fill Type: -viewer.utilityPane.annotation.circle.transparencyLabel=Transparency: -## Utility Pane Annotation ink Tab -viewer.utilityPane.annotation.ink.appearance.title=Ink Annotation -viewer.utilityPane.annotation.ink.lineThickness=Ink Thickness: -viewer.utilityPane.annotation.ink.lineStyle=Ink Style: -viewer.utilityPane.annotation.ink.colorBorderChooserTitle=Ink Color -viewer.utilityPane.annotation.ink.colorBorderLabel=Ink Color: -viewer.utilityPane.annotation.ink.transparencyLabel=Transparency: -## Utility Pane border Tab -viewer.utilityPane.annotation.border.title=Border -viewer.utilityPane.annotation.border.linkType=Border Type: -viewer.utilityPane.annotation.border.lineThickness=Border Thickness: -viewer.utilityPane.annotation.border.lineStyle=Border Style: -viewer.utilityPane.annotation.border.colorChooserTitle=Border Color -viewer.utilityPane.annotation.border.colorLabel=Color: -viewer.utilityPane.annotation.border.borderType.visibleRectangle=Visible -viewer.utilityPane.annotation.border.borderType.invisibleRectangle=Invisible -viewer.utilityPane.annotation.border.solid=Solid -viewer.utilityPane.annotation.border.dashed=Dashed -viewer.utilityPane.annotation.border.beveled=Beveled -viewer.utilityPane.annotation.border.inset=Inset -viewer.utilityPane.annotation.border.underline=Underline -## Utility Pane border Tab -viewer.utilityPane.annotation.flags.title=Flags -viewer.utilityPane.annotation.flags.noRotate=No Rotate: -viewer.utilityPane.annotation.flags.noZoom=No Zoom: -viewer.utilityPane.annotation.flags.readOnly=Read Only: -viewer.utilityPane.annotation.flags.printable=Printable: -viewer.utilityPane.annotation.flags.yes=Printable: -viewer.utilityPane.annotation.flags.enabled=Enabled -viewer.utilityPane.annotation.flags.disabled=Disabled -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle=Action -viewer.utilityPane.action.addAction=Add -viewer.utilityPane.action.editAction=Edit -viewer.utilityPane.action.removeAction=Remove -viewer.utilityPane.action.type.destination.label=Destination -viewer.utilityPane.action.type.uriAction.label=URI Action -viewer.utilityPane.action.type.goToAction.label=GoTo Action -viewer.utilityPane.action.type.launchAction.label=Launch Action -viewer.utilityPane.action.dialog.new.title=Add New Action -viewer.utilityPane.action.dialog.new.msgs=Action Type: -viewer.utilityPane.action.dialog.delete.title=Delete Confirmation -viewer.utilityPane.action.dialog.delete.msgs=Are you sure your want to delete this action? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title=URI Action Properties -viewer.utilityPane.action.dialog.uri.msgs=URI: -## launch action dialog test -viewer.utilityPane.action.dialog.launch.title=Launch Action Properties -viewer.utilityPane.action.dialog.launch.msgs=File Path: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title=GoTo Action Properties -viewer.utilityPane.action.dialog.goto.page.label=Page: -viewer.utilityPane.action.dialog.goto.type.label=Type -viewer.utilityPane.action.dialog.goto.type.xyz.label=Absolute -viewer.utilityPane.action.dialog.goto.type.fit.label=Fit Page -viewer.utilityPane.action.dialog.goto.type.fith.label=Fit Top Width -viewer.utilityPane.action.dialog.goto.type.fitv.label=Fit Left Width -viewer.utilityPane.action.dialog.goto.type.fitr.label=Fit Zoom Box -viewer.utilityPane.action.dialog.goto.type.fitb.label=Fit Page Bounds -viewer.utilityPane.action.dialog.goto.type.fitbh.label=Fit Bounds Top -viewer.utilityPane.action.dialog.goto.type.fitbv.label=Fit Bounds Left -viewer.utilityPane.action.dialog.goto.right.label=Right: -viewer.utilityPane.action.dialog.goto.left.label=Left: -viewer.utilityPane.action.dialog.goto.top.label=Top: -viewer.utilityPane.action.dialog.goto.bottom.label=Bottom: -viewer.utilityPane.action.dialog.goto.zoom.label=Zoom: -viewer.utilityPane.action.dialog.goto.unassigned.label=NaN -viewer.utilityPane.action.dialog.goto.current.label=Current View: -viewer.utilityPane.action.dialog.goto.current=Set Location -viewer.utilityPane.action.dialog.goto.name.label=Name: -viewer.utilityPane.action.dialog.goto.browse=Browse... -viewer.utilityPane.action.dialog.goto.explicitDestination.title=Implicit Destination -viewer.utilityPane.action.dialog.goto.nameDestination.title=Named Destination -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title=Document Name Tree -viewer.utilityPane.action.dialog.goto.nameTree.root.label=Name Tree -viewer.utilityPane.action.dialog.goto.nameTree.branch.label={0} to {1} -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title=Search -viewer.utilityPane.search.searchText.label=Search Text: -viewer.utilityPane.search.results.label=Results: -viewer.utilityPane.search.searchButton.label=Search -viewer.utilityPane.search.clearSearchButton.label=Clear -viewer.utilityPane.search.caseSenstiveCheckbox.label=Case-sensitive -viewer.utilityPane.search.wholeWordCheckbox.label=Whole words only -viewer.utilityPane.search.cumlitiveCheckbox.label=Cumulative -viewer.utilityPane.search.showPagesCheckbox.label=Show Pages -viewer.utilityPane.search.stopButton.label=Stop -viewer.utilityPane.search.searching.msg=Search... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg=\ - Searching {0} out of {1} -viewer.utilityPane.search.searching1.oneFile.msg={2} page -viewer.utilityPane.search.searching1.moreFile.msg={2} pages -# Page x (y result(s)) -viewer.utilityPane.search.result.msg=Page {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg={2} result -viewer.utilityPane.search.result.moreFile.msg={2} results -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg=\ - Searched {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg=page -viewer.utilityPane.search.progress.morePage.msg=pages -viewer.utilityPane.search.progress.oneMatch.msg={2} match -viewer.utilityPane.search.progress.moreMatch.msg={2} matches -## Popup Annotation component -viewer.annotation.popup.reply.label=Reply -viewer.annotation.popup.delete.label=Delete -viewer.annotation.popup.status.label=Set Status -viewer.annotation.popup.status.accepted.label=Accepted -viewer.annotation.popup.status.cancelled.label=Cancelled -viewer.annotation.popup.status.completed.label=Completed -viewer.annotation.popup.status.rejected.label=Rejected -viewer.annotation.popup.status.none.label=None -viewer.annotation.popup.openAll.label=Open all Popups -viewer.annotation.popup.minimizeAll.label=Minimize Popups -viewer.annotation.popup.replyTo.label=Re: {0} -viewer.annotation.popup.status.none.title=None: {0} -viewer.annotation.popup.status.none.msg=None set by {0} -viewer.annotation.popup.status.accepted.title=Accepted: {0} -viewer.annotation.popup.status.accepted.msg=Accepted set by {0} -viewer.annotation.popup.status.cancelled.title=Cancelled: {0} -viewer.annotation.popup.status.cancelled.msg=Cancelled set by {0} -viewer.annotation.popup.status.completed.title=Completed: {0} -viewer.annotation.popup.status.completed.msg=Completed set by {0} -viewer.annotation.popup.status.rejected.title=Rejected: {0} -viewer.annotation.popup.status.rejected.msg=Rejected set by {0} -## Signature component -viewer.annotation.signature.menu.validateSignature.label=Validate Signature -viewer.annotation.signature.menu.showCertificates.label=Show Certificate Properties -viewer.annotation.signature.menu.signatureProperties.label=Show Signature Properties -viewer.annotation.signature.menu.signaturePageNavigation.label=Go to Page... -## Signature validation dialog. -viewer.annotation.signature.validation.dialog.title=Signature Validation Summary -viewer.annotation.signature.validation.dialog.close.button.label=Close -viewer.annotation.signature.validation.dialog.signerProperties.button.label=Signature Properties... -# common validation messages -viewer.annotation.signature.validation.common.invalid.label=Signature is invalid: -viewer.annotation.signature.validation.common.unknown.label=Signature is valid: -viewer.annotation.signature.validation.common.valid.label=Signature validity is unknown: -viewer.annotation.signature.validation.common.signedBy.label=- Signed by {0} {1} -viewer.annotation.signature.validation.common.doc.modified.label=\ - - This version of the document is unaltered but subsequent changes have been made -viewer.annotation.signature.validation.common.doc.unmodified.label=- Document has not been modified since it was signed -viewer.annotation.signature.validation.common.doc.major.label=- Document has been altered or corrupted since it was signed -viewer.annotation.signature.validation.common.identity.unknown.label=\ - - Signer's identity is unknown because it could not be found in your keystore -viewer.annotation.signature.validation.common.identity.unchecked.label=\ - - Signature is valid, but revocation of the signer's identity could not be checked -viewer.annotation.signature.validation.common.identity.valid.label=- Signer's identity is valid -viewer.annotation.signature.validation.common.time.local.label=- Signing time is from the clock on this signer's computer -viewer.annotation.signature.validation.common.time.embedded.label=\ - - Signature included an embedded timestamp but it could not be validated -viewer.annotation.signature.validation.common.notAvailable.label=N/A -## Signatures properties Dialog. -viewer.annotation.signature.properties.dialog.title=Signature Properties -viewer.annotation.signature.properties.dialog.invalid.label=Signature is invalid -viewer.annotation.signature.properties.dialog.unknown.label=Signature is valid -viewer.annotation.signature.properties.dialog.valid.label=Signature validity is unknown -viewer.annotation.signature.properties.dialog.signedBy.label=Signed by {0} {1} -viewer.annotation.signature.properties.dialog.signingTime.label=Signed time: {0} -viewer.annotation.signature.properties.dialog.reason.label=Reason: {0} -viewer.annotation.signature.properties.dialog.location.label=Location: {0} -# SignatureSigner Info -viewer.annotation.signature.properties.dialog.pathValidation.success=- Path validation checks were successful. -viewer.annotation.signature.properties.dialog.pathValidation.failure=- Path validation checks were unsuccessful. -viewer.annotation.signature.properties.dialog.revocation.success=- Signer's certificate is valid and has not been revoked. -viewer.annotation.signature.properties.dialog.revocation.failure=- Revocation checking was not performed. -viewer.annotation.signature.properties.dialog.certificateExpired.failure=- Signer certificate has expired. -viewer.annotation.signature.properties.dialog.showCertificates.label=Signer's Certificate... -viewer.annotation.signature.properties.dialog.validity.title=Validity Summary -viewer.annotation.signature.properties.dialog.signerInfo.title=Signer Info -## Common Button Labels -viewer.button.ok.label=Ok -viewer.button.ok.mnemonic=O -viewer.button.cancel.label=Cancel -viewer.button.cancel.mnemonic=C -## Pilot Specific Mesages -pilot.title=ICEbrowser - ICEpdf Pilot Errror -pilot.loading.msg=Opening document {0} ... -pilot.display.msg=Displaying {0} -pilot.loading.error.msg=PDF Pilot: Failed to load {0}. -pilot.error.classLoading=Required class {0} not found. Required library \ - 'icepdf.jar' may not be on the classpath - PDF Pilot disabled."; -### -# General Error Messages -# Command Line Errors -viewer.commandLin.error=\ - Usage: java org.icepdf.ri.viewer.Main [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title=ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message=ICEpdf could not open the specified file. {0} at URL: {1}. -viewer.launcher.lookAndFeel.error.message=The specified look-and-feel ({0}) is not accessible from this platform. -# Pilot Loading Errors -### parser error dialogs -parse.title=Properties Parsing Error -parse.integer=Warning : {0} is not a correct integer. -parse.float=Warning : {0} is not a correct float. -parse.double=Warning : {0} is not a correct double. -parse.choice=Warning : {0} is not a valid choice. -parse.laf=Warning : look-and-feel {0} is not supported. -### Properties Manager Errors -manager.properties.title=ICEpdf Properties Manager -fontManager.properties.title=ICEpdf Font Manager -manager.properties.createNewDirectory=\ - To create the directory {0},\n\ - where the ICEpdf Viewer will store changes to its setup, click Yes.\n\n\ - If you click "No", all changes you make to the ICEpdf Viewer setup\n\ - will be lost when you quit the application. \n\n -manager.properties.failedCreation=\ - ICEpdf Viewer directory to store user data can not be created:\n\ - {0}\n\ - ICEpdf Viewer will not save changes to its default setup. -manager.properties.session.nolock=\ - Error creating the lock file :\n\ - {0}\n -manager.properties.session.readError=\ - Error loading properties file: \n\ - {0} -manager.properties.deleted=Property file has been deleted\n\ - ({0})\n\ - Recreate it ? -manager.properties.modified=Property file has been modified since last update\n\ -({0,date,long})\n\ -Would you like to merge changes in the file with the current properties? -manager.properties.saveError=Impossible to save property file.\n\ -Encountered the folowing error :\n\ -{0} -manager.properties.lafError=\ - Look&Feel {0} given in the default properties is unsupported.\n\ - Using system default. -manager.properties.brokenProperty=Broken default property {0} value: {1} -manager.properties.missingProperty=Missing default property {0} value: {1} - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_da.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_da.properties deleted file mode 100644 index e0fc57f362..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_da.properties +++ /dev/null @@ -1,477 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf-fremviser -viewer.window.title.open.default = ICEpdf-fremviser - [{0}] - -#status bar -viewer.statusbar.currentPage = Side {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Skjul værktøjslinje -viewer.toolbar.showToolBar.label = Vis værktøjslinje -viewer.toolbar.showUtilityPane.label = Vis ruden Hjælpeprogram -viewer.toolbar.hideUtilityPane.label = Skjul ruden Hjælpeprogram -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Åbn dokument -viewer.toolbar.saveAs.label = Gem som -viewer.toolbar.saveAs.tooltip = Gem som... -viewer.toolbar.print.label = Udskriv -viewer.toolbar.print.tooltip = Udskriv dokumentet -viewer.toolbar.search.label = Søg -viewer.toolbar.search.tooltip = Søg i dokument -viewer.toolbar.utilityPane.label = Ruden Hjælpeprogram -viewer.toolbar.utilityPane.tooltip = Vis/skjul ruden Hjælpeprogram -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Antal sider -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = Aktuelt sidenummer -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Første side -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Forrige side -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Næste side -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Sidste side -viewer.toolbar.pageIndicator = af {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zoom -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Zoom ud -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Zoom ind -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Aktuel størrelse -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = Tilpas vindue -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Tilpas bredde -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Roter til venstre -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Roter til højre -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Tekstmarkeringsværktøj -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Tekstmarkeringsværktøj -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Markeringsværktøj -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Linkmarkeringsværktøj -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Værktøjet Zoom ind -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Værktøjet Zoom ud -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Aktiver/deaktiver Font Engine - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Enkeltsidet visning, ikke-kontinuerlig -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Visning af modstående sider, ikke-kontinuerlig -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Enkeltsidet visning, kontinuerlig -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Visning af modstående sider, kontinuerlig - - -## File Menu and submenu items -viewer.menu.file.label = Fil -viewer.menu.file.mnemonic = F -viewer.menu.open.label = Åbn -viewer.menu.open.file.label = Fil... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Luk -viewer.menu.saveAs.label = Gem som... -viewer.menu.exportText.label = Eksporter tekst... -viewer.menu.documentProperties.label=Dokumentoplysninger... -viewer.menu.documentPermission.label = Dokumenttilladelser... -viewer.menu.documentInformation.label = Dokumentoplysninger... -viewer.menu.printSetup.label = Udskriftsindstillinger... -viewer.menu.print.label = Udskriv... -viewer.menu.exit.label = Afbrudt - -## View Menu and submenu items -viewer.menu.edit.label = Rediger -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Annuller -viewer.menu.edit.redo.label = Cyklus -viewer.menu.edit.copy.label = Kopier -viewer.menu.edit.delete.label = Slet -viewer.menu.edit.selectAll.label = Marker alt -viewer.menu.edit.deselectAll.label = Afmarker alle -## View Menu and submenu items -viewer.menu.view.label = Vis -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = Aktuel størrelse -viewer.menu.view.fitInWindow.label = Tilpas vindue -viewer.menu.view.fitWidth.label = Tilpas bredde -viewer.menu.view.zoomIn.label = Zoom ind -viewer.menu.view.zoomOut.label = Zoom ud -viewer.menu.view.rotateLeft.label = Roter til venstre -viewer.menu.view.rotateRight.label = Roter til højre -viewer.menu.view.hideToolBar.label = Skjul værktøjslinje -viewer.menu.view.showToolBar.label = Vis værktøjslinje -viewer.menu.view.showUtilityPane.label = Vis ruden Hjælpeprogram -viewer.menu.view.hideUtilityPane.label = Skjul ruden Hjælpeprogram - -## Document Menu and submenu items -viewer.menu.document.label = Dokument -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Første side -viewer.menu.document.previousPage.label = Forrige side -viewer.menu.document.nextPage.label = Næste side -viewer.menu.document.lastPage.label = Sidste side -viewer.menu.document.search.label = Søg... -viewer.menu.document.gotToPage.label = Gå til side... - -## Window Menu and submenu items -viewer.menu.window.label = Dialogboks -viewer.menu.window.mnemonic = kbytes -viewer.menu.window.minAll.label = Minimer alle -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = Sæt alle forrest -viewer.menu.window.frontAll.mnemonic = b -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Hjælp -viewer.menu.help.mnemonic = Sp -viewer.menu.help.about.label = Om ICEpdf-fremviser... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Undtagelse -viewer.dialog.error.exception.msg = \ - Der opstod en fejl under udførelsen af kommandoen til følgende undtagelse\n {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Åbn fil -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Fejl i åbning af fil -viewer.dialog.openFile.error.msg = \ - ICEpdf kunne ikke åbne den angivne fil på {0}\n\ - Filen kan være defekt eller af en ikke-understøttet filtype. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - PDF-undtagelse -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf kunne ikke åbne den angivne fil {0}\n\ - Filen kan være defekt eller af en ikke-understøttet filtype. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - PDF-sikkerhedsundtagelse -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf kunne ikke åbne den krypterede fil på {0}\n\ - Dette kan skyldes en ugyldig adgangskode eller en manglende JCE Security Provider.\n\n\ - Der henvises til ICEpdf Developer's Guide vedr. yderligere oplysninger. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Undtagelse -viewer.dialog.openDocument.exception.msg = \ - ICEpdf kunne ikke åbne den angivne fil på {0}\n\ - Filen kan være defekt eller af en ikke-understøttet filtype. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - URL-undtagelse -viewer.dialog.openURL.exception.msg = ICEpdf kunne ikke åbne den angivne fil. {0} \n\ - på URL: {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Information -viewer.dialog.information.copyAll.msg = Dokumentet har mere end {0} sider, brug venligst\n\ - "Eksporter tekst..." til at trække dokumentets tekst ud. - -## Open URL Dialog -viewer.dialog.security.title = Dokumentsikkerhed -viewer.dialog.security.msg = Denne PDF er beskyttet -viewer.dialog.security.password.label = Adgangskode: -viewer.dialog.security.okButton.label = OK -viewer.dialog.security.okButton.mnemonic = o -viewer.dialog.security.cancelButton.label = Annuller -viewer.dialog.security.cancelButton.mnemonic = E - - -## Open URL Dialog -viewer.dialog.openURL.title = Åbn URL - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Gem som -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Fej i Gem -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf kunne ikke gemme til {0}, da den ikke er en understøtte filtype. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Fej i Gem -viewer.dialog.saveAs.noExtensionError.msg = Angiv et filtypenavn. - - -## Export Text Dialog -viewer.dialog.exportText.title = Eksporter dokumentets tekst -viewer.dialog.exportText.progress.msg = Træk PDF-teksten ud -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Fej i Gem -viewer.dialog.exportText.noExtensionError.msg = Angiv et filtype navn. -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf fremviser, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = Gennemført {0} ud af {1}. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} side -viewer.exportText.fileStamp.progress.moreFile.msg = {2} sider - - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Side {0} af {1} -viewer.dialog.printing.status.start.msg = Spooler side(r) til printeren - - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Dokumenttilladelser -viewer.dialog.documentPermissions.securityMethod.label = Sikkerhedsmetode: -viewer.dialog.documentPermissions.userPassword.label = Brugeradgangskode: -viewer.dialog.documentPermissions.ownerPassword.label = Ejers adgangskode: -viewer.dialog.documentPermissions.printing.label = Udskriver: -viewer.dialog.documentPermissions.changing.label = Ændring af dokument: -viewer.dialog.documentPermissions.copyExtraction.label = Kopiering af indhold eller ekstraktion: -viewer.dialog.documentPermissions.comments.label = Oprettelse af kommentar- og formfelter: -viewer.dialog.documentPermissions.formFillingIn.label = Udfyld eller underskriv formfelt: -viewer.dialog.documentPermissions.accessibility.label = Adgang til indhold er aktiveret: -viewer.dialog.documentPermissions.assembly.label = Dokumentsamling: -viewer.dialog.documentPermissions.encryptionLevel.label = Indkodningsniveau: -viewer.dialog.documentPermissions.securityLevel = {0}-bit v{1} R {2} -viewer.dialog.documentPermissions.none = Ingen -viewer.dialog.documentPermissions.no = Nej -viewer.dialog.documentPermissions.yes = Ja -viewer.dialog.documentPermissions.allowed = Tilladt -viewer.dialog.documentPermissions.notAllowed = Ikke tilladt -viewer.dialog.documentPermissions.fullyAllowed = Fuldt tilladt -viewer.dialog.documentPermissions.standardSecurity = Adobe Acrobat Standard Security -viewer.dialog.documentPermissions.partial = Delvis (Lav kvalitet) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = Dokumentoplysninger -viewer.dialog.documentInformation.title.label = Titel: -viewer.dialog.documentInformation.subject.label = Emne: -viewer.dialog.documentInformation.author.label = Forfatter: -viewer.dialog.documentInformation.keywords.label = Nøgleord: -viewer.dialog.documentInformation.creator.label = Forfatter: -viewer.dialog.documentInformation.producer.label = Producer: -viewer.dialog.documentInformation.created.label = Oprettet: -viewer.dialog.documentInformation.modified.label = Ændret: -viewer.dialog.documentInformation.notAvailable = Ikke tilgængelig - -## Go to Page Dialog -viewer.dialog.goToPage.title = Gå til side... -viewer.dialog.goToPage.description.label = Sidenummer - -## About Dialog -viewer.dialog.about.title = Om ICEpdf-fremviser -viewer.dialog.about.pageNumber.label = \ - Se de sidste nyheder på ICEpdf webstedet\n\ - http://www.icepdf.org/ - -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Bogmærker - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Anmærkninger -viewer.utilityPane.link.appearanceTitle = Udseende -viewer.utilityPane.link.linkType = Linktype: -viewer.utilityPane.annotation.link.highlightType = Markeringstypografi: -viewer.utilityPane.link.lineThickness = Linjetykkelse: -viewer.utilityPane.link.lineStyle = Linjetypografi: -viewer.utilityPane.link.colorChooserTitle = Anmærkningsfarve -viewer.utilityPane.link.colorLabel = Farve: -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Beskrivelse -viewer.utilityPane.action.addAction = Tilføj -viewer.utilityPane.action.editAction = Rediger -viewer.utilityPane.action.removeAction = Slet -viewer.utilityPane.action.type.destination.label = Destination -viewer.utilityPane.action.type.uriAction.label = URI-handling -viewer.utilityPane.action.type.goToAction.label = GoTo (Gå til) handling -viewer.utilityPane.action.dialog.new.title = Tilføj ny handling -viewer.utilityPane.action.dialog.new.msgs = Handlingstype: -viewer.utilityPane.action.dialog.delete.title = Slet bekræftelse -viewer.utilityPane.action.dialog.delete.msgs = Ønsker du at slette denne handling? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = URI handlingsegenskaber -viewer.utilityPane.action.dialog.uri.msgs = URI: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = GoTo (Gå til) handlingsegenskaber -viewer.utilityPane.action.dialog.goto.page.label = Side: -viewer.utilityPane.action.dialog.goto.type.label = Type -viewer.utilityPane.action.dialog.goto.type.xyz.label = Absolut -viewer.utilityPane.action.dialog.goto.type.fit.label = Tilpas side -viewer.utilityPane.action.dialog.goto.type.fith.label = Tilpas topbredde -viewer.utilityPane.action.dialog.goto.type.fitv.label = Tilpas venstre bredde -viewer.utilityPane.action.dialog.goto.type.fitr.label = Tilpas zoomboks -viewer.utilityPane.action.dialog.goto.type.fitb.label = Tilpas sidens grænser -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Tilpas grænsernes top -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Tilpas grænsernes venstre side -viewer.utilityPane.action.dialog.goto.right.label = Højre: -viewer.utilityPane.action.dialog.goto.left.label = Venstre: -viewer.utilityPane.action.dialog.goto.top.label = Top: -viewer.utilityPane.action.dialog.goto.bottom.label = Bund: -viewer.utilityPane.action.dialog.goto.zoom.label = Zoom: -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Aktuel visning: -viewer.utilityPane.action.dialog.goto.current = Indstil sted -viewer.utilityPane.action.dialog.goto.name.label = Navn: -viewer.utilityPane.action.dialog.goto.browse = Gennemse... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Implicit destination -viewer.utilityPane.action.dialog.goto.nameDestination.title = Navngivet Destination -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Dokumentnavnetræ -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Navnetræ -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} til {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Søg -viewer.utilityPane.search.searchText.label = Søg tekst: -viewer.utilityPane.search.results.label = Resultater: -viewer.utilityPane.search.searchButton.label = Søg -viewer.utilityPane.search.clearSearchButton.label = Ryd -viewer.utilityPane.search.caseSenstiveCheckbox.label = Skelnen mellem store og små bogstaver -viewer.utilityPane.search.wholeWordCheckbox.label = Kun hele ord -viewer.utilityPane.search.cumlitiveCheckbox.label = Kumulativ -viewer.utilityPane.search.showPagesCheckbox.label = Vis sider -viewer.utilityPane.search.stopButton.label = Stop -viewer.utilityPane.search.searching.msg = Søg... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = Søger 0} ud af {1}. -viewer.utilityPane.search.searching1.oneFile.msg = {2} side -viewer.utilityPane.search.searching1.moreFile.msg = {2} sider -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Side {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} resultat -viewer.utilityPane.search.result.moreFile.msg = {2} resultater -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = Søgt {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = side -viewer.utilityPane.search.progress.morePage.msg = sider -viewer.utilityPane.search.progress.oneMatch.msg = {2} match -viewer.utilityPane.search.progress.moreMatch.msg = {2} matches - -## Common Button Labels -viewer.button.ok.label = OK -viewer.button.ok.mnemonic = O -viewer.button.cancel.label = Annuller -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - ICEpdf-pilotfejl -pilot.loading.msg =Åbner dokument {0} ... -pilot.display.msg = Viser {0} -pilot.loading.error.msg = PDF-pilot: Kunne ikke indlæse {0}. -pilot.error.classLoading = Kræven klasse {0} ikke fundet. Krævet bibliotek \n\ - 'icepdf.jar' er muligvis ikke på klassestien - PDF-pilot deaktiveret."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = Brug: java org.icepdf.ri.fremviser.Vigtigste [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf kunne ikke åbne den angivne fil. {0} på URL: {1}. -viewer.launcher.lookAndFeel.error.message = Den angivne look-and-feel ({0}) kan ikke åbnes fra denne platform. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Parsing-fejl i egenskaber -parse.integer = Advarsel: {0} er ikke et korrekt heltal. -parse.float = Advarsel: {0} er ikke et korrekt flydende. -parse.double = Advarsel: {0} er ikke et korrekt dobbelt. -parse.choice = Advarsel: {0} er ikke et gyldigt valg. -parse.laf = Advarsel: look-and-feel {0} understøttes ikke. - -### Properties Manager Errors -manager.properties.title = ICEpdf Properties Manager -fontManager.properties.title = ICEpdf Font Manager - -manager.properties.createNewDirectory = Klik Ja for at oprette biblioteket {0},\n\ - hvor ICEpdf Viewer vil gemme ændringerne til dets opsætning.\n\n\ - Hvis du klikker "Nej", mistes alle ændringer til ICEpdf Viewer'en opsætning,\n\ - når applikationen afsluttes. - -manager.properties.failedCreation = \ - Der kunne ikke oprettes et ICEpdf Viewer-bibliotek til at gemme brugerdata:\n\ - {0} \n\ - ICEpdf Viewer gemmer ikke ændringer til standardopsætningen. - -manager.properties.session.nolock = \ - Fejl under oprettelse af låsefil:\n\ - {0} - -manager.properties.session.readError = \ - Fejl under indlæsning af egenskabsfil: \n\ - {0} - -manager.properties.deleted = Egenskabsfilen er slettet\n\ - ({0})\n\ - Genopret ? - -manager.properties.modified = Egenskabsfilen er ændret siden sidste opdatering\n\ - ({0,date,long})\n\ - Ønsker du at slå ændringerne sammen med filens aktuelle egenskaber? - -manager.properties.saveError = Kunne ikke gemme egenskabsfilen.\n\ - Følgende fejl fundet:\n\ - {0} - -manager.properties.lafError = Look&Feel {0} understøttes ikke i de givne standardegenskaber.\n\ - Brug af systemstandarder. - -manager.properties.brokenProperty = Brudt værdi for standardegenskab {0}: {1} - -manager.properties.missingProperty = Manglende værdi for standardegenskab {0}: {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_de.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_de.properties deleted file mode 100644 index b0808d860b..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_de.properties +++ /dev/null @@ -1,490 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf Viewer -viewer.window.title.open.default = ICEpdf Viewer - [{0}] - -#status bar -viewer.statusbar.currentPage = Seite {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Symbolleiste ausblenden -viewer.toolbar.showToolBar.label = Symbolleiste anzeigen -viewer.toolbar.showUtilityPane.label = Fensterbereich Hilfsfunktionen anzeigen -viewer.toolbar.hideUtilityPane.label = Fensterbereich Hilfsfunktionen ausblenden -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Dokument öffnen -viewer.toolbar.saveAs.label = Speichern unter -viewer.toolbar.saveAs.tooltip = Speichern unter:.. -viewer.toolbar.print.label = Drucken -viewer.toolbar.print.tooltip = Dokument drucken -viewer.toolbar.search.label = Suchen -viewer.toolbar.search.tooltip = Dokument suchen -viewer.toolbar.utilityPane.label = Fensterbereich Hilfsfunktionen -viewer.toolbar.utilityPane.tooltip = Fensterbereich Hilfsfunktionen anzeigen/ausblenden -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Seitenanzahl -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = AktuelleSeite Nummer -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Erste Seite -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Vorherige Seite -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Nächste Seite -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Letzte Seite -viewer.toolbar.pageIndicator = von {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zoom -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Zoom - hinaus -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Zoom - hinein -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Tatsächliche Größe -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = An Fenster anpassen -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Breite anpassen -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Nach links drehen -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Nach rechts drehen -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Verschiebewerkzeug -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Textauswahlwerkzeug -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Auswahlwerkzeug -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Anmerkungs-Vernküpfungswerkzeug -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Vergrößern-Werkzeug -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Verkleinern-Werkzeug -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Font-Engine aktivieren/deaktivieren - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Ansicht Einzelseite, nicht fortlaufend -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Ansicht Doppelseite, nicht fortlaufend -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Einzelseite, fortlaufend -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Doppelseite, fortlaufend - - -## File Menu and submenu items -viewer.menu.file.label = Datei -viewer.menu.file.mnemonic = F -viewer.menu.open.label = Öffnen (Open) -viewer.menu.open.file.label = Datei... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Schließen -viewer.menu.saveAs.label = Speichern unter:.. -viewer.menu.exportText.label = Text exportieren... -viewer.menu.documentProperties.label=Dokumentinformationen... -viewer.menu.documentPermission.label = Dokumentenberechtigungen... -viewer.menu.documentInformation.label = Dokumentinformationen... -viewer.menu.printSetup.label = Drucker einrichten... -viewer.menu.print.label = Drucken... -viewer.menu.exit.label = Abbruch - -## View Menu and submenu items -viewer.menu.edit.label = Bearbeiten -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Rückgängig -viewer.menu.edit.redo.label = Wiederholen -viewer.menu.edit.copy.label = Kopieren -viewer.menu.edit.delete.label = Löschen -viewer.menu.edit.selectAll.label = Alles auswählen -viewer.menu.edit.deselectAll.label = Auswahl für alle aufheben -## View Menu and submenu items -viewer.menu.view.label = Ansicht -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = Tatsächliche Größe -viewer.menu.view.fitInWindow.label = An Fenster anpassen -viewer.menu.view.fitWidth.label = Breite anpassen -viewer.menu.view.zoomIn.label = Zoom - hinein -viewer.menu.view.zoomOut.label = Zoom - hinaus -viewer.menu.view.rotateLeft.label = Nach links drehen -viewer.menu.view.rotateRight.label = Nach rechts drehen -viewer.menu.view.hideToolBar.label = Symbolleiste ausblenden -viewer.menu.view.showToolBar.label = Symbolleiste anzeigen -viewer.menu.view.showUtilityPane.label = Fensterbereich Hilfsfunktionen anzeigen -viewer.menu.view.hideUtilityPane.label = Fensterbereich Hilfsfunktionen ausblenden - -## Document Menu and submenu items -viewer.menu.document.label = Dokumente -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Erste Seite -viewer.menu.document.previousPage.label = Vorherige Seite -viewer.menu.document.nextPage.label = Nächste Seite -viewer.menu.document.lastPage.label = Letzte Seite -viewer.menu.document.search.label = Suchen... -viewer.menu.document.gotToPage.label = Gehe zu Seite... - -## Window Menu and submenu items -viewer.menu.window.label = Fenster -viewer.menu.window.mnemonic = W -viewer.menu.window.minAll.label = Alle minimieren -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = Alles in den Vordergrund -viewer.menu.window.frontAll.mnemonic = b -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Hilfe -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = Über den ICEpdf Viewer... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Ausnahme -viewer.dialog.error.exception.msg = \ - Bei der Ausführung des Befehls ist aufgrund folgender Ausnahme ein Fehler aufgetreten\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Datei öffnen -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Fehler beim Öffnen der Datei -viewer.dialog.openFile.error.msg = \ - ICEpdf konnte die angegebene Datei unter {0} nicht öffnen\n\ - Möglicherweise ist die Datei beschädigt oder in einem nicht unterstützten Dateiformat abgespeichert. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - PDF-Ausnahme -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf konnte die angegebene Datei {0} nicht öffnen\n\ - Möglicherweise ist die Datei beschädigt oder in einem nicht unterstützten Dateiformat abgespeichert. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - PDF-Sicherheitsausnahme -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf konnte die verschlüsselte Datei unter {0} nicht öffnen\n\ - Ursache ist möglicherweise ein falsches Passwort oder ein fehlender JCE Security Provider.\n\n\ - Weitere Informationen finden Sie im ICEpdf Entwickler-Handbuch. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Ausnahme -viewer.dialog.openDocument.exception.msg = \ - ICEpdf konnte die angegebene Datei unter {0} nicht öffnen\n\ - Möglicherweise ist die Datei beschädigt oder in einem nicht unterstützten Dateiformat abgespeichert. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - URL-Ausnahme -viewer.dialog.openURL.exception.msg = \ - ICEpdf konnte die angegebene Datei nicht öffnen. {0} \n\ - unter URL: {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Information -viewer.dialog.information.copyAll.msg = \ - Das Dokument hat mehr als {0} Seiten, bitte verwenden Sie\n\ - "Text exportieren...", um den Dokumententext zu extrahieren. - -## Open URL Dialog -viewer.dialog.security.title = Dokumentensicherheit -viewer.dialog.security.msg = Dieses PDF ist geschützt -viewer.dialog.security.password.label = Passwort: -viewer.dialog.security.okButton.label = Ok -viewer.dialog.security.okButton.mnemonic = o -viewer.dialog.security.cancelButton.label = Abbrechen -viewer.dialog.security.cancelButton.mnemonic = C - - -## Open URL Dialog -viewer.dialog.openURL.title = URL öffnen - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Speichern unter -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Fehler beim Speichern -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf konnte unter {0} nicht speichern, weil dies kein unterstützter Dateityp ist. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Fehler beim Speichern -viewer.dialog.saveAs.noExtensionError.msg = Bitte geben Sie eine Dateierweiterung an. - - -## Export Text Dialog -viewer.dialog.exportText.title = Dokumententext exportieren. -viewer.dialog.exportText.progress.msg = PDF-Text extrahieren -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Fehler beim Speichern -viewer.dialog.exportText.noExtensionError.msg = Bitte geben Sie eine Dateierweiterung an. -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = {0} von {1} abgeschlossen. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} Seite -viewer.exportText.fileStamp.progress.moreFile.msg = {2} Seiten - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Seite {0} von {1} -viewer.dialog.printing.status.start.msg = Übertragung der Seite(n) zum Drucker - - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Dokumentenberechtigungen -viewer.dialog.documentPermissions.securityMethod.label = Sicherheitsmethode: -viewer.dialog.documentPermissions.userPassword.label = Benutzerpasswort: -viewer.dialog.documentPermissions.ownerPassword.label = Besitzerpasswort: -viewer.dialog.documentPermissions.printing.label = Drucken: -viewer.dialog.documentPermissions.changing.label = Ändern des Dokuments: -viewer.dialog.documentPermissions.copyExtraction.label = Kopieren oder Extrahieren des Inhalts: -viewer.dialog.documentPermissions.comments.label = Bearbeiten von Kommentaren und Formularfeldern: -viewer.dialog.documentPermissions.formFillingIn.label = Ausfüllen von Formularfeldern oder Unterzeichnen: -viewer.dialog.documentPermissions.accessibility.label = Zugriff auf Inhalte freigegeben: -viewer.dialog.documentPermissions.assembly.label = Dokumentenzusammenstellung: -viewer.dialog.documentPermissions.encryptionLevel.label = Verschlüsselungsgrad: -viewer.dialog.documentPermissions.securityLevel = {0}-bit v{1} R {2} -viewer.dialog.documentPermissions.none = Keine -viewer.dialog.documentPermissions.no = Nein -viewer.dialog.documentPermissions.yes = Ja -viewer.dialog.documentPermissions.allowed = Zulässig -viewer.dialog.documentPermissions.notAllowed = Nicht zulässig -viewer.dialog.documentPermissions.fullyAllowed = Voll zulässig -viewer.dialog.documentPermissions.standardSecurity = Adobe Acrobat Standardsicherheit -viewer.dialog.documentPermissions.partial = Partiell (Niedrige Qualität) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = Dokumentinformationen -viewer.dialog.documentInformation.title.label = Titel: -viewer.dialog.documentInformation.subject.label = Thema: -viewer.dialog.documentInformation.author.label = Autor: -viewer.dialog.documentInformation.keywords.label = Stichwörter: -viewer.dialog.documentInformation.creator.label = Ersteller: -viewer.dialog.documentInformation.producer.label = Hersteller: -viewer.dialog.documentInformation.created.label = Erstellt: -viewer.dialog.documentInformation.modified.label = Geändert: -viewer.dialog.documentInformation.notAvailable = Nicht verfügbar - -## Go to Page Dialog -viewer.dialog.goToPage.title = Gehe zu Seite... -viewer.dialog.goToPage.description.label = Seitennummer - -## About Dialog -viewer.dialog.about.title = Über ICEpdf Viewer -viewer.dialog.about.pageNumber.label = \ - Besuchen Sie die ICEpdf Website, um die neuesten Informationen zu erhalten:\n\ - http://www.icepdf.org/ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Lesezeichen - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Anmerkungen -viewer.utilityPane.link.appearanceTitle = Darstellung -viewer.utilityPane.link.linkType = Linktyp: -viewer.utilityPane.annotation.link.highlightType = Hervorhebungsstil: -viewer.utilityPane.link.lineThickness = Liniendicke: -viewer.utilityPane.link.lineStyle = Linienstil: -viewer.utilityPane.link.colorChooserTitle = Farbe von Anmerkungen -viewer.utilityPane.link.colorLabel = Farbe: -## Utility Pane border Tab -viewer.utilityPane.annotation.flags.title = Flags -viewer.utilityPane.annotation.flags.noRotate = No Rotate: -viewer.utilityPane.annotation.flags.noZoom = No Zoom: -viewer.utilityPane.annotation.flags.readOnly = Read Only: -viewer.utilityPane.annotation.flags.printable = Printable: -viewer.utilityPane.annotation.flags.yes = Printable: -viewer.utilityPane.annotation.flags.enabled = Enabled -viewer.utilityPane.annotation.flags.disabled = Disabled -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Funktion -viewer.utilityPane.action.addAction = Hinzufügen -viewer.utilityPane.action.editAction = Bearbeiten -viewer.utilityPane.action.removeAction = Löschen -viewer.utilityPane.action.type.destination.label = Ziel -viewer.utilityPane.action.type.uriAction.label = URI Aktion -viewer.utilityPane.action.type.goToAction.label = Gehe zu Aktion -viewer.utilityPane.action.dialog.new.title = Neue Aktion hinzufügen -viewer.utilityPane.action.dialog.new.msgs = Aktionstyp: -viewer.utilityPane.action.dialog.delete.title = Bestätigung löschen -viewer.utilityPane.action.dialog.delete.msgs = Sind Sie sicher, dass Sie diese Aktion löschen möchten? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = URI-Aktionseigenschaften -viewer.utilityPane.action.dialog.uri.msgs = URI: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = Gehe zu Aktionseigenschaften -viewer.utilityPane.action.dialog.goto.page.label = Seite: -viewer.utilityPane.action.dialog.goto.type.label = Typ -viewer.utilityPane.action.dialog.goto.type.xyz.label = Absolut -viewer.utilityPane.action.dialog.goto.type.fit.label = Seite anpassen -viewer.utilityPane.action.dialog.goto.type.fith.label = Breite oben anpassen -viewer.utilityPane.action.dialog.goto.type.fitv.label = Breite links anpassen -viewer.utilityPane.action.dialog.goto.type.fitr.label = Zoom-Rahmen anpassen -viewer.utilityPane.action.dialog.goto.type.fitb.label = Seitengrenzen anpassen -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Grenzen oben anpassen -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Grenzen links anpassen -viewer.utilityPane.action.dialog.goto.right.label = Rechts: -viewer.utilityPane.action.dialog.goto.left.label = Links: -viewer.utilityPane.action.dialog.goto.top.label = Oben: -viewer.utilityPane.action.dialog.goto.bottom.label = Unten: -viewer.utilityPane.action.dialog.goto.zoom.label = Zoom: -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Aktuelle Ansicht: -viewer.utilityPane.action.dialog.goto.current = Adresse einstellen -viewer.utilityPane.action.dialog.goto.name.label = Name: -viewer.utilityPane.action.dialog.goto.browse = Durchsuchen... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Implizites Ziel -viewer.utilityPane.action.dialog.goto.nameDestination.title = Benanntes Ziel -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Dokumentennamen-Baum -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Namen-Baum -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} bis {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Suchen -viewer.utilityPane.search.searchText.label = Text suchen: -viewer.utilityPane.search.results.label = Ergebnisse: -viewer.utilityPane.search.searchButton.label = Suchen -viewer.utilityPane.search.clearSearchButton.label = Löschen -viewer.utilityPane.search.caseSenstiveCheckbox.label = Schreibungsabhängig -viewer.utilityPane.search.wholeWordCheckbox.label = Nur ganze Wörter -viewer.utilityPane.search.cumlitiveCheckbox.label = kumuliert -viewer.utilityPane.search.showPagesCheckbox.label = Seiten anzeigen -viewer.utilityPane.search.stopButton.label = Stopp -viewer.utilityPane.search.searching.msg = Suchen... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = Suche {0} von {1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} Seite -viewer.utilityPane.search.searching1.moreFile.msg = {2} Seiten -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Seite {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} Ergebnis -viewer.utilityPane.search.result.moreFile.msg = {2} Ergebnisse -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = Gesucht {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = Seite -viewer.utilityPane.search.progress.morePage.msg = Seiten -viewer.utilityPane.search.progress.oneMatch.msg = {2} Treffer -viewer.utilityPane.search.progress.moreMatch.msg = {2} Treffer - -## Common Button Labels -viewer.button.ok.label = Ok -viewer.button.ok.mnemonic = o -viewer.button.cancel.label = Abbrechen -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - ICEpdf Pilot Fehler -pilot.loading.msg =Öffne Dokument {0} ... -pilot.display.msg = Zeige {0} -pilot.loading.error.msg = PDF Pilot: Laden von {0} fehlgeschlagen. -pilot.error.classLoading = Erforderliche Klasse {0} nicht gefunden. Erforderliche Bibliothek \ - 'icepdf.jar' befindet sich möglicherweise nicht auf Klassenpfad - PDF Pilot deaktiviert."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - Verwendung: java org.icepdf.ri.viewer.Main [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf konnte die angegebene Datei nicht öffnen. {0} unter URL: {1}. -viewer.launcher.lookAndFeel.error.message = Das angegebene Look-and-Feel ({0}) ist von dieser Plattform aus nicht erreichbar. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Eigenschaften-Parsingfehler -parse.integer = Warnung : {0} ist keine korrekte Ganzzahl. -parse.float = Warnung : {0} ist keine korrekte Gleitkommazahl. -parse.double = Warnung : {0} ist kein korrektes Double. -parse.choice = Warnung : {0} ist keine gültige Auswahl. -parse.laf = Warnung : Look-and-Feel {0} wird nicht unterstützt. - -### Properties Manager Errors -manager.properties.title = ICEpdf Eigenschaften-Manager -fontManager.properties.title = ICEpdf Font-Manager - -manager.properties.createNewDirectory = \ - Um das Verzeichnis {0} zu erstellen,\n\ - in dem der ICEpdf Viewer Änderungen an den EInstellungen speichert, klicken Sie auf Ja.\n\n\ - Wenn Sie auf "Nein" klicken, gehen alle Änderungen, die Sie an den ICEpdf Viewer Einstellungen vornehmen,\n\ - beim Beenden der Applikation verloren. - -manager.properties.failedCreation = \ - ICEpdf Viewer Verzeichnis zum Speichern der Benutzerdaten kann nicht erstellt werden:\n\ - {0}\n\ - ICEpdf Viewer wird die Änderungen an den Standardeinstellungen nicht speichern. - -manager.properties.session.nolock = \ - Fehler beim Erstellen der Sperrdatei :\n\ - {0} - -manager.properties.session.readError = \ - Fehler beim Laden der Eigenschaften-Datei: \n\ - {0} - -manager.properties.deleted = Eigenschaften-Datei wurde gelöscht\n\ - ({0})\n\ - Datei wiederherstellen ? - -manager.properties.modified = Eigenschaften-Datei wurde seit der letzten Aktualisierung geändert\n\ - ({0,date,long})\n\ - Möchten Sie die Änderungen in der Datei mit den aktuellen Eigenschaften zusammenlegen? - -manager.properties.saveError = Eigenschaften-Datei kann nicht gespeichert werden.\n\ - Folgender Fehler wurde festgestellt :\n\ - {0} - -manager.properties.lafError = \ - Das in den Standardeigenschaften festgelegte Look&Feel {0} wird nicht unterstützt.\n\ - Systemstandard wird verwendet. - -manager.properties.brokenProperty = Defekter Wert für Eigenschaft {0}: {1} - -manager.properties.missingProperty = Fehlender Wert für Eigenschaft {0}: {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_es.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_es.properties deleted file mode 100644 index 2c2bbf0b16..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_es.properties +++ /dev/null @@ -1,481 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf Viewer -viewer.window.title.open.default = ICEpdf Viewer - [{0}] - -#status bar -viewer.statusbar.currentPage = Página {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Ocultar barra de herramientas -viewer.toolbar.showToolBar.label = Mostrar barra de herramientas -viewer.toolbar.showUtilityPane.label = Mostrar panel de utilidades -viewer.toolbar.hideUtilityPane.label = Ocultar panel de utilidades -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Abrir documento -viewer.toolbar.saveAs.label = Guardar como -viewer.toolbar.saveAs.tooltip = Guardar como... -viewer.toolbar.print.label = Imprimir -viewer.toolbar.print.tooltip = Imprimir documento -viewer.toolbar.search.label = Buscar -viewer.toolbar.search.tooltip = Buscar documento -viewer.toolbar.utilityPane.label = Panel de utilidades -viewer.toolbar.utilityPane.tooltip = Mostrar/Ocultar panel de utilidades -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Número de páginas -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = Número de página actual -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Primera página -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Página anterior -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Página siguiente -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Última página -viewer.toolbar.pageIndicator = de {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zoom -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Alejar -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Acercar -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Tamaño real -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = Ajustar a ventana -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Ajustar anchura -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Rotar a izquierda -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Rotar a derecha -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Herramienta Seleccionar texto -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Herramienta Seleccionar texto -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Herramienta Seleccionar -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Herramienta Vincular anotación -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Herramienta Acercar -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Herramienta Alejar -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Activar/Desactivar motor de fuente - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Vista de una página no continua -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Vista de páginas enfrentadas no continuas -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Vista de una página continua -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Vista de páginas enfrentadas continuas - - -## File Menu and submenu items -viewer.menu.file.label = Archivo -viewer.menu.file.mnemonic = A -viewer.menu.open.label = Abrir -viewer.menu.open.file.label = Archivo... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Cerrar -viewer.menu.saveAs.label = Guardar como... -viewer.menu.exportText.label = Exportar texto... -viewer.menu.documentProperties.label=Información del documento... -viewer.menu.documentPermission.label = Permisos del documento... -viewer.menu.documentInformation.label = Información del documento... -viewer.menu.printSetup.label = Configurar impresión... -viewer.menu.print.label = Imprimir... -viewer.menu.exit.label = Salir - -## View Menu and submenu items -viewer.menu.edit.label = Edición -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Deshacer -viewer.menu.edit.redo.label = Rehacer -viewer.menu.edit.copy.label = Copiar -viewer.menu.edit.delete.label = Borrar -viewer.menu.edit.selectAll.label = Seleccionar todo -viewer.menu.edit.deselectAll.label = Anular selección -## View Menu and submenu items -viewer.menu.view.label = Ver -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = Tamaño real -viewer.menu.view.fitInWindow.label = Ajustar a ventana -viewer.menu.view.fitWidth.label = Ajustar anchura -viewer.menu.view.zoomIn.label = Acercar -viewer.menu.view.zoomOut.label = Alejar -viewer.menu.view.rotateLeft.label = Rotar a izquierda -viewer.menu.view.rotateRight.label = Rotar a derecha -viewer.menu.view.hideToolBar.label = Ocultar barra de herramientas -viewer.menu.view.showToolBar.label = Mostrar barra de herramientas -viewer.menu.view.showUtilityPane.label = Mostrar panel de utilidades -viewer.menu.view.hideUtilityPane.label = Ocultar panel de utilidades - -## Document Menu and submenu items -viewer.menu.document.label = Documento -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Primera página -viewer.menu.document.previousPage.label = Página anterior -viewer.menu.document.nextPage.label = Página siguiente -viewer.menu.document.lastPage.label = Última página -viewer.menu.document.search.label = Buscar... -viewer.menu.document.gotToPage.label = Ir a página... - -## Window Menu and submenu items -viewer.menu.window.label = Ventana -viewer.menu.window.mnemonic = V -viewer.menu.window.minAll.label = Minimizar todo -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = Mostrar en primer plano -viewer.menu.window.frontAll.mnemonic = T -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Ayuda -viewer.menu.help.mnemonic = U -viewer.menu.help.about.label = Acerca de ICEpdf Viewer... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Excepción -viewer.dialog.error.exception.msg = \ - Se ha producido un error al ejecutar la orden debido a la siguiente excepción\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Abrir archivo -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Error al abrir el archivo -viewer.dialog.openFile.error.msg = \ - ICEpdf no ha podido abrir el archivo especificado en {0}\n\ - Es posible que el archivo esté dañado o sea de un tipo no admitido. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - Excepción de PDF -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf no ha podido abrir el archivo especificado {0}\n\ - Es posible que el archivo esté dañado o sea de un tipo no admitido. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - Excepción de seguridad de PDF -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf no ha podido abrir el archivo codificado en {0}\n\ - Puede ser a causa de una contraseña no válida o por falta del proveedor de seguridad JCE.\n\n\ - Consulte la Guía del desarrollador de ICEpdf para obtener más información. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Excepción -viewer.dialog.openDocument.exception.msg = \ - ICEpdf no ha podido abrir el archivo especificado en {0}\n\ - Es posible que el archivo esté dañado o sea de un tipo no admitido. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - Excepción de URL -viewer.dialog.openURL.exception.msg = \ - ICEpdf no ha podido abrir el archivo especificado. {0} \n\ - en la URL: {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Información -viewer.dialog.information.copyAll.msg = \ - El documento tiene más de {0} páginas, por favor, utilice\n\ - "Exportar texto..." para extraer el texto del documento. - -## Open URL Dialog -viewer.dialog.security.title = Seguridad de documentos -viewer.dialog.security.msg = Este PDF está protegido -viewer.dialog.security.password.label = Contraseña: -viewer.dialog.security.okButton.label = Aceptar -viewer.dialog.security.okButton.mnemonic = A -viewer.dialog.security.cancelButton.label = Cancelar -viewer.dialog.security.cancelButton.mnemonic = C - - -## Open URL Dialog -viewer.dialog.openURL.title = Abrir URL - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Guardar como -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Error al guardar -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf no se ha podido guardar en {0} porque es de un tipo de archivo no admitido. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Error al guardar -viewer.dialog.saveAs.noExtensionError.msg = Por favor, especifique una extensión de archivo. - - -## Export Text Dialog -viewer.dialog.exportText.title = Exportar texto de documento -viewer.dialog.exportText.progress.msg = Extrayendo texto de PDF -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Error al guardar -viewer.dialog.exportText.noExtensionError.msg = Por favor, especifique una extensión de archivo. -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = Finalizado {0} de {1}. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} página -viewer.exportText.fileStamp.progress.moreFile.msg = {2} páginas - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Página {0} de {1} -viewer.dialog.printing.status.start.msg = Página(s) en cola de impresión de la impresora - - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Permisos del documento -viewer.dialog.documentPermissions.securityMethod.label = Método de seguridad: -viewer.dialog.documentPermissions.userPassword.label = Contraseña del usuario: -viewer.dialog.documentPermissions.ownerPassword.label = Contraseña del propietario: -viewer.dialog.documentPermissions.printing.label = imprimir: -viewer.dialog.documentPermissions.changing.label = Cambiar el documento: -viewer.dialog.documentPermissions.copyExtraction.label = Copiar o extraer contenido: -viewer.dialog.documentPermissions.comments.label = Autorizar comentarios y campos de formulario: -viewer.dialog.documentPermissions.formFillingIn.label = Rellenar o firmar campo de formulario: -viewer.dialog.documentPermissions.accessibility.label = Activar acceso a contenido: -viewer.dialog.documentPermissions.assembly.label = Ensamblar documento: -viewer.dialog.documentPermissions.encryptionLevel.label = Nivel de codificación: -viewer.dialog.documentPermissions.securityLevel = {0}-bits v{1} R {2} -viewer.dialog.documentPermissions.none = Ninguno -viewer.dialog.documentPermissions.no = No -viewer.dialog.documentPermissions.yes = Sí -viewer.dialog.documentPermissions.allowed = Permitido -viewer.dialog.documentPermissions.notAllowed = No permitido -viewer.dialog.documentPermissions.fullyAllowed = Totalmente permitido -viewer.dialog.documentPermissions.standardSecurity = Seguridad estándar de Adobe Acrobat -viewer.dialog.documentPermissions.partial = Parcial (baja calidad) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = Información del documento -viewer.dialog.documentInformation.title.label = Título: -viewer.dialog.documentInformation.subject.label = Asunto: -viewer.dialog.documentInformation.author.label = Autor: -viewer.dialog.documentInformation.keywords.label = Palabras clave: -viewer.dialog.documentInformation.creator.label = Creador: -viewer.dialog.documentInformation.producer.label = Productor: -viewer.dialog.documentInformation.created.label = Creado: -viewer.dialog.documentInformation.modified.label = Modificado: -viewer.dialog.documentInformation.notAvailable = No disponible - -## Go to Page Dialog -viewer.dialog.goToPage.title = Ir a página... -viewer.dialog.goToPage.description.label = Número de página - -## About Dialog -viewer.dialog.about.title = Acerca de ICEpdf Viewer -viewer.dialog.about.pageNumber.label = \ - Visitar el sitio web de ICEpdf para ver las novedades más recientes:\n\ - http://www.icepdf.org/ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Marcadores electrónicos - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Anotaciones -viewer.utilityPane.link.appearanceTitle = Aspecto -viewer.utilityPane.link.linkType = Tipo de vínculo: -viewer.utilityPane.annotation.link.highlightType = Estilo del resaltado: -viewer.utilityPane.link.lineThickness = Grosor de línea: -viewer.utilityPane.link.lineStyle = Estilo de línea: -viewer.utilityPane.link.colorChooserTitle = Color de la anotación -viewer.utilityPane.link.colorLabel = Color: -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Acción -viewer.utilityPane.action.addAction = Añadir -viewer.utilityPane.action.editAction = Editar -viewer.utilityPane.action.removeAction = Eliminar -viewer.utilityPane.action.type.destination.label = Destino -viewer.utilityPane.action.type.uriAction.label = Acción URI -viewer.utilityPane.action.type.goToAction.label = Ir a acción -viewer.utilityPane.action.dialog.new.title = Añadir nueva acción -viewer.utilityPane.action.dialog.new.msgs = Tipo de acción: -viewer.utilityPane.action.dialog.delete.title = Borrar confirmación -viewer.utilityPane.action.dialog.delete.msgs = ¿Seguro que desea borrar esta acción? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = Propiedades de Acción URI -viewer.utilityPane.action.dialog.uri.msgs = URI: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = Propiedades de Ir a acción -viewer.utilityPane.action.dialog.goto.page.label = Página: -viewer.utilityPane.action.dialog.goto.type.label = Tipo -viewer.utilityPane.action.dialog.goto.type.xyz.label = Absoluta -viewer.utilityPane.action.dialog.goto.type.fit.label = Ajustar a página -viewer.utilityPane.action.dialog.goto.type.fith.label = Ajustar anchura arriba -viewer.utilityPane.action.dialog.goto.type.fitv.label = Ajustar anchura izquierda -viewer.utilityPane.action.dialog.goto.type.fitr.label = Ajustar zoom a caja -viewer.utilityPane.action.dialog.goto.type.fitb.label = Ajustar límites de página -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Ajustar límites arriba -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Ajustar límites a izquierda -viewer.utilityPane.action.dialog.goto.right.label = Derecha: -viewer.utilityPane.action.dialog.goto.left.label = Izquierda: -viewer.utilityPane.action.dialog.goto.top.label = Superior: -viewer.utilityPane.action.dialog.goto.bottom.label = Inferior: -viewer.utilityPane.action.dialog.goto.zoom.label = Zoom: -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Vista actual: -viewer.utilityPane.action.dialog.goto.current = Definir ubicación -viewer.utilityPane.action.dialog.goto.name.label = Nombre: -viewer.utilityPane.action.dialog.goto.browse = Examinar... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Destino implícito -viewer.utilityPane.action.dialog.goto.nameDestination.title = Destino con nombre -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Árbol de nombres del documento -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Árbol de nombres -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} a {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Buscar -viewer.utilityPane.search.searchText.label = Texto de búsqueda: -viewer.utilityPane.search.results.label = Resultados: -viewer.utilityPane.search.searchButton.label = Buscar -viewer.utilityPane.search.clearSearchButton.label = Limpiar -viewer.utilityPane.search.caseSenstiveCheckbox.label = Distinguir mayúsculas y minúsculas -viewer.utilityPane.search.wholeWordCheckbox.label = Sólo palabras completas -viewer.utilityPane.search.cumlitiveCheckbox.label = Acumulada -viewer.utilityPane.search.showPagesCheckbox.label = Mostrar páginas -viewer.utilityPane.search.stopButton.label = Parar -viewer.utilityPane.search.searching.msg = Buscar... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = Buscando {0} de {1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} página -viewer.utilityPane.search.searching1.moreFile.msg = {2} páginas -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Página {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} resultado -viewer.utilityPane.search.result.moreFile.msg = {2} resultados -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = Buscado {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = página -viewer.utilityPane.search.progress.morePage.msg = páginas -viewer.utilityPane.search.progress.oneMatch.msg = {2} coincidencia -viewer.utilityPane.search.progress.moreMatch.msg = {2} coincidencias - -## Common Button Labels -viewer.button.ok.label = Aceptar -viewer.button.ok.mnemonic = A -viewer.button.cancel.label = Cancelar -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - Error de ICEpdf Pilot -pilot.loading.msg =Abriendo documento {0}. .. -pilot.display.msg = Mostrando {0} -pilot.loading.error.msg = PDF Pilot: No se ha podido cargar {0}. -pilot.error.classLoading = No se encuentra la clase necesaria {0}. La biblioteca necesaria \ - 'icepdf.jar' no se encuentra en la ruta de acceso a la clase - se ha desactivado PDF Pilot."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - Uso: java org.icepdf.ri.viewer.Main [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf no ha podido abrir el archivo especificado. {0} en la URL: {1}. -viewer.launcher.lookAndFeel.error.message = La apariencia especificada ({0}) no es accesible desde esta plataforma. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Propiedades de error de análisis -parse.integer = Advertencia: {0} no es un número entero correcto. -parse.float = Advertencia: {0} no es un número flotante correcto. -parse.double = Advertencia: {0} no es un número doble correcto. -parse.choice = Advertencia: {0} no es una opción correcta. -parse.laf = Advertencia: {0} no es una apariencia válida. - -### Properties Manager Errors -manager.properties.title = Administrador de propiedades de ICEpdf -fontManager.properties.title = Administrador de fuentes de ICEpdf - -manager.properties.createNewDirectory = \ - Para crear el directorio {0},\n\ - en el que ICEpdf Viewer deba guardar los cambios de esta configuración, haga clic en Sí.\n\n\ - Si hace clic en "No", todos los cambios introducidos en la configuración de ICEpdf Viewer\n\ - se perderán en cuanto salga de la aplicación. - -manager.properties.failedCreation = \ - No ha sido posible crear el directorio de ICEpdf Viewer para guardar los datos del usuario:\n\ - {0}\n\ - ICEpdf Viewer no guardará los cambios en su archivo de configuración predeterminado. - -manager.properties.session.nolock = \ - Se ha producido un error al crear el archivo de bloqueo:\n\ - {0}\n - -manager.properties.session.readError = \ - Se ha producido un error al cargar el archivo de propiedades: \n\ - {0} - -manager.properties.deleted = Se ha borrado el archivo de propiedades\n\ - ({0})\n\ - ¿Desea volver a crearlo? - -manager.properties.modified = El archivo de propiedades se ha modificado desde la última actualización\n\ - ({0,date,long})\n\ - ¿Desea fusionar los cambios del archivo con las propiedades actuales? - -manager.properties.saveError = Imposible guardar el archivo de propiedades.\n\ - Se ha producido el siguiente error:\n\ - {0} - -manager.properties.lafError = \ - La apariencia {0} dada en el archivo de propiedades predeterminado no es válida.\n\ - Utilizando los valores predeterminados del sistema. - -manager.properties.brokenProperty = Se ha roto el valor de propiedad predeterminado {0}: {1} - -manager.properties.missingProperty = Falta el valor de propiedad predeterminado {0}: {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_fi.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_fi.properties deleted file mode 100644 index 52c91757b6..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_fi.properties +++ /dev/null @@ -1,480 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf-katselusovellus -viewer.window.title.open.default = ICEpdf-katselusovellus - [{0}] - -#status bar -viewer.statusbar.currentPage = Sivu {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Piilota työkalurivi -viewer.toolbar.showToolBar.label = Näytä työkalurivi -viewer.toolbar.showUtilityPane.label = Näytä Apuohjelmat-ruutu -viewer.toolbar.hideUtilityPane.label = Piilota Apuohjelmat-ruutu -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Avaa asiakirja -viewer.toolbar.saveAs.label = Tallenna nimellä -viewer.toolbar.saveAs.tooltip = Tallenna nimellä... -viewer.toolbar.print.label = Tulosta -viewer.toolbar.print.tooltip = Tulosta asiakirja -viewer.toolbar.search.label = Etsi -viewer.toolbar.search.tooltip = Etsi asiakirja -viewer.toolbar.utilityPane.label = Apuohjelmat-ruutu -viewer.toolbar.utilityPane.tooltip = Näytä/piilota Apuohjelmat-ruutu -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Sivumäärä -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = Nykyisen sivun numero -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Ensimmäinen sivu -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Edellinen sivu -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Seuraava sivu -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Viimeinen sivu -viewer.toolbar.pageIndicator = / {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zoomaa -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Loitonna -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Lähennä -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Todellinen koko -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = Sovita ikkunaan -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Sovita leveys -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Kierrä vasemmalle -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Kierrä oikealle -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Tekstin valintatyökalu -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Tekstin valintatyökalu -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Valintatyökalu -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Linkin huomautustyökalu -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Lähennystyökalu -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Loitonnustyökalu -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Ota käyttöön/poista käytöstä fonttikone - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Yksi sivu, ei jatkuva asiakirja -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Kaksi sivua, ei jatkuva asiakirja -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Yksi sivu, jatkuva asiakirja -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Kaksi sivua, jatkuva asiakirja - - -## File Menu and submenu items -viewer.menu.file.label = Tiedosto -viewer.menu.file.mnemonic = F -viewer.menu.open.label = Avaa -viewer.menu.open.file.label = Tiedosto... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Sulje -viewer.menu.saveAs.label = Tallenna nimellä... -viewer.menu.exportText.label = Vie teksti... -viewer.menu.documentProperties.label=Asiakirjan tiedot... -viewer.menu.documentPermission.label = Asiakirjan luvat... -viewer.menu.documentInformation.label = Asiakirjan tiedot... -viewer.menu.printSetup.label = Tulostusasetukset... -viewer.menu.print.label = Tulosta... -viewer.menu.exit.label = Poistu - -## View Menu and submenu items -viewer.menu.edit.label = Muokkaa -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Kumoa -viewer.menu.edit.redo.label = Tee uudelleen -viewer.menu.edit.copy.label = Kopioi -viewer.menu.edit.delete.label = Poista -viewer.menu.edit.selectAll.label = Valitse kaikki -viewer.menu.edit.deselectAll.label = Peruuta kaikkien valinta -## View Menu and submenu items -viewer.menu.view.label = Näkymä -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = Todellinen koko -viewer.menu.view.fitInWindow.label = Sovita ikkunaan -viewer.menu.view.fitWidth.label = Sovita leveys -viewer.menu.view.zoomIn.label = Lähennä -viewer.menu.view.zoomOut.label = Loitonna -viewer.menu.view.rotateLeft.label = Kierrä vasemmalle -viewer.menu.view.rotateRight.label = Kierrä oikealle -viewer.menu.view.hideToolBar.label = Piilota työkalurivi -viewer.menu.view.showToolBar.label = Näytä työkalurivi -viewer.menu.view.showUtilityPane.label = Näytä Apuohjelmat-ruutu -viewer.menu.view.hideUtilityPane.label = Piilota Apuohjelmat-ruutu - -## Document Menu and submenu items -viewer.menu.document.label = Asiakirja -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Ensimmäinen sivu -viewer.menu.document.previousPage.label = Edellinen sivu -viewer.menu.document.nextPage.label = Seuraava sivu -viewer.menu.document.lastPage.label = Viimeinen sivu -viewer.menu.document.search.label = Etsi... -viewer.menu.document.gotToPage.label = Siirry sivulle... - -## Window Menu and submenu items -viewer.menu.window.label = Ikkuna -viewer.menu.window.mnemonic = W -viewer.menu.window.minAll.label = Pienennä kaikki -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = Tuo kaikki eteen -viewer.menu.window.frontAll.mnemonic = B -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Ohje -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = Tietoja ICEpdf-katselusovelluksesta... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Poikkeus -viewer.dialog.error.exception.msg = \ - Komennon suorittamisessa tapahtui virhe seuraavan poikkeuksen vuoksi\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Avaa tiedosto -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Tiedoston avausvirhe -viewer.dialog.openFile.error.msg = \ - ICEpdf ei voinut avata määritettyä tiedostoa kohteessa {0}\n\ - Tiedosto voi olla turmeltunut tai tiedostotyyppiä ei tueta. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - PDF-poikkeus -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf ei voinut avata määritettyä tiedostoa {0}\n\ - Tiedosto voi olla turmeltunut tai tiedostotyyppiä ei tueta. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - PDF-suojauspoikkeus -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf ei voinut avata salattua tiedostoa kohteessa {0}\n\ - Syynä voi olla virheellinen salasana tai puuttuva JCE-suojauksen tarjoaja.\n\n\ - Lisätietoja löytyy ICEpdf-sovelluskehitysoppaasta. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Poikkeus -viewer.dialog.openDocument.exception.msg = \ - ICEpdf ei voinut avata määritettyä tiedostoa kohteessa {0}\n\ - Tiedosto voi olla turmeltunut tai tiedostotyyppiä ei tueta. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - URL-poikkeus -viewer.dialog.openURL.exception.msg = \ - ICEpdf ei voinut avata määritettyä tiedostoa. {0} \n\ - URL-osoitteessa: {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Tiedot -viewer.dialog.information.copyAll.msg = \ - Asiakirjassa on enemmän kuin {0} sivua, käytä komentoa\n\ - Vie teksti...asiakirjan tekstin purkamisessa. - -## Open URL Dialog -viewer.dialog.security.title = Asiakirjan suojaus -viewer.dialog.security.msg = Tämä PDF on suojattu -viewer.dialog.security.password.label = Salasana: -viewer.dialog.security.okButton.label = Ok -viewer.dialog.security.okButton.mnemonic = O -viewer.dialog.security.cancelButton.label = Peruuta -viewer.dialog.security.cancelButton.mnemonic = C - -## Open URL Dialog -viewer.dialog.openURL.title = Avaa URL - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Tallenna nimellä -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Tallennusvirhe -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf ei voinut tallentaa tiedostoon {0}, koska tiedostotyyppiä ei tueta. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Tallennusvirhe -viewer.dialog.saveAs.noExtensionError.msg = Määritä tiedoston tarkenne. - - -## Export Text Dialog -viewer.dialog.exportText.title = Vie asiakirjan teksti -viewer.dialog.exportText.progress.msg = Puretaan PDF:n tekstiä -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Tallennusvirhe -viewer.dialog.exportText.noExtensionError.msg = Määritä tiedoston tarkenne. -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf -katselusovellus, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = \ - Valmiina {0} / {1}. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} sivu -viewer.exportText.fileStamp.progress.moreFile.msg = {2} sivua - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Sivu {0} / {1} -viewer.dialog.printing.status.start.msg = Sivua/sivuja lähetetään tulostimeen - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Asiakirjan luvat -viewer.dialog.documentPermissions.securityMethod.label = Suojausmenetelmä: -viewer.dialog.documentPermissions.userPassword.label = Käyttäjän salasana: -viewer.dialog.documentPermissions.ownerPassword.label = Omistajan salasana: -viewer.dialog.documentPermissions.printing.label = Tulostus: -viewer.dialog.documentPermissions.changing.label = Asiakirjan muuttaminen: -viewer.dialog.documentPermissions.copyExtraction.label = Sisällön kopiointi tai purkaminen: -viewer.dialog.documentPermissions.comments.label = Kommenttien tai lomakekenttien käsittely: -viewer.dialog.documentPermissions.formFillingIn.label = Lomakekentän täyttö tai allekirjoitus: -viewer.dialog.documentPermissions.accessibility.label = Sisällön käyttö sallittu: -viewer.dialog.documentPermissions.assembly.label = Asiakirjan kokoonpano: -viewer.dialog.documentPermissions.encryptionLevel.label = Salaustaso: -viewer.dialog.documentPermissions.securityLevel = {0}-bittinen v{1} R {2} -viewer.dialog.documentPermissions.none = Ei mitään -viewer.dialog.documentPermissions.no = Ei -viewer.dialog.documentPermissions.yes = Kyllä -viewer.dialog.documentPermissions.allowed = Sallittu -viewer.dialog.documentPermissions.notAllowed = Ei sallittu -viewer.dialog.documentPermissions.fullyAllowed = Täysin sallittu -viewer.dialog.documentPermissions.standardSecurity = Adobe Acrobat -vakiosuojaus -viewer.dialog.documentPermissions.partial = Osittainen (alhainen laatu) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = Asiakirjan tiedot -viewer.dialog.documentInformation.title.label = Otsikko: -viewer.dialog.documentInformation.subject.label = Aihe: -viewer.dialog.documentInformation.author.label = Tekijä: -viewer.dialog.documentInformation.keywords.label = Avainsanat: -viewer.dialog.documentInformation.creator.label = Laatija: -viewer.dialog.documentInformation.producer.label = Tuottaja: -viewer.dialog.documentInformation.created.label = Luotu: -viewer.dialog.documentInformation.modified.label = Muokattu: -viewer.dialog.documentInformation.notAvailable = Ei saatavilla - -## Go to Page Dialog -viewer.dialog.goToPage.title = Siirry sivulle... -viewer.dialog.goToPage.description.label = Sivun numero - -## About Dialog -viewer.dialog.about.title = Tietoja ICEpdf-katselusovelluksesta -viewer.dialog.about.pageNumber.label = \ - Lue uusimmat tiedot ICEpdf-verkkosivulta:\n\ - http://www.icepdf.org/ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Kirjanmerkit - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Huomautukset -viewer.utilityPane.link.appearanceTitle = Ulkonäkö -viewer.utilityPane.link.linkType = Linkin tyyppi: -viewer.utilityPane.annotation.link.highlightType = Korostustyyli: -viewer.utilityPane.link.lineThickness = Viivan paksuus: -viewer.utilityPane.link.lineStyle = Viivan tyyli: -viewer.utilityPane.link.colorChooserTitle = Huomautuksen väri -viewer.utilityPane.link.colorLabel = Väri: -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Toiminto -viewer.utilityPane.action.addAction = Lisää -viewer.utilityPane.action.editAction = Muokkaa -viewer.utilityPane.action.removeAction = Poista -viewer.utilityPane.action.type.destination.label = Kohde -viewer.utilityPane.action.type.uriAction.label = URI-toiminto -viewer.utilityPane.action.type.goToAction.label = Siirry-toiminto -viewer.utilityPane.action.dialog.new.title = Lisää uusi toiminto -viewer.utilityPane.action.dialog.new.msgs = Toiminnon tyyppi: -viewer.utilityPane.action.dialog.delete.title = Poista vahvistus -viewer.utilityPane.action.dialog.delete.msgs = Haluatko varmasti poistaa tämän toiminnon? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = URI-toiminnon ominaisuudet -viewer.utilityPane.action.dialog.uri.msgs = URI: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = Siirry-toiminnon ominaisuudet -viewer.utilityPane.action.dialog.goto.page.label = Sivu: -viewer.utilityPane.action.dialog.goto.type.label = Tyyppi -viewer.utilityPane.action.dialog.goto.type.xyz.label = Absoluuttinen -viewer.utilityPane.action.dialog.goto.type.fit.label = Sovita sivu -viewer.utilityPane.action.dialog.goto.type.fith.label = Sovita yläosan leveys -viewer.utilityPane.action.dialog.goto.type.fitv.label = Sovita vasemman puolen leveys -viewer.utilityPane.action.dialog.goto.type.fitr.label = Sovita zoomausruutu -viewer.utilityPane.action.dialog.goto.type.fitb.label = Sovita sivun rajat -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Sovita ylärajat -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Sovita vasemmat rajat -viewer.utilityPane.action.dialog.goto.right.label = Oikea: -viewer.utilityPane.action.dialog.goto.left.label = Vasen: -viewer.utilityPane.action.dialog.goto.top.label = Ylä: -viewer.utilityPane.action.dialog.goto.bottom.label = Ala: -viewer.utilityPane.action.dialog.goto.zoom.label = Zoomaus: -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Nykyinen näkymä: -viewer.utilityPane.action.dialog.goto.current = Aseta sijainti -viewer.utilityPane.action.dialog.goto.name.label = Nimi: -viewer.utilityPane.action.dialog.goto.browse = Selaa... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Oletuskohde -viewer.utilityPane.action.dialog.goto.nameDestination.title = Nimetty kohde -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Asiakirjan nimipuu -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Nimipuu -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} - {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Etsi -viewer.utilityPane.search.searchText.label = Etsi tekstiä: -viewer.utilityPane.search.results.label = Vastaukset: -viewer.utilityPane.search.searchButton.label = Etsi -viewer.utilityPane.search.clearSearchButton.label = Tyhjennä -viewer.utilityPane.search.caseSenstiveCheckbox.label = Sama kirjainkoko -viewer.utilityPane.search.wholeWordCheckbox.label = Vain kokonaiset sanat -viewer.utilityPane.search.cumlitiveCheckbox.label = Kumulatiivinen -viewer.utilityPane.search.showPagesCheckbox.label = Näytä sivut -viewer.utilityPane.search.stopButton.label = Pysäytä -viewer.utilityPane.search.searching.msg = Etsi... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = Etsitään kohdetta {0} / {1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} sivu -viewer.utilityPane.search.searching1.moreFile.msg = {2} sivua -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Sivu {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} tulos -viewer.utilityPane.search.result.moreFile.msg = {2} tulosta -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = Haettu {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = sivu -viewer.utilityPane.search.progress.morePage.msg = sivua -viewer.utilityPane.search.progress.oneMatch.msg = {2} vastaavuus -viewer.utilityPane.search.progress.moreMatch.msg = {2} vastaavuutta - -## Common Button Labels -viewer.button.ok.label = Ok -viewer.button.ok.mnemonic = O -viewer.button.cancel.label = Peruuta -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - ICEpdf Pilot -virhe -pilot.loading.msg =Avataan asiakirjaa {0}... -pilot.display.msg = Näytetään {0} -pilot.loading.error.msg = PDF Pilot: Asiakirjaa {0} ei voi ladata. -pilot.error.classLoading = Vaadittua luokkaa {0} ei löydy. Vaadittu kirjasto \ - 'icepdf.jar' ei mahdollisesti ole luokan polussa - PDF Pilot poistettu käytöstä."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - Käyttö: java org.icepdf.ri.viewer.Main [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf ei voinut avata määritettyä tiedostoa. {0} URL-osoitteessa: {1}. -viewer.launcher.lookAndFeel.error.message = Määritetty käyttötuntuma ({0}) ei ole mahdollinen tässä ympäristössä. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Ominaisuuksien jäsennysvirhe -parse.integer = Varoitus: {0} ei ole oikea kokonaisluku. -parse.float = Varoitus: {0} ei ole oikea liukuluku. -parse.double = Varoitus: {0} ei ole oikea double. -parse.choice = Varoitus: {0} ei ole oikea valinta. -parse.laf = Varoitus: käyttötuntumaa {0} ei tueta. - -### Properties Manager Errors -manager.properties.title = ICEpdf - Ominaisuuksien hallinta -fontManager.properties.title = ICEpdf - Fonttien hallinta - -manager.properties.createNewDirectory = \ - Luo hakemisto {0},\n\ - johon ICEpdf-katselusovellus tallentaa asetuksiin tehdyt muutokset, napsauttamalla Kyllä-painiketta.\n\n\ - Jos napsautat Ei-painiketta, kaikki ICEpdf-katselusovelluksen asetuksiin tekemäsi muutokset\n\ - häviävät, kun poistut sovelluksesta. - -manager.properties.failedCreation = \ - ICEpdf-katselusovelluksen hakemistoa käyttäjän tietojen tallentamista varten ei voi luoda:\n\ - {0}\n\ - ICEpdf-katselusovellus ei tallenna muutoksia oletusasetuksiinsa. - -manager.properties.session.nolock = \ - Virhe lukitustiedoston luomisessa:\n\ - {0}\n - -manager.properties.session.readError = \ - Virhe ominaisuustiedoston lataamisessa: \n\ - {0} - -manager.properties.deleted = Ominaisuustiedosto on poistettu\n\ - ({0})\n\ - Luodaanko se uudelleen? - -manager.properties.modified = Ominaisuustiedostoa on muutettu viimeisen päivityksen jälkeen\n\ - ({0,date,long})\n\ - Haluatko yhdistää muutokset tiedostoon nykyisten ominaisuuksien joukkoon? - -manager.properties.saveError = Ominaisuustiedostoa ei voi tallentaa.\n\ - Esiintyi seuraava virhe:\n\ - {0} - -manager.properties.lafError = \ - Oletusominaisuuksissa annettua käyttötuntumaa {0} ei tueta.\n\ - Käytetään järjestelmän oletusarvoja. - -manager.properties.brokenProperty = Virheellinen oletusominaisuuden {0} arvo: {1} - -manager.properties.missingProperty = Puuttuva oletusominaisuuden {0} arvo: {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_fr.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_fr.properties deleted file mode 100644 index ec45d6f02e..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_fr.properties +++ /dev/null @@ -1,479 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf Viewer -viewer.window.title.open.default = ICEpdf Viewer - [{0}] - -#status bar -viewer.statusbar.currentPage = Page {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Masquer la barre d'outils -viewer.toolbar.showToolBar.label = Afficher la barre d'outils -viewer.toolbar.showUtilityPane.label = Afficher le panneau Utilitaires -viewer.toolbar.hideUtilityPane.label = Masquer le panneau Utilitaires -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Ouvrir un classeur -viewer.toolbar.saveAs.label = Enregistrer sous -viewer.toolbar.saveAs.tooltip = Enregistrer sous... -viewer.toolbar.print.label = Imprimer -viewer.toolbar.print.tooltip = Imprimer le classeur -viewer.toolbar.search.label = Rechercher -viewer.toolbar.search.tooltip = Rechercher le classeur -viewer.toolbar.utilityPane.label = Panneau Utilitaires -viewer.toolbar.utilityPane.tooltip = Afficher/Masquer le panneau Utilitaires -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Nombre de pages -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = Numéro de la page en cours -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Première page -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Page précédente -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Page suivante -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Dernière page -viewer.toolbar.pageIndicator = de {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zoom -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Zoom arrière -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Zoom avant -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Taille réelle -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = Ajuster à la fenêtre -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Ajuster la largeur -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Pivoter Gauche -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Pivoter Droite -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Outil de sélection de Texte -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Outil de sélection de Texte -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Outil de sélection -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Outil d'annotation de lien -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Outil Zoom avant -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Outil Zoom arrière -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Activer/Désactiver le moteur de polices - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Vue page simple non continue -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Vue page double non continue -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Vue page simple continue -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Vue page double continue - - -## File Menu and submenu items -viewer.menu.file.label = Fichier -viewer.menu.file.mnemonic = F -viewer.menu.open.label = Ouvrir -viewer.menu.open.file.label = Fichier... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Fermer -viewer.menu.saveAs.label = Enregistrer sous... -viewer.menu.exportText.label = Exporter le texte... -viewer.menu.documentProperties.label=Informations sur le classeur... -viewer.menu.documentPermission.label = Permissions pour le classeur... -viewer.menu.documentInformation.label = Informations sur le classeur... -viewer.menu.printSetup.label = Configuration de l'imprimante…... -viewer.menu.print.label = Imprimer... -viewer.menu.exit.label = Quitter - -## View Menu and submenu items -viewer.menu.edit.label = Édition -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Annuler -viewer.menu.edit.redo.label = Rétablir -viewer.menu.edit.copy.label = Copier -viewer.menu.edit.delete.label = Supprimer -viewer.menu.edit.selectAll.label = Tout sélectionner -viewer.menu.edit.deselectAll.label = Annuler la sélection de tous les éléments -## View Menu and submenu items -viewer.menu.view.label = Affichage -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = Taille réelle -viewer.menu.view.fitInWindow.label = Ajuster à la fenêtre -viewer.menu.view.fitWidth.label = Ajuster la largeur -viewer.menu.view.zoomIn.label = Zoom avant -viewer.menu.view.zoomOut.label = Zoom arrière -viewer.menu.view.rotateLeft.label = Pivoter Gauche -viewer.menu.view.rotateRight.label = Pivoter Droite -viewer.menu.view.hideToolBar.label = Masquer la barre d'outils -viewer.menu.view.showToolBar.label = Afficher la barre d'outils -viewer.menu.view.showUtilityPane.label = Afficher le panneau Utilitaires -viewer.menu.view.hideUtilityPane.label = Masquer le panneau Utilitaires - -## Document Menu and submenu items -viewer.menu.document.label = Classeur -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Première page -viewer.menu.document.previousPage.label = Page précédente -viewer.menu.document.nextPage.label = Page suivante -viewer.menu.document.lastPage.label = Dernière page -viewer.menu.document.search.label = Rechercher... -viewer.menu.document.gotToPage.label = Aller à la Page... - -## Window Menu and submenu items -viewer.menu.window.label = Fenêtre -viewer.menu.window.mnemonic = W -viewer.menu.window.minAll.label = Tout réduire -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = Tout afficher au premier plan -viewer.menu.window.frontAll.mnemonic = B -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Aide -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = À propos de ICEpdf viewer... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Exception -viewer.dialog.error.exception.msg = \ - Une erreur s'est produite lors de l'exécution de la commande en raison de l'exception suivante\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Ouvrir un fichier -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Erreur d'ouverture de fichier -viewer.dialog.openFile.error.msg = \ - ICEpdf n'est pas parvenu à ouvrir le fichier spécifié stocké dans {0}\n\ - Ce fichier est peut-être endommagé ou son type n'est pas pris en charge. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - Exception PDF -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf n'est pas parvenu à ouvrir le fichier spécifié {0}\n\ - Ce fichier est peut-être endommagé ou son type n'est pas pris en charge. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - Exception de protection PDF -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf n'est pas parvenu à ouvrir le fichier crypté stocké dans {0}\n\ - Cela peut être dû à la saisie d'un mot de passe incorrect ou à l'absence d'un fournisseur de protection JCE.\n\n\ - Pour des informations plus complètes, reportez-vous au Guide du développeur ICEpdf. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Exception -viewer.dialog.openDocument.exception.msg = \ - ICEpdf n'est pas parvenu à ouvrir le fichier spécifié stocké dans {0}\n\ - Ce fichier est peut-être endommagé ou son type n'est pas pris en charge. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - Exception URL -viewer.dialog.openURL.exception.msg = \ - ICEpdf n'est pas parvenu à ouvrir le fichier spécifié. {0} \n\ - à l'URL : {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Information -viewer.dialog.information.copyAll.msg = \ - Ce classeur comporte plus de {0} pages. Utilisez l'option\n\ - "Exporter le texte..." pour extraire le texte du classeur. - -## Open URL Dialog -viewer.dialog.security.title = Protection du classeur -viewer.dialog.security.msg = Ce fichier PDF est protégé -viewer.dialog.security.password.label = Mot de passe : -viewer.dialog.security.okButton.label = OK -viewer.dialog.security.okButton.mnemonic = O -viewer.dialog.security.cancelButton.label = Annuler -viewer.dialog.security.cancelButton.mnemonic = C - -## Open URL Dialog -viewer.dialog.openURL.title = Ouvrir l'URL - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Enregistrer sous -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Erreur d'enregistrement -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf n'a pas pu procéder à l'enregistrement des données dans {0} car le type de fichier n'est pas pris en charge. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Erreur d'enregistrement -viewer.dialog.saveAs.noExtensionError.msg = Vous devez spécifier une extension de fichier. - - -## Export Text Dialog -viewer.dialog.exportText.title = Exporter le texte du classeur -viewer.dialog.exportText.progress.msg = Extraction du texte PDF -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Erreur d'enregistrement -viewer.dialog.exportText.noExtensionError.msg = Vous devez spécifier une extension de fichier. -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = {0} traité(es) sur {1}. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} page -viewer.exportText.fileStamp.progress.moreFile.msg = {2} pages - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Page {0} sur {1} -viewer.dialog.printing.status.start.msg = Mise en file d'attente d'impression des pages - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Permissions pour le classeur -viewer.dialog.documentPermissions.securityMethod.label = Méthode de protection : -viewer.dialog.documentPermissions.userPassword.label = Mot de passe utilisateur : -viewer.dialog.documentPermissions.ownerPassword.label = Mot de passe propriétaire : -viewer.dialog.documentPermissions.printing.label = Impression : -viewer.dialog.documentPermissions.changing.label = Modification du classeur : -viewer.dialog.documentPermissions.copyExtraction.label = Copie ou extraction du contenu : -viewer.dialog.documentPermissions.comments.label = Commentaires de création et champs du formulaire : -viewer.dialog.documentPermissions.formFillingIn.label = Remplissage ou signature des champs du formulaire : -viewer.dialog.documentPermissions.accessibility.label = Accès au contenu activé : -viewer.dialog.documentPermissions.assembly.label = Assemblage du classeur : -viewer.dialog.documentPermissions.encryptionLevel.label = Niveau de chiffrement : -viewer.dialog.documentPermissions.securityLevel = {0}-bit v{1} R {2} -viewer.dialog.documentPermissions.none = Aucun(e) -viewer.dialog.documentPermissions.no = Non -viewer.dialog.documentPermissions.yes = Oui -viewer.dialog.documentPermissions.allowed = Autorisé -viewer.dialog.documentPermissions.notAllowed = Non autorisé -viewer.dialog.documentPermissions.fullyAllowed = Totalement autorisé -viewer.dialog.documentPermissions.standardSecurity = Protection standard Adobe Acrobat -viewer.dialog.documentPermissions.partial = Partiel (faible qualité) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = Informations sur le classeur -viewer.dialog.documentInformation.title.label = Titre : -viewer.dialog.documentInformation.subject.label = Objet : -viewer.dialog.documentInformation.author.label = Auteur : -viewer.dialog.documentInformation.keywords.label = Mots clés : -viewer.dialog.documentInformation.creator.label = Créateur : -viewer.dialog.documentInformation.producer.label = Producteur : -viewer.dialog.documentInformation.created.label = Date de création : -viewer.dialog.documentInformation.modified.label = Date de modification : -viewer.dialog.documentInformation.notAvailable = Non disponible - -## Go to Page Dialog -viewer.dialog.goToPage.title = Aller à la Page... -viewer.dialog.goToPage.description.label = Numéro de page - -## About Dialog -viewer.dialog.about.title = À propos de ICEpdf Viewer -viewer.dialog.about.pageNumber.label = \ - Pour les dernières nouveautés, consultez le site Web de ICEpdf :\n\ - http://www.icepdf.org/ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Signets - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Annotations -viewer.utilityPane.link.appearanceTitle = Aspect -viewer.utilityPane.link.linkType = Type de lien : -viewer.utilityPane.annotation.link.highlightType = Style de mise en surbrillance : -viewer.utilityPane.link.lineThickness = Épaisseur du trait : -viewer.utilityPane.link.lineStyle = Style du trait : -viewer.utilityPane.link.colorChooserTitle = Couleur d'annotation -viewer.utilityPane.link.colorLabel = Couleur : -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Action -viewer.utilityPane.action.addAction = Ajouter -viewer.utilityPane.action.editAction = Éditer -viewer.utilityPane.action.removeAction = Supprimer -viewer.utilityPane.action.type.destination.label = Destination -viewer.utilityPane.action.type.uriAction.label = Action URI -viewer.utilityPane.action.type.goToAction.label = Aller à l'action -viewer.utilityPane.action.dialog.new.title = Ajouter une action -viewer.utilityPane.action.dialog.new.msgs = Type d'action : -viewer.utilityPane.action.dialog.delete.title = Confirmation de suppression -viewer.utilityPane.action.dialog.delete.msgs = Êtes-vous certain de vouloir supprimer cette action ? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = Propriétés de l'action URI -viewer.utilityPane.action.dialog.uri.msgs = URI : -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = Aller aux propriétés de l'action -viewer.utilityPane.action.dialog.goto.page.label = Page : -viewer.utilityPane.action.dialog.goto.type.label = Type -viewer.utilityPane.action.dialog.goto.type.xyz.label = Absolu -viewer.utilityPane.action.dialog.goto.type.fit.label = Ajuster la page -viewer.utilityPane.action.dialog.goto.type.fith.label = Ajuster la largeur supérieure -viewer.utilityPane.action.dialog.goto.type.fitv.label = Ajuster la largeur de gauche -viewer.utilityPane.action.dialog.goto.type.fitr.label = Ajuster Zoom - Boîte -viewer.utilityPane.action.dialog.goto.type.fitb.label = Ajuster les limites de page -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Ajuster les limites supérieures -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Ajuster les limites de gauche -viewer.utilityPane.action.dialog.goto.right.label = Droite : -viewer.utilityPane.action.dialog.goto.left.label = Gauche : -viewer.utilityPane.action.dialog.goto.top.label = Haut : -viewer.utilityPane.action.dialog.goto.bottom.label = Bas : -viewer.utilityPane.action.dialog.goto.zoom.label = Zoom : -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Vue actuelle : -viewer.utilityPane.action.dialog.goto.current = Définir l'emplacement -viewer.utilityPane.action.dialog.goto.name.label = Nom : -viewer.utilityPane.action.dialog.goto.browse = Parcourir... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Destination implicite -viewer.utilityPane.action.dialog.goto.nameDestination.title = Destination désignée -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Arborescence des noms de classeurs -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Arborescence de noms -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} à {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Rechercher -viewer.utilityPane.search.searchText.label = Texte recherché : -viewer.utilityPane.search.results.label = RÉSULTAT : -viewer.utilityPane.search.searchButton.label = Rechercher -viewer.utilityPane.search.clearSearchButton.label = Effacer -viewer.utilityPane.search.caseSenstiveCheckbox.label = Respect des majuscules/minuscules -viewer.utilityPane.search.wholeWordCheckbox.label = Mots entiers uniquement -viewer.utilityPane.search.cumlitiveCheckbox.label = Cumulatif -viewer.utilityPane.search.showPagesCheckbox.label = Afficher les pages -viewer.utilityPane.search.stopButton.label = Arrêter -viewer.utilityPane.search.searching.msg = Rechercher... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = Recherche de {0} sur {1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} page -viewer.utilityPane.search.searching1.moreFile.msg = {2} pages -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Page {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} résultat -viewer.utilityPane.search.result.moreFile.msg = {2} résultats -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = Recherche effectuée dans {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = page -viewer.utilityPane.search.progress.morePage.msg = pages -viewer.utilityPane.search.progress.oneMatch.msg = {2} correspondance -viewer.utilityPane.search.progress.moreMatch.msg = {2} correspondances - -## Common Button Labels -viewer.button.ok.label = OK -viewer.button.ok.mnemonic = O -viewer.button.cancel.label = Annuler -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - Erreur de pilote ICEpdf -pilot.loading.msg =Ouverture du classeur {0}... -pilot.display.msg = Affichage de {0} -pilot.loading.error.msg = Pilote PDF : Échec de chargement de {0}. -pilot.error.classLoading = Classe requise {0} introuvable. La bibliothèque requise \ - 'icepdf.jar' ne figure peut-être pas dans le chemin d'accès à la classe - Pilote PDF désactivé."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - Utilisation : java org.icepdf.ri.Viewer.Main [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf n'est pas parvenu à ouvrir le fichier spécifié. {0} à l'URL : {1}. -viewer.launcher.lookAndFeel.error.message = L'apparence ({0}) spécifiée n'est pas accessible à partir de cette plate-forme. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Erreur d'analyse des propriétés -parse.integer = Attention : {0} n'est pas un entier correct. -parse.float = Attention : {0} n'est pas une valeur flottante correcte. -parse.double = Attention : {0} n'est pas un double correct. -parse.choice = Attention : {0} n'est pas un choix valide. -parse.laf = Attention : l'apparence {0} n'est pas prise en charge. - -### Properties Manager Errors -manager.properties.title = Gestionnaire de propriétés ICEpdf -fontManager.properties.title = Gestionnaire de polices ICEpdf - -manager.properties.createNewDirectory = \ - Pour créer le répertoire {0},\n\ - dans lequel ICEpdf va stocker les modifications apportées à sa configuration, cliquez sur Oui.\n\n\ - Si vous cliquez sur "Non", tous les changements que vous apportez à la configuration de ICEpdf Viewer\n\ - seront perdues lorsque vous quitterez l'application. - -manager.properties.failedCreation = \ - Le répertoire ICEpdf à utiliser pour le stockage des données utilisateur n'a pas pu être créé :\n\ - {0}\n\ - ICEpdf Viewer ne va pas enregistrer les modifications apportées à sa configuration par défaut. - -manager.properties.session.nolock = \ - Erreur de création du fichier de verrouillage :\n\ - {0} - -manager.properties.session.readError = \ - Erreur de chargement du fichier de propriétés : \n\ - {0} - -manager.properties.deleted = Le fichier de propriétés a été supprimé \n\ - ({0})\n\ - Voulez-vous en créer un nouveau ? - -manager.properties.modified = Le fichier de propriétés a été modifié depuis la dernière mise à jour\n\ - ({0,date,long})\n\ - Voulez-vous fusionner les modifications apportées au fichier et les propriétés actuelles ? - -manager.properties.saveError = Impossible d'enregistrer le fichier de propriétés.\n\ - L'erreur suivante a été détectée :\n\ - {0} - -manager.properties.lafError = \ - L'apparence {0} spécifiée dans les propriétés par défaut n'est pas prise en charge.\n\ - Utilisation des valeurs par défaut du système. - -manager.properties.brokenProperty = Valeur interrompue de la propriété par défaut {0} : {1} - -manager.properties.missingProperty = Valeur manquante de la propriété par défaut {0} : {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_it.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_it.properties deleted file mode 100644 index 496d2c5955..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_it.properties +++ /dev/null @@ -1,467 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf Viewer -viewer.window.title.open.default = ICEpdf Viewer - [{0}] - -#status bar -viewer.statusbar.currentPage = Pag. {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Nascondi barra strumenti -viewer.toolbar.showToolBar.label = Mostra barra strumenti -viewer.toolbar.showUtilityPane.label = Mostra pannello Utilità -viewer.toolbar.hideUtilityPane.label = Nascondi pannello Utilità -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Apri documento -viewer.toolbar.saveAs.label = Salva con nome -viewer.toolbar.saveAs.tooltip = Salva con nome... -viewer.toolbar.print.label = Stampa -viewer.toolbar.print.tooltip = Stampa documento -viewer.toolbar.search.label = Cerca -viewer.toolbar.search.tooltip = Cerca nel documento -viewer.toolbar.utilityPane.label = Pannello Utilità -viewer.toolbar.utilityPane.tooltip = Mostra/Nascondi pannello Utilità -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Numero di pagine -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = Numero di pagina corrente -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Prima pagina -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Pagina precedente -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Pagina successiva -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Ultima pagina -viewer.toolbar.pageIndicator = di {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zoom -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Zoom indietro -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Zoom avanti -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Dimensioni effettive -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = Adatta alla finestra -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Adatta alla larghezza -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Ruota a sinistra -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Ruota a destra -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Strumento Seleziona testo -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Strumento Seleziona testo -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Strumento Seleziona -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Strumento Collega annotazione -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Strumento Zoom avanti -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Strumento Zoom indietro -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Abilita/Disabilita motore caratteri - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Vista pagina singola, non continua -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Vista pagine affiancate, non continua -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Vista pagina singola, continua -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Vista pagine affiancate, continua - - -## File Menu and submenu items -viewer.menu.file.label = File -viewer.menu.file.mnemonic = F -viewer.menu.open.label = Apri -viewer.menu.open.file.label = File... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Chiudi -viewer.menu.saveAs.label = Salva con nome... -viewer.menu.exportText.label = Esporta testo... -viewer.menu.documentProperties.label=Informazioni sul documento... -viewer.menu.documentPermission.label = Permessi del documento... -viewer.menu.documentInformation.label = Informazioni sul documento... -viewer.menu.printSetup.label = Imposta pagina... -viewer.menu.print.label = Stampa... -viewer.menu.exit.label = Esci - -## View Menu and submenu items -viewer.menu.edit.label = Modifica -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Annulla -viewer.menu.edit.redo.label = Ripeti -viewer.menu.edit.copy.label = Copia -viewer.menu.edit.delete.label = Rimuovi -viewer.menu.edit.selectAll.label = Seleziona tutto -viewer.menu.edit.deselectAll.label = Deseleziona tutto -## View Menu and submenu items -viewer.menu.view.label = Visualizza -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = Dimensioni effettive -viewer.menu.view.fitInWindow.label = Adatta alla finestra -viewer.menu.view.fitWidth.label = Adatta alla larghezza -viewer.menu.view.zoomIn.label = Zoom avanti -viewer.menu.view.zoomOut.label = Zoom indietro -viewer.menu.view.rotateLeft.label = Ruota a sinistra -viewer.menu.view.rotateRight.label = Ruota a destra -viewer.menu.view.hideToolBar.label = Nascondi barra strumenti -viewer.menu.view.showToolBar.label = Mostra barra strumenti -viewer.menu.view.showUtilityPane.label = Mostra pannello Utilità -viewer.menu.view.hideUtilityPane.label = Nascondi pannello Utilità - -## Document Menu and submenu items -viewer.menu.document.label = Documenti -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Prima pagina -viewer.menu.document.previousPage.label = Pagina precedente -viewer.menu.document.nextPage.label = Pagina successiva -viewer.menu.document.lastPage.label = Ultima pagina -viewer.menu.document.search.label = Cerca... -viewer.menu.document.gotToPage.label = Vai a pagina... - -## Window Menu and submenu items -viewer.menu.window.label = Finestra -viewer.menu.window.mnemonic = W -viewer.menu.window.minAll.label = Riduci tutto a icona -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = Porta tutto in primo piano -viewer.menu.window.frontAll.mnemonic = b -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Guida -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = Informazioni su ICEpdf viewer... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Eccezione -viewer.dialog.error.exception.msg = \ - Si è verificato un errore durante l'esecuzione del comando per la seguente eccezione\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Apri file -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Errore durante l'apertura del file -viewer.dialog.openFile.error.msg = \ - ICEpdf non ha potuto aprire il file specificato in {0} \n\ - Il file potrebbe essere danneggiato oppure di un tipo non supportato. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - Eccezione PDF -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf non ha potuto aprire il file specificato {0}\n\ - Il file potrebbe essere danneggiato oppure di un tipo non supportato. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - Eccezione sicurezza PDF -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf non ha potuto aprire il file criptato in {0} \n\ - Ciò potrebbe essere dovuto a una password non valida o all'assenza del Provider di sicurezza JCE.\n\n\ - Per ulteriori informazioni, fare riferimento alla Guida per lo sviluppatore ICEpdf. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Eccezione -viewer.dialog.openDocument.exception.msg = \ - ICEpdf non ha potuto aprire il file specificato in {0}\n\ - Il file potrebbe essere danneggiato oppure di un tipo non supportato. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - Eccezione URL -viewer.dialog.openURL.exception.msg = \ - ICEpdf non ha potuto aprire il file specificato. {0} \n\ - nell'URL: {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Informazioni -viewer.dialog.information.copyAll.msg = \ - Il documento contiene più di {0} pagine, utilizzare \n\ - la funzione "Esporta testo..." per estrarre il testo del documento. - -## Open URL Dialog -viewer.dialog.security.title = Sicurezza del documento -viewer.dialog.security.msg = Questo PDF è protetto -viewer.dialog.security.password.label = Password: -viewer.dialog.security.okButton.label = OK -viewer.dialog.security.okButton.mnemonic = O -viewer.dialog.security.cancelButton.label = Annulla -viewer.dialog.security.cancelButton.mnemonic = C - -## Open URL Dialog -viewer.dialog.openURL.title = Apri URL - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Salva con nome -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Errore durante il salvataggio -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf non ha potuto salvare in {0} perché non è un tipo di file supportato. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Errore durante il salvataggio -viewer.dialog.saveAs.noExtensionError.msg = Specificare un estensione per il file. - -## Export Text Dialog -viewer.dialog.exportText.title = Esporta testo documento -viewer.dialog.exportText.progress.msg = Estrazione testo dal PDF -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Errore durante il salvataggio -viewer.dialog.exportText.noExtensionError.msg = Specificare un estensione per il file. -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = Completate {0} di {1}. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} pagina -viewer.exportText.fileStamp.progress.moreFile.msg = {2} pagine - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Pagina {0} di {1} -viewer.dialog.printing.status.start.msg = Spooling della/e pagina/e sulla stampante - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Permessi del documento -viewer.dialog.documentPermissions.securityMethod.label = Metodo di sicurezza: -viewer.dialog.documentPermissions.userPassword.label = Password utente: -viewer.dialog.documentPermissions.ownerPassword.label = Password proprietario: -viewer.dialog.documentPermissions.printing.label = Stampa: -viewer.dialog.documentPermissions.changing.label = Modifica del documento: -viewer.dialog.documentPermissions.copyExtraction.label = Copia o estrazione del contenuto: -viewer.dialog.documentPermissions.comments.label = Creazione di commenti e campi del modulo: -viewer.dialog.documentPermissions.formFillingIn.label = Compilazione dei campi del modulo o firma: -viewer.dialog.documentPermissions.accessibility.label = Accessibilità contenuto abilitata: -viewer.dialog.documentPermissions.assembly.label = Creazione documento: -viewer.dialog.documentPermissions.encryptionLevel.label = Livello crittografia: -viewer.dialog.documentPermissions.securityLevel = {0}-bit v{1} R {2} -viewer.dialog.documentPermissions.none = Nessuno -viewer.dialog.documentPermissions.no = No -viewer.dialog.documentPermissions.yes = Sì -viewer.dialog.documentPermissions.allowed = Consentito -viewer.dialog.documentPermissions.notAllowed = Non consentito -viewer.dialog.documentPermissions.fullyAllowed = Totalmente consentito -viewer.dialog.documentPermissions.standardSecurity = Sicurezza standard Adobe Acrobat -viewer.dialog.documentPermissions.partial = Parziale (Bassa qualità) - -## Document Information Dialog -viewer.dialog.documentInformation.title = Informazioni sul documento -viewer.dialog.documentInformation.title.label = Titolo: -viewer.dialog.documentInformation.subject.label = Oggetto: -viewer.dialog.documentInformation.author.label = Autore: -viewer.dialog.documentInformation.keywords.label = Parole chiave: -viewer.dialog.documentInformation.creator.label = Creatore: -viewer.dialog.documentInformation.producer.label = Produttore: -viewer.dialog.documentInformation.created.label = Creato: -viewer.dialog.documentInformation.modified.label = Modificato: -viewer.dialog.documentInformation.notAvailable = Non disponibile - -## Go to Page Dialog -viewer.dialog.goToPage.title = Vai a pagina... -viewer.dialog.goToPage.description.label = Numero di pagina - -## About Dialog -viewer.dialog.about.title = Informazioni su Visualizzatore ICEpdf -viewer.dialog.about.pageNumber.label = \ - Visitare il sito web ICEpdf per le notizie più aggiornate:\n\ - http://www.icepdf.org/ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Segnalibri - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Annotazioni -viewer.utilityPane.link.appearanceTitle = Aspetto -viewer.utilityPane.link.linkType = Tipo di collegamento: -viewer.utilityPane.annotation.link.highlightType = Stile evidenziazione: -viewer.utilityPane.link.lineThickness = Spessore linea: -viewer.utilityPane.link.lineStyle = Stile linea: -viewer.utilityPane.link.colorChooserTitle = Colore annotazione -viewer.utilityPane.link.colorLabel = Colore: -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Azione -viewer.utilityPane.action.addAction = Aggiungi -viewer.utilityPane.action.editAction = Modifica -viewer.utilityPane.action.removeAction = Rimuovi -viewer.utilityPane.action.type.destination.label = Destinazione -viewer.utilityPane.action.type.uriAction.label = Azione URI -viewer.utilityPane.action.type.goToAction.label = Vai a azione -viewer.utilityPane.action.dialog.new.title = Aggiungi nuova azione -viewer.utilityPane.action.dialog.new.msgs = Tipo azione: -viewer.utilityPane.action.dialog.delete.title = Elimina conferma -viewer.utilityPane.action.dialog.delete.msgs = Eliminare questa azione? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = Proprietà azione URI -viewer.utilityPane.action.dialog.uri.msgs = URI: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = Vai a proprietà azione -viewer.utilityPane.action.dialog.goto.page.label = Pagina: -viewer.utilityPane.action.dialog.goto.type.label = Tipo -viewer.utilityPane.action.dialog.goto.type.xyz.label = Assoluto -viewer.utilityPane.action.dialog.goto.type.fit.label = Adatta pagina -viewer.utilityPane.action.dialog.goto.type.fith.label = Adatta larghezza superiore -viewer.utilityPane.action.dialog.goto.type.fitv.label = Adatta larghezza sinistra -viewer.utilityPane.action.dialog.goto.type.fitr.label = Adatta Zoom riquadro -viewer.utilityPane.action.dialog.goto.type.fitb.label = Adatta limiti pagina -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Adatta limiti superiori -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Adatta limiti sinistra -viewer.utilityPane.action.dialog.goto.right.label = Destra: -viewer.utilityPane.action.dialog.goto.left.label = Sinistra: -viewer.utilityPane.action.dialog.goto.top.label = Alto: -viewer.utilityPane.action.dialog.goto.bottom.label = Basso: -viewer.utilityPane.action.dialog.goto.zoom.label = Zoom: -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Vista corrente: -viewer.utilityPane.action.dialog.goto.current = Imposta ubicazione -viewer.utilityPane.action.dialog.goto.name.label = Nome: -viewer.utilityPane.action.dialog.goto.browse = Sfoglia... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Destinazione implicita -viewer.utilityPane.action.dialog.goto.nameDestination.title = Destinazione denominata -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Struttura nomi documento -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Struttura nomi -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} a {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Cerca -viewer.utilityPane.search.searchText.label = Cerca testo: -viewer.utilityPane.search.results.label = Risultati: -viewer.utilityPane.search.searchButton.label = Cerca -viewer.utilityPane.search.clearSearchButton.label = Cancella -viewer.utilityPane.search.caseSenstiveCheckbox.label = Maiuscolo/minuscolo -viewer.utilityPane.search.wholeWordCheckbox.label = Solo parole intere -viewer.utilityPane.search.cumlitiveCheckbox.label = Cumulativo -viewer.utilityPane.search.showPagesCheckbox.label = Mostra pagine -viewer.utilityPane.search.stopButton.label = Stop -viewer.utilityPane.search.searching.msg = Cerca... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = Cerca {0} di {1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} pagina -viewer.utilityPane.search.searching1.moreFile.msg = {2} pagine -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Pagina {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} risultato -viewer.utilityPane.search.result.moreFile.msg = {2} risultati -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = Cercati {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = pagina -viewer.utilityPane.search.progress.morePage.msg = pagine -viewer.utilityPane.search.progress.oneMatch.msg = {2} corrispondenza -viewer.utilityPane.search.progress.moreMatch.msg = {2} corrispondenze - -## Common Button Labels -viewer.button.ok.label = OK -viewer.button.ok.mnemonic = O -viewer.button.cancel.label = Annulla -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - Errore ICEpdf Pilot -pilot.loading.msg =Apertura documento {0} ... -pilot.display.msg = Visualizzazione {0} -pilot.loading.error.msg = PDF Pilot: Impossibile caricare {0}. -pilot.error.classLoading = Impossibile trovare la classe richiesta {0}. La libreria richiesta \ - 'icepdf.jar' potrebbe non essere nel percorso della classe - PDF Pilot disabilitato."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - Utilizzo: java org.icepdf.ri.visualizzatore.Main [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf non ha potuto aprire il file specificato. {0} nell'URL: {1}. -viewer.launcher.lookAndFeel.error.message = Il look-and-feel specificato ({0}) non è accessibile da questa piattaforma. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Errore di analisi delle proprietà -parse.integer = Attenzione: {0} non è un intero corretto. -parse.float = Attenzione: {0} non è un decimale corretto. -parse.double = Attenzione: {0} non è un doppio corretto. -parse.choice = Attenzione: {0} non è una scelta valida. -parse.laf = Attenzione: il look-and-feel {0} non è supportato. - -### Properties Manager Errors -manager.properties.title = Gestione proprietà ICEpdf -fontManager.properties.title = Gestione caratteri ICEpdf - -manager.properties.createNewDirectory = \ - Per creare la directory {0},\n\ - dove ICEpdf Viewer memorizzerà le modifiche alla sua configurazione, fare clic su Sì.\n\n\ - Se si fa clic su "No", tutte le modifiche apportate alla configurazione di ICEpdf Viewer \n\ - andranno perdute alla chiusura dell'applicazione. - -manager.properties.failedCreation = \ - Impossibile creare la directory di ICEpdf Viewer per la memorizzazione dei dati utente:\n\ - {0}\n\ - ICEpdf Viewer non salverà le modifiche alla sua configurazione predefinita. - -manager.properties.session.nolock = \ - Errore durante la creazione del file lock:\n\ - {0} - -manager.properties.session.readError = \ - Errore durante la creazione del file delle proprietà: \n\ - {0} - -manager.properties.deleted = Il file delle proprietà è stato eliminato\n\ - ({0})\n\ - Ricrearlo? - -manager.properties.modified = Il file delle proprietà è stato modificato dall'ultimo aggiornamento\n\ - ({0,date,long})\n\ - Unire le modifiche presenti nel file con le proprietà correnti? - -manager.properties.saveError = Impossibile salvare il file delle proprietà.\n\ - È stato incontrato il seguente errore:\n\ - {0} - -manager.properties.lafError = \ - Il Look&Feel {0} indicato nelle proprietà predefinite non è supportato.\n\ - Utilizzo delle impostazioni predefinite del sistema. - -manager.properties.brokenProperty = Valore proprietà predefinita {0} interrotto: {1} - -manager.properties.missingProperty = Valore proprietà predefinita {0} assente: {1} \ No newline at end of file diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_nl.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_nl.properties deleted file mode 100644 index 8d00b9ef91..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_nl.properties +++ /dev/null @@ -1,481 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf Viewer -viewer.window.title.open.default = ICEpdf Viewer - [{0}] - -#status bar -viewer.statusbar.currentPage = Pag. {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Werkbalk verbergen -viewer.toolbar.showToolBar.label = Werkbalk weergeven -viewer.toolbar.showUtilityPane.label = Paneel met hulpprogramma's weergeven -viewer.toolbar.hideUtilityPane.label = Paneel met hulpprogramma's verbergen -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Document openen -viewer.toolbar.saveAs.label = Opslaan als -viewer.toolbar.saveAs.tooltip = Opslaan als... -viewer.toolbar.print.label = Afdrukken -viewer.toolbar.print.tooltip = Document afdrukken -viewer.toolbar.search.label = Zoeken -viewer.toolbar.search.tooltip = Document zoeken -viewer.toolbar.utilityPane.label = Hulpprogrammapaneel -viewer.toolbar.utilityPane.tooltip = Paneel met hulpprogramma's weergeven/verbergen -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Aantal pagina's -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = Huidige paginanummer -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Eerste pagina -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Vorige pagina -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Volgende pagina -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Laatste pagina -viewer.toolbar.pageIndicator = van {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zoomen -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Zoom uit -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Zoom in -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Werkelijke grootte -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = Passen in venster -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Passen in breedte -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Naar links draaien -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Naar rechts draaien -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Tekstselectie-tool -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Tekstselectie-tool -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Selectie-tool -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Link-annotatietool -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Inzoom-tool -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Uitzoom-tool -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Lettertype-engine inschakelen/uitschakelen - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Enkele pagina, niet-doorlopend -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Dubbele pagina, niet-doorlopend -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Enkele pagina, doorlopend -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Dubbele pagina, doorlopend - - -## File Menu and submenu items -viewer.menu.file.label = Bestand -viewer.menu.file.mnemonic = F -viewer.menu.open.label = Openen -viewer.menu.open.file.label = Bestand... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Sluiten -viewer.menu.saveAs.label = Opslaan als... -viewer.menu.exportText.label = Tekst exporteren... -viewer.menu.documentProperties.label=Documentinformatie... -viewer.menu.documentPermission.label = Documentrechten... -viewer.menu.documentInformation.label = Documentinformatie... -viewer.menu.printSetup.label = Afdrukinstellingen... -viewer.menu.print.label = Afdrukken... -viewer.menu.exit.label = Afsluiten - -## View Menu and submenu items -viewer.menu.edit.label = Bewerken -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Ongedaan maken -viewer.menu.edit.redo.label = Opnieuw -viewer.menu.edit.copy.label = Kopiëren -viewer.menu.edit.delete.label = Verwijderen -viewer.menu.edit.selectAll.label = Alles selecteren -viewer.menu.edit.deselectAll.label = Alles deselecteren -## View Menu and submenu items -viewer.menu.view.label = Beeld -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = Werkelijke grootte -viewer.menu.view.fitInWindow.label = Passen in venster -viewer.menu.view.fitWidth.label = Passen in breedte -viewer.menu.view.zoomIn.label = Zoom in -viewer.menu.view.zoomOut.label = Zoom uit -viewer.menu.view.rotateLeft.label = Naar links draaien -viewer.menu.view.rotateRight.label = Naar rechts draaien -viewer.menu.view.hideToolBar.label = Werkbalk verbergen -viewer.menu.view.showToolBar.label = Werkbalk weergeven -viewer.menu.view.showUtilityPane.label = Paneel met hulpprogramma's weergeven -viewer.menu.view.hideUtilityPane.label = Paneel met hulpprogramma's verbergen - -## Document Menu and submenu items -viewer.menu.document.label = Document -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Eerste pagina -viewer.menu.document.previousPage.label = Vorige pagina -viewer.menu.document.nextPage.label = Volgende pagina -viewer.menu.document.lastPage.label = Laatste pagina -viewer.menu.document.search.label = Zoeken... -viewer.menu.document.gotToPage.label = Ga naar pagina... - -## Window Menu and submenu items -viewer.menu.window.label = Venster -viewer.menu.window.mnemonic = W -viewer.menu.window.minAll.label = Alles minimaliseren -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = Alles naar voren brengen -viewer.menu.window.frontAll.mnemonic = B -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Help -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = Over de ICEpdf Viewer... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Uitzondering -viewer.dialog.error.exception.msg = \ - Er is een fout opgetreden bij het uitvoeren van uw commando door de volgende uitzondering\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Bestand openen -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Fout bij openen van bestand -viewer.dialog.openFile.error.msg = \ - ICEpdf kon het gespecificeerde bestand in {0} niet openen\n\ - Het bestand is mogelijk beschadigd of is van een niet-ondersteund bestandstype. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - PDF uitzondering -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf kon het gespecificeerde bestand {0} niet openen\n\ - Het bestand is mogelijk beschadigd of is van een niet-ondersteund bestandstype. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - PDF beveiligingsuitzondering -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf kon het versleutelde bestand in {0} niet openen\n\ - Dit kan het gevolg zijn van een ongeldig wachtwoord of een ontbrekende JCE beveiligingsprovider.\n\n\ - Raadpleeg voor meer informatie de ICEpdf Developer's Guide. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Uitzondering -viewer.dialog.openDocument.exception.msg = \ - ICEpdf kon het gespecificeerde bestand in {0} niet openen\n\ - Het bestand is mogelijk beschadigd of is van een niet-ondersteund bestandstype. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - URL uitzondering -viewer.dialog.openURL.exception.msg = \ - ICEpdf kon het gespecificeerde bestand niet openen. {0} \n\ - op URL: {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Informatie -viewer.dialog.information.copyAll.msg = \ - Het document heeft meer dan {0} pagina's, gebruik\n\ - "Tekst exporteren..." om tekst uit het document te verwijderen. - -## Open URL Dialog -viewer.dialog.security.title = Documentbeveiliging -viewer.dialog.security.msg = Deze PDF is beveiligd -viewer.dialog.security.password.label = Wachtwoord: -viewer.dialog.security.okButton.label = OK -viewer.dialog.security.okButton.mnemonic = O -viewer.dialog.security.cancelButton.label = Annuleren -viewer.dialog.security.cancelButton.mnemonic = C - -## Open URL Dialog -viewer.dialog.openURL.title = URL openen - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Opslaan als -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Fout bij opslaan -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf kon niet opslaan naar {0} omdat het geen ondersteund bestandstype is. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Fout bij opslaan -viewer.dialog.saveAs.noExtensionError.msg = Specificeer een bestandsextensie a.u.b. - - -## Export Text Dialog -viewer.dialog.exportText.title = Documenttekst exporteren -viewer.dialog.exportText.progress.msg = PDF-tekst extraheren -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Fout bij opslaan -viewer.dialog.exportText.noExtensionError.msg = Specificeer een bestandsextensie a.u.b. -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = {0} van {1} voltooid. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} pagina -viewer.exportText.fileStamp.progress.moreFile.msg = {2} pagina's - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Pag. {0} van {1} -viewer.dialog.printing.status.start.msg = Bezig met verzenden van pagina('s) naar printer - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Documentrechten -viewer.dialog.documentPermissions.securityMethod.label = Beveiligingsmethode: -viewer.dialog.documentPermissions.userPassword.label = Wachtwoord gebruiker: -viewer.dialog.documentPermissions.ownerPassword.label = Wachtwoord eigenaar: -viewer.dialog.documentPermissions.printing.label = Afdrukken: -viewer.dialog.documentPermissions.changing.label = Het document veranderen: -viewer.dialog.documentPermissions.copyExtraction.label = Kopiëren of knippen van inhoud: -viewer.dialog.documentPermissions.comments.label = Authoring-opmerkingen en formuliervelden: -viewer.dialog.documentPermissions.formFillingIn.label = Formuliervelden invullen of ondertekenen: -viewer.dialog.documentPermissions.accessibility.label = Toegankelijkheid inhoud ingeschakeld: -viewer.dialog.documentPermissions.assembly.label = Documentsamenstelling: -viewer.dialog.documentPermissions.encryptionLevel.label = Versleutelingsniveau: -viewer.dialog.documentPermissions.securityLevel = {0}-bit v{1} R {2} -viewer.dialog.documentPermissions.none = Geen -viewer.dialog.documentPermissions.no = Nee -viewer.dialog.documentPermissions.yes = Ja -viewer.dialog.documentPermissions.allowed = Toegestaan -viewer.dialog.documentPermissions.notAllowed = Niet toegestaan -viewer.dialog.documentPermissions.fullyAllowed = Volledig toegestaan -viewer.dialog.documentPermissions.standardSecurity = Standaardbeveiliging Adobe Acrobat -viewer.dialog.documentPermissions.partial = Partieel (lage kwaliteit) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = Documentinformatie -viewer.dialog.documentInformation.title.label = Titel: -viewer.dialog.documentInformation.subject.label = Onderwerp: -viewer.dialog.documentInformation.author.label = Auteur: -viewer.dialog.documentInformation.keywords.label = Trefwoorden: -viewer.dialog.documentInformation.creator.label = Maker: -viewer.dialog.documentInformation.producer.label = Producent: -viewer.dialog.documentInformation.created.label = Gemaakt: -viewer.dialog.documentInformation.modified.label = Gewijzigd: -viewer.dialog.documentInformation.notAvailable = Niet beschikbaar - -## Go to Page Dialog -viewer.dialog.goToPage.title = Ga naar pagina... -viewer.dialog.goToPage.description.label = Paginanummer - -## About Dialog -viewer.dialog.about.title = Over de ICEpdf Viewer -viewer.dialog.about.pageNumber.label = \ - Ga naar de ICEpdf website voor het laatste nieuws:\n\ - http://www.icepdf.org/ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Bladwijzers - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Annotaties -viewer.utilityPane.link.appearanceTitle = Uiterlijk -viewer.utilityPane.link.linkType = Type link: -viewer.utilityPane.annotation.link.highlightType = Type markering: -viewer.utilityPane.link.lineThickness = Lijndikte: -viewer.utilityPane.link.lineStyle = Lijntype: -viewer.utilityPane.link.colorChooserTitle = Annotatiekleur -viewer.utilityPane.link.colorLabel = Kleur: -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Actie -viewer.utilityPane.action.addAction = Toevoegen -viewer.utilityPane.action.editAction = Bewerken -viewer.utilityPane.action.removeAction = Verwijderen -viewer.utilityPane.action.type.destination.label = Bestemming -viewer.utilityPane.action.type.uriAction.label = URI actie -viewer.utilityPane.action.type.goToAction.label = Ga naar actie -viewer.utilityPane.action.dialog.new.title = Nieuwe actie toevoegen -viewer.utilityPane.action.dialog.new.msgs = Type actie: -viewer.utilityPane.action.dialog.delete.title = Wissen bevestigen -viewer.utilityPane.action.dialog.delete.msgs = Weet u zeker dat u deze actie wilt wissen? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = URI actie-eigenschappen -viewer.utilityPane.action.dialog.uri.msgs = URI: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = Ga naar actie-eigenschappen -viewer.utilityPane.action.dialog.goto.page.label = Pagina: -viewer.utilityPane.action.dialog.goto.type.label = Type -viewer.utilityPane.action.dialog.goto.type.xyz.label = Absoluut -viewer.utilityPane.action.dialog.goto.type.fit.label = Pagina passen -viewer.utilityPane.action.dialog.goto.type.fith.label = Passen in breedte bovenkant -viewer.utilityPane.action.dialog.goto.type.fitv.label = Passen in breedte links -viewer.utilityPane.action.dialog.goto.type.fitr.label = Passen in zoomvak -viewer.utilityPane.action.dialog.goto.type.fitb.label = Paginagrenzen passen -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Grenzen bovenkant passen -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Grenzen links passen -viewer.utilityPane.action.dialog.goto.right.label = Rechts: -viewer.utilityPane.action.dialog.goto.left.label = Links: -viewer.utilityPane.action.dialog.goto.top.label = Boven: -viewer.utilityPane.action.dialog.goto.bottom.label = Onder: -viewer.utilityPane.action.dialog.goto.zoom.label = Zoomen: -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Huidige weergave: -viewer.utilityPane.action.dialog.goto.current = Locatie instellen -viewer.utilityPane.action.dialog.goto.name.label = Naam: -viewer.utilityPane.action.dialog.goto.browse = Bladeren... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Impliciete bestemming -viewer.utilityPane.action.dialog.goto.nameDestination.title = Bestemming met naam -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Documentnamen-boomstructuur -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Namen-boomstructuur -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} tot {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Zoeken -viewer.utilityPane.search.searchText.label = Zoektekst: -viewer.utilityPane.search.results.label = Resultaten: -viewer.utilityPane.search.searchButton.label = Zoeken -viewer.utilityPane.search.clearSearchButton.label = Wissen -viewer.utilityPane.search.caseSenstiveCheckbox.label = Hoofdlettergevoelig -viewer.utilityPane.search.wholeWordCheckbox.label = Alleen hele woorden -viewer.utilityPane.search.cumlitiveCheckbox.label = Cumulatief -viewer.utilityPane.search.showPagesCheckbox.label = Pagina's weergeven -viewer.utilityPane.search.stopButton.label = Stoppen -viewer.utilityPane.search.searching.msg = Zoeken... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = \ - Bezig met zoeken van {0} van {1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} pagina -viewer.utilityPane.search.searching1.moreFile.msg = {2} pagina's -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Pag. {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} resultaat -viewer.utilityPane.search.result.moreFile.msg = {2} resultaten -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = \ - Gezocht {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = pagina -viewer.utilityPane.search.progress.morePage.msg = pagina's -viewer.utilityPane.search.progress.oneMatch.msg = {2} match -viewer.utilityPane.search.progress.moreMatch.msg = {2} matches - -## Common Button Labels -viewer.button.ok.label = OK -viewer.button.ok.mnemonic = O -viewer.button.cancel.label = Annuleren -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - ICEpdf Pilotfout -pilot.loading.msg = Bezig met openen van document {0} ... -pilot.display.msg = Bezig met weergeven van {0} -pilot.loading.error.msg = PDF Pilot: Kon {0} niet laden. -pilot.error.classLoading = Vereiste klas {0} niet gevonden. Vereiste bibliotheek \ - 'icepdf.jar' staat mogelijk niet in het klaspad - PDF Pilot uitgeschakeld."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - Gebruik: java org.icepdf.ri.viewer.Hoofdmenu [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf kon het gespecificeerde bestand niet openen. {0} op URL: {1}. -viewer.launcher.lookAndFeel.error.message = De gespecificeerde look-and-feel ({0}) is niet toegankelijk vanaf dit platform. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Fout bij analyseren van eigenschappen -parse.integer = Waarschuwing: {0} is geen correct geheel getal. -parse.float = Waarschuwing: {0} is geen correcte drijvende komma. -parse.double = Waarschuwing: {0} is geen correcte dubbele punt. -parse.choice = Waarschuwing: {0} is geen geldige selectie. -parse.laf = Waarschuwing: look-and-feel {0} wordt niet ondersteund. - -### Properties Manager Errors -manager.properties.title = ICEpdf Eigenschappenbeheer -fontManager.properties.title = ICEpdf Lettertypebeheer - -manager.properties.createNewDirectory = \ - Om de directory {0} te creëren,\n\ - waarin de ICEpdf Viewer veranderingen in de setup zal opslaan, klikt u op Ja.\n\n\ - Als u op "Nee" klikt, gaan alle veranderingen die u in de ICEpdf Viewer-setup maakt\n\ - verloren als u de toepassing afsluit. - -manager.properties.failedCreation = \ - ICEpdf Viewer-directory om gebruikersgegevens in op te slaan kan niet gecreëerd worden:\n\ - {0}\n\ - ICEpdf Viewer slaat veranderingen in de standaardinstallatie niet op. - -manager.properties.session.nolock = \ - Fout bij creëren van het beveiligingsbestand:\n\ - {0}\n - -manager.properties.session.readError = \ - Fout bij het laden van het eigenschappenbestand: \n\ - {0} - -manager.properties.deleted = Eigenschappenbestand is gewist\n\ - ({0})\n\ - Wilt u dit opnieuw creëren? - -manager.properties.modified = Eigenschappenbestand is gewijzigd sinds de laatste update\n\ - ({0,date,long})\n\ - Wilt u veranderingen in het bestand samenvoegen met de huidige eigenschappen? - -manager.properties.saveError = Kan eigenschappenbestand niet opslaan.\n\ - Is de volgende fout tegengekomen:\n\ - {0} - -manager.properties.lafError = \ - Look&Feel {0} in de standaardeigenschappen wordt niet ondersteund.\n\ - De standaardinstellingen van het systeem worden gebruikt. - -manager.properties.brokenProperty = Defecte standaardwaarde van eigenschap {0}: {1} - -manager.properties.missingProperty = Ontbrekende standaardwaarde van eigenschap {0}: {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_no.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_no.properties deleted file mode 100644 index 972d4b9c8b..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_no.properties +++ /dev/null @@ -1,481 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf Oversikt -viewer.window.title.open.default = ICEpdf Oversikt - [{0}] - -#status bar -viewer.statusbar.currentPage = Side {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Skjul verktøylinje -viewer.toolbar.showToolBar.label = Vis verktøylinje -viewer.toolbar.showUtilityPane.label = Vis vinduet Hjelpefunksjoner -viewer.toolbar.hideUtilityPane.label = Skjul vinduet Hjelpefunksjoner -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Åpne dokument -viewer.toolbar.saveAs.label = Lagre som -viewer.toolbar.saveAs.tooltip = Lagre som... -viewer.toolbar.print.label = Skriv ut -viewer.toolbar.print.tooltip = Skriv ut dokument -viewer.toolbar.search.label = Søk -viewer.toolbar.search.tooltip = Søk dokument -viewer.toolbar.utilityPane.label = Hjeplefunksjoner-vindu -viewer.toolbar.utilityPane.tooltip = Vis/Skjul vinduet Hjelpefunksjoner -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Antall sider -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = Aktuelt sidetall -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Første side -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Forrige side -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Neste side -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Siste side -viewer.toolbar.pageIndicator = av {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zoom -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Zoom - Ut -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Zoom - Inn -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Aktuell størrelse -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = Tilpass i vindu -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Tilpass bredde -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Roter til venstre -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Roter til høyre -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Tekst Velg verktøy -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Tekst Velg verktøy -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Velg verktøy -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Lenkekommentar verktøy -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Zoom Inn Verktøy -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Zoom Ut Verktøy -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Aktiver/Deaktiver skriftstørrelse motor - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Ikke-kontinuerlig visning av enkelt side -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Ikke-kontinuerlig visning av framside -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Kontinuerlig visning av enkelt side -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Kontinuerlig visning av framside - - -## File Menu and submenu items -viewer.menu.file.label = Fil -viewer.menu.file.mnemonic = F -viewer.menu.open.label = Åpne -viewer.menu.open.file.label = Fil... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Lukk -viewer.menu.saveAs.label = Lagre som... -viewer.menu.exportText.label = Eksporter tekst... -viewer.menu.documentProperties.label=Dokumentinformasjon... -viewer.menu.documentPermission.label = Dokumentgodkjennelser... -viewer.menu.documentInformation.label = Dokumentinformasjon... -viewer.menu.printSetup.label = Skriv ut oppsett... -viewer.menu.print.label = Skriv ut... -viewer.menu.exit.label = Avbryt - -## View Menu and submenu items -viewer.menu.edit.label = Rediger -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Angre -viewer.menu.edit.redo.label = Gjør om -viewer.menu.edit.copy.label = Kopier -viewer.menu.edit.delete.label = Fjern -viewer.menu.edit.selectAll.label = Merk alle -viewer.menu.edit.deselectAll.label = Opphev alle -## View Menu and submenu items -viewer.menu.view.label = Vis -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = Aktuell størrelse -viewer.menu.view.fitInWindow.label = Tilpass i vindu -viewer.menu.view.fitWidth.label = Tilpass bredde -viewer.menu.view.zoomIn.label = Zoom - Inn -viewer.menu.view.zoomOut.label = Zoom - Ut -viewer.menu.view.rotateLeft.label = Roter til venstre -viewer.menu.view.rotateRight.label = Roter til høyre -viewer.menu.view.hideToolBar.label = Skjul verktøylinje -viewer.menu.view.showToolBar.label = Vis verktøylinje -viewer.menu.view.showUtilityPane.label = Vis vinduet Hjelpefunksjoner -viewer.menu.view.hideUtilityPane.label = Skjul vinduet Hjelpefunksjoner - -## Document Menu and submenu items -viewer.menu.document.label = Dokumenter -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Første side -viewer.menu.document.previousPage.label = Forrige side -viewer.menu.document.nextPage.label = Neste side -viewer.menu.document.lastPage.label = Siste side -viewer.menu.document.search.label = Søk... -viewer.menu.document.gotToPage.label = Gå til side... - -## Window Menu and submenu items -viewer.menu.window.label = Vindu -viewer.menu.window.mnemonic = K -viewer.menu.window.minAll.label = Minimer alle -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = Legg alle foran -viewer.menu.window.frontAll.mnemonic = b -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Hjelp -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = Om ICEpdf Oversikt... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Unntaksbetingelse -viewer.dialog.error.exception.msg = \ - Det oppsto en feil når kommandoen din skulle utføres på grunn av følgende unntaksbetingelse\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Åpne fil -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Feil under åpning av fil -viewer.dialog.openFile.error.msg = \ - ICEpdf kunne ikke åpne den spesifiserte filen i {0}\n\ - Filen kan være ødelagt eller en filtype som ikke støttes. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - PDF Unntaksbetingelse -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf kunne ikke åpne den spesifiserte filen {0}\n\ - Filen kan være ødelagt eller en filtype som ikke støttes. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - PDF Sikkerhetsmessig unntaksbetingelse -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf kunne ikke åpne den kodede filen i {0}\n\ - Dette kan skyldes ugyldig passord eller manglende JCE Sikkerhetstilbyder.\n\n\ - Les veiledningen fra ICEpdf Utvikler for mer informasjon. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Unntaksbetingelse -viewer.dialog.openDocument.exception.msg = \ - ICEpdf kunne ikke åpne den spesifiserte filen i {0}\n\ - Filen kan være ødelagt eller en filtype som ikke støttes. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - URL Unntaksbetingelse -viewer.dialog.openURL.exception.msg = \ - ICEpdf kunne ikke åpne den spesifiserte filen. {0} \n\ - i URL: {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Informasjon -viewer.dialog.information.copyAll.msg = \ - Dokumentet har mer enn {0} sider, bruk \n\ - "Eksporter tekst..." for å pakke ut dokumentteksten. - -## Open URL Dialog -viewer.dialog.security.title = Dokumentsikkerhet -viewer.dialog.security.msg = Denne PDF er beskyttet -viewer.dialog.security.password.label = Passord: -viewer.dialog.security.okButton.label = Ok -viewer.dialog.security.okButton.mnemonic = o -viewer.dialog.security.cancelButton.label = Avbryt -viewer.dialog.security.cancelButton.mnemonic = C - - -## Open URL Dialog -viewer.dialog.openURL.title = Åpne URL - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Lagre som -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Feil under lagring -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf kunne ikke lagre til {0} fordi det ikke er en støttet filtype. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Feil under lagring -viewer.dialog.saveAs.noExtensionError.msg = Spesifiser en filutvidelse. - - -## Export Text Dialog -viewer.dialog.exportText.title = Eksporter dokumenttekst -viewer.dialog.exportText.progress.msg = Pakker ut PDF Tekst -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Feil under lagring -viewer.dialog.exportText.noExtensionError.msg = Spesifiser en filutvidelse. -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Oversikt, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = Fullført {0} av {1}. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} side -viewer.exportText.fileStamp.progress.moreFile.msg = (2) sider - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Side {0} av {1} -viewer.dialog.printing.status.start.msg = Spoler side(r) til skriver - - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Dokumentgodkjennelser -viewer.dialog.documentPermissions.securityMethod.label = Sikkerhetsmetode: -viewer.dialog.documentPermissions.userPassword.label = Brukerpassord: -viewer.dialog.documentPermissions.ownerPassword.label = Eierpassord: -viewer.dialog.documentPermissions.printing.label = Skriver ut: -viewer.dialog.documentPermissions.changing.label = Endre dokumentet: -viewer.dialog.documentPermissions.copyExtraction.label = Kopiere eller trekke ut innhold: -viewer.dialog.documentPermissions.comments.label = Autorisere kommentarer og felt: -viewer.dialog.documentPermissions.formFillingIn.label = Fylle ut felt eller signere: -viewer.dialog.documentPermissions.accessibility.label = Tilgang til innhold aktivert: -viewer.dialog.documentPermissions.assembly.label = Dokumentsamling: -viewer.dialog.documentPermissions.encryptionLevel.label = Kodenivå: -viewer.dialog.documentPermissions.securityLevel = {0}-bit v{1} R {2} -viewer.dialog.documentPermissions.none = Ingen -viewer.dialog.documentPermissions.no = Nei -viewer.dialog.documentPermissions.yes = Ja -viewer.dialog.documentPermissions.allowed = Tillatt -viewer.dialog.documentPermissions.notAllowed = Ikke tillatt -viewer.dialog.documentPermissions.fullyAllowed = Fullt tillatt -viewer.dialog.documentPermissions.standardSecurity = Adobe Acrobats standard sikkerhet -viewer.dialog.documentPermissions.partial = Delvis (lav kvalitet) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = Dokumentinformasjon -viewer.dialog.documentInformation.title.label = Tittel: -viewer.dialog.documentInformation.subject.label = Emne: -viewer.dialog.documentInformation.author.label = Forfatter: -viewer.dialog.documentInformation.keywords.label = Nøkkelord: -viewer.dialog.documentInformation.creator.label = Oppretter: -viewer.dialog.documentInformation.producer.label = Produsent: -viewer.dialog.documentInformation.created.label = Opprettet: -viewer.dialog.documentInformation.modified.label = Endret: -viewer.dialog.documentInformation.notAvailable = Ikke tilgjengelig - -## Go to Page Dialog -viewer.dialog.goToPage.title = Gå til side... -viewer.dialog.goToPage.description.label = Sidetall - -## About Dialog -viewer.dialog.about.title = Om ICEpdf Oversikt -viewer.dialog.about.pageNumber.label = \ - Finn siste nytt på ICEpdf nettside:\n\ - http://www.icepdf.org/ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Bokmerker - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Kommentarer -viewer.utilityPane.link.appearanceTitle = Utseende -viewer.utilityPane.link.linkType = Lenketype: -viewer.utilityPane.annotation.link.highlightType = Uthevet stil: -viewer.utilityPane.link.lineThickness = Linjetykkelse: -viewer.utilityPane.link.lineStyle = Linjetype: -viewer.utilityPane.link.colorChooserTitle = Kommentarfarge -viewer.utilityPane.link.colorLabel = Farge: -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Handling -viewer.utilityPane.action.addAction = Legg til -viewer.utilityPane.action.editAction = Rediger -viewer.utilityPane.action.removeAction = Fjern -viewer.utilityPane.action.type.destination.label = Destinasjon -viewer.utilityPane.action.type.uriAction.label = URI handling -viewer.utilityPane.action.type.goToAction.label = GoTo (Gå til) handling -viewer.utilityPane.action.dialog.new.title = Legg til ny handling -viewer.utilityPane.action.dialog.new.msgs = Handlingstype: -viewer.utilityPane.action.dialog.delete.title = Slett bekreftelse -viewer.utilityPane.action.dialog.delete.msgs = Er du sikker på at du vil slette denne handlingen? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = URI handlingsegenskaper -viewer.utilityPane.action.dialog.uri.msgs = URI: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = GoTo (Gå til) handlingsegenskaper -viewer.utilityPane.action.dialog.goto.page.label = Side: -viewer.utilityPane.action.dialog.goto.type.label = Skriv inn -viewer.utilityPane.action.dialog.goto.type.xyz.label = Absolutt -viewer.utilityPane.action.dialog.goto.type.fit.label = Tilpass side -viewer.utilityPane.action.dialog.goto.type.fith.label = Tilpass toppbredde -viewer.utilityPane.action.dialog.goto.type.fitv.label = Tilpass venstre bredde -viewer.utilityPane.action.dialog.goto.type.fitr.label = Tilpass Zoom - Box -viewer.utilityPane.action.dialog.goto.type.fitb.label = Tilpass sidegrenser -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Tilpass grenser oppe -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Tilpass grenser venstre -viewer.utilityPane.action.dialog.goto.right.label = Høyre: -viewer.utilityPane.action.dialog.goto.left.label = Venstre: -viewer.utilityPane.action.dialog.goto.top.label = Topp: -viewer.utilityPane.action.dialog.goto.bottom.label = Bunn: -viewer.utilityPane.action.dialog.goto.zoom.label = Zoom: -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Aktuell visning: -viewer.utilityPane.action.dialog.goto.current = Still inn lokasjon -viewer.utilityPane.action.dialog.goto.name.label = Navn: -viewer.utilityPane.action.dialog.goto.browse = Bla gjennom... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Implisitt destionasjon -viewer.utilityPane.action.dialog.goto.nameDestination.title = Navngitt destinasjon -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Dokumentets navnetre -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Navnetre -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} til {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Søk -viewer.utilityPane.search.searchText.label = Søk tekst: -viewer.utilityPane.search.results.label = Resultater: -viewer.utilityPane.search.searchButton.label = Søk -viewer.utilityPane.search.clearSearchButton.label = Tøm -viewer.utilityPane.search.caseSenstiveCheckbox.label = Saksavhengig -viewer.utilityPane.search.wholeWordCheckbox.label = Kun hele ord -viewer.utilityPane.search.cumlitiveCheckbox.label = Kumulativ -viewer.utilityPane.search.showPagesCheckbox.label = Vis sider -viewer.utilityPane.search.stopButton.label = Stopp -viewer.utilityPane.search.searching.msg = Søk... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = Søker {0} av {1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} side -viewer.utilityPane.search.searching1.moreFile.msg = (2) sider -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Side {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = (2) resultat -viewer.utilityPane.search.result.moreFile.msg = (2) resultater -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = Søkte {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = side -viewer.utilityPane.search.progress.morePage.msg = sider -viewer.utilityPane.search.progress.oneMatch.msg = {2} treff -viewer.utilityPane.search.progress.moreMatch.msg = {2} treff - -## Common Button Labels -viewer.button.ok.label = Ok -viewer.button.ok.mnemonic = o -viewer.button.cancel.label = Avbryt -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEleser - ICEpdf Pilotfeil -pilot.loading.msg =Åpne dokument {0} ... -pilot.display.msg = Vise {0} -pilot.loading.error.msg = PDF Pilot: Lasting mislyktes {0}. -pilot.error.classLoading = Fant ikke ønsket klasse {0}. Ønsket bibliotek \ - 'icepdf.jar' er kanskje ikke på klassebanen - PDF Pilot deaktivert."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - Bruk: java org.icepdf.ri.viser.Hoved [-innlastningsfil ] [-lasturl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf kunne ikke åpne den spesifiserte filen. {0} i URL: {1}. -viewer.launcher.lookAndFeel.error.message = Spesifisert se-og-føl ({0}) er ikke tilgjengelig fra denne plattformen. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Syntaksanalysefeil i egenskaper -parse.integer = Advarsel : {0} er ikke et korrekt heltall. -parse.float = Advarsel : {0} er ikke et korrekt flytende. -parse.double = Advarsel : {0} er ikke en korrekt dobbel. -parse.choice = Advarsel : {0} er ikke et gyldig valg. -parse.laf = Advarsel : se-og-føl {0} støttes ikke. - -### Properties Manager Errors -manager.properties.title = ICEpdf Egenskaperbehandling -fontManager.properties.title = ICEpdf Skrifttypebehandler - -manager.properties.createNewDirectory = \ - Opprette katalogen {0},\n\ - hvor ICEpdf Oversikt vil lagre endringer til oppsettet, klikk på Ja.\n\n\ - Hvis du klikker på "Nei", vil alle endringene du foretar i oppsettet til ICEpdf Oversikt\n\ - gå tapt når du lukker applikasjonen. - -manager.properties.failedCreation = \ - Kan ikke opprette ICEpdf Oversikt-katalog for å lagre brukerdata:\n\ - {0}\n\ - ICEpdf Oversikt lagrer ikke endringene i det grunninnstilte oppsettet. - -manager.properties.session.nolock = \ - Feil under oppretting av låsefil :\n\ - {0} - -manager.properties.session.readError = \ - Feil under lasting av egenskaper-fil: \n\ - {0} - -manager.properties.deleted = Egenskaper-fil er blitt slettet \n\ - ({0})\n\ - Opprett den på nytt ? - -manager.properties.modified = Egenskaper-filen er blitt endret siden siste oppdatering\n\ - ({0,date,long})\n\ - Vil du flette endringer i filen med de aktuelle egenskapene? - -manager.properties.saveError = Umulig å lagre egenskaper-fil. \n\ - Støtte på følgende feil :\n\ - {0} - -manager.properties.lafError = \ - Se&Føl {0} gitt i grunninnstilte egenskaper støttes ikke.\n\ - Bruke systemets grunninnstilling. - -manager.properties.brokenProperty = Brutte grunninnstilte {0} -verdier i egenskaper: {1} - -manager.properties.missingProperty = Det mangler grunninnstilte {0} -verdier i egenskaper: {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_pt.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_pt.properties deleted file mode 100644 index c4e9efb0c8..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_pt.properties +++ /dev/null @@ -1,481 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = Visualizador CEpdf -viewer.window.title.open.default = Visualizador ICEpdf - [{0}] - -#status bar -viewer.statusbar.currentPage = Página {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Ocultar barra de ferramentas -viewer.toolbar.showToolBar.label = Mostrar barra de ferramentas -viewer.toolbar.showUtilityPane.label = Mostrar painel de utilitários -viewer.toolbar.hideUtilityPane.label = Ocultar painel de utilitários -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Abrir documento -viewer.toolbar.saveAs.label = Guardar como -viewer.toolbar.saveAs.tooltip = Guardar como... -viewer.toolbar.print.label = Imprimir -viewer.toolbar.print.tooltip = Imprimir documento -viewer.toolbar.search.label = Procurar -viewer.toolbar.search.tooltip = Procurar documento -viewer.toolbar.utilityPane.label = Painel de utilitários -viewer.toolbar.utilityPane.tooltip = Mostrar/Ocultar painel de utilitários -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Número de páginas -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = Número da página actual -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Primeira página -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Página anterior -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Página seguinte -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Última página -viewer.toolbar.pageIndicator = de {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zoom -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Reduzir zoom -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Aumentar zoom -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Tamanho actual -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = Ajustar na janela -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Ajustar largura -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Rodar para a esquerda -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Rodar para a direita -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Ferramenta Selecção de texto -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Ferramenta Selecção de texto -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Ferramenta Selecção -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Ferramenta Anotação de ligação -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Ferramenta Aumentar zoom -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Ferramenta Reduzir zoom -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Activar/Desactivar motor de tipos de letra - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Vista Página individual não contínua -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Vista Página frontal não contínua -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Vista Página individual contínua -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Vista Página frontal contínua - - -## File Menu and submenu items -viewer.menu.file.label = Ficheiro -viewer.menu.file.mnemonic = F -viewer.menu.open.label = Abrir -viewer.menu.open.file.label = Ficheiro... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Fechar -viewer.menu.saveAs.label = Guardar como... -viewer.menu.exportText.label = Exportar texto... -viewer.menu.documentProperties.label=Informações do documento... -viewer.menu.documentPermission.label = Permissões do documento... -viewer.menu.documentInformation.label = Informações do documento... -viewer.menu.printSetup.label = Configurar impressora... -viewer.menu.print.label = Imprimir... -viewer.menu.exit.label = Sair - -## View Menu and submenu items -viewer.menu.edit.label = Editar -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Anular -viewer.menu.edit.redo.label = Repetir -viewer.menu.edit.copy.label = Copiar -viewer.menu.edit.delete.label = Eliminar -viewer.menu.edit.selectAll.label = Seleccionar tudo -viewer.menu.edit.deselectAll.label = Desseleccionar tudo -## View Menu and submenu items -viewer.menu.view.label = Ver -viewer.menu.view.mnemonic = S -viewer.menu.view.actualSize.label = Tamanho actual -viewer.menu.view.fitInWindow.label = Ajustar na janela -viewer.menu.view.fitWidth.label = Ajustar largura -viewer.menu.view.zoomIn.label = Aumentar zoom -viewer.menu.view.zoomOut.label = Reduzir zoom -viewer.menu.view.rotateLeft.label = Rodar para a esquerda -viewer.menu.view.rotateRight.label = Rodar para a direita -viewer.menu.view.hideToolBar.label = Ocultar barra de ferramentas -viewer.menu.view.showToolBar.label = Mostrar barra de ferramentas -viewer.menu.view.showUtilityPane.label = Mostrar painel de utilitários -viewer.menu.view.hideUtilityPane.label = Ocultar painel de utilitários - -## Document Menu and submenu items -viewer.menu.document.label = Documento -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Primeira página -viewer.menu.document.previousPage.label = Página anterior -viewer.menu.document.nextPage.label = Página seguinte -viewer.menu.document.lastPage.label = Última página -viewer.menu.document.search.label = Procurar... -viewer.menu.document.gotToPage.label = Ir para página... - -## Window Menu and submenu items -viewer.menu.window.label = Janela -viewer.menu.window.mnemonic = W -viewer.menu.window.minAll.label = Minimizar tudo -viewer.menu.window.minAll.mnemonic = ´M -viewer.menu.window.frontAll.label = Trazer tudo para a frente -viewer.menu.window.frontAll.mnemonic = b -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Ajuda -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = Acerca do visualizador ICEpdf... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Excepção -viewer.dialog.error.exception.msg = \ - Houve um erro de execução do comando devido à seguinte excepção\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Abrir ficheiro -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Erro ao abrir ficheiro -viewer.dialog.openFile.error.msg = \ - O ICEpdf não conseguiu abrir o ficheiro especificado em {0}\n\ - O ficheiro pode estar corrompido ou não ser um tipo de ficheiro suportado. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - Excepção PDF -viewer.dialog.openDocument.pdfException.msg = \ - O ICEpdf não conseguiu abrir o ficheiro especificado {0}\n\ - O ficheiro pode estar corrompido ou não ser um tipo de ficheiro suportado. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - Excepção de segurança do PDF -viewer.dialog.openDocument.pdfSecurityException.msg = \ - O ICEpdf não conseguiu abrir o ficheiro encriptado em {0} \n\ - Isto pode ser o resultado de uma palavra-passe inválida ou de um fornecedor de segurança JCE inexistente.\n\n\ - Consulte o Guia do Programador do ICEpdf para obter mais informações. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Excepção -viewer.dialog.openDocument.exception.msg = \ - O ICEpdf não conseguiu abrir o ficheiro especificado em {0}\n\ - O ficheiro pode estar corrompido ou não ser um tipo de ficheiro suportado. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - Excepção URL -viewer.dialog.openURL.exception.msg = \ - O ICEpdf não conseguiu abrir o ficheiro especificado. {0} \n\ - no URL: {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Informação -viewer.dialog.information.copyAll.msg = \ - O documento tem mais de {0} páginas, utilize\n\ - "Exportar texto..." para extrair texto do documento. - -## Open URL Dialog -viewer.dialog.security.title = Segurança do documento -viewer.dialog.security.msg = Este PDF está protegido -viewer.dialog.security.password.label = Palavra-passe: -viewer.dialog.security.okButton.label = Ok -viewer.dialog.security.okButton.mnemonic = O -viewer.dialog.security.cancelButton.label = Cancelar -viewer.dialog.security.cancelButton.mnemonic = S - - -## Open URL Dialog -viewer.dialog.openURL.title = Abrir URL - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Guardar como -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Erro ao guardar -viewer.dialog.saveAs.extensionError.msg = \ - O ICEpdf não conseguiu guardar em {0} porque não é um tipo de ficheiro suportado. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Erro ao guardar -viewer.dialog.saveAs.noExtensionError.msg = Especifique uma extensão do ficheiro. - - -## Export Text Dialog -viewer.dialog.exportText.title = Exportar texto do documento -viewer.dialog.exportText.progress.msg = Extrair texto do PDF -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Erro ao guardar -viewer.dialog.exportText.noExtensionError.msg = Especifique uma extensão do ficheiro. -# Text extraction output file -viewer.exportText.fileStamp.msg = Visualizador ICEsoft ICEpdf, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = Concluído {0} de {1}. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} página -viewer.exportText.fileStamp.progress.moreFile.msg = {2} páginas - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Página {0} de {1} -viewer.dialog.printing.status.start.msg = Spool de página(s) para a impressora - - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Permissões do documento -viewer.dialog.documentPermissions.securityMethod.label = Método de segurança: -viewer.dialog.documentPermissions.userPassword.label = Palavra-passe do utilizador: -viewer.dialog.documentPermissions.ownerPassword.label = Palavra-passe do proprietário: -viewer.dialog.documentPermissions.printing.label = Imprimir: -viewer.dialog.documentPermissions.changing.label = Alterar documento: -viewer.dialog.documentPermissions.copyExtraction.label = Extracção ou cópia de conteúdo: -viewer.dialog.documentPermissions.comments.label = Criação de campos de formulários e comentários: -viewer.dialog.documentPermissions.formFillingIn.label = Assinatura ou preenchimento dos campos dos formulários: -viewer.dialog.documentPermissions.accessibility.label = Acessibilidade ao conteúdo activada: -viewer.dialog.documentPermissions.assembly.label = Montagem de documentos: -viewer.dialog.documentPermissions.encryptionLevel.label = Nível de encriptação: -viewer.dialog.documentPermissions.securityLevel = {0} bits v{1} R {2} -viewer.dialog.documentPermissions.none = Nenhum -viewer.dialog.documentPermissions.no = Não -viewer.dialog.documentPermissions.yes = Sim -viewer.dialog.documentPermissions.allowed = Permitido -viewer.dialog.documentPermissions.notAllowed = Não permitido -viewer.dialog.documentPermissions.fullyAllowed = Completamente permitido -viewer.dialog.documentPermissions.standardSecurity = Segurança standard do Adobe Acrobat -viewer.dialog.documentPermissions.partial = Parcial (Baixa qualidade) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = Informações do documento -viewer.dialog.documentInformation.title.label = Título: -viewer.dialog.documentInformation.subject.label = Assunto: -viewer.dialog.documentInformation.author.label = Autor: -viewer.dialog.documentInformation.keywords.label = Palavras-chave: -viewer.dialog.documentInformation.creator.label = Criador: -viewer.dialog.documentInformation.producer.label = Produtor: -viewer.dialog.documentInformation.created.label = Criado: -viewer.dialog.documentInformation.modified.label = Modificado: -viewer.dialog.documentInformation.notAvailable = Indisponível - -## Go to Page Dialog -viewer.dialog.goToPage.title = Ir para página... -viewer.dialog.goToPage.description.label = Número da página - -## About Dialog -viewer.dialog.about.title = Acerca do Visualizador ICEpdf -viewer.dialog.about.pageNumber.label = \ - Consulte o sítio Web do ICEpdf para ver as notícias mais recentes:\n\ - http://www.icepdf.org/ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Marcadores - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Anotações -viewer.utilityPane.link.appearanceTitle = Aspecto -viewer.utilityPane.link.linkType = Tipo de ligação: -viewer.utilityPane.annotation.link.highlightType = Estilo do realce: -viewer.utilityPane.link.lineThickness = Espessura da linha: -viewer.utilityPane.link.lineStyle = Estilo da linha: -viewer.utilityPane.link.colorChooserTitle = Cor da anotação -viewer.utilityPane.link.colorLabel = Cor: -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Acção -viewer.utilityPane.action.addAction = Adicionar -viewer.utilityPane.action.editAction = Editar -viewer.utilityPane.action.removeAction = Remover -viewer.utilityPane.action.type.destination.label = Destino -viewer.utilityPane.action.type.uriAction.label = Acção URI -viewer.utilityPane.action.type.goToAction.label = Acção Ir para -viewer.utilityPane.action.dialog.new.title = Acção Adicionar novo -viewer.utilityPane.action.dialog.new.msgs = Tipo de acção: -viewer.utilityPane.action.dialog.delete.title = Confirmação da eliminação -viewer.utilityPane.action.dialog.delete.msgs = Deseja eliminar esta acção? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = Propriedades da acção URI -viewer.utilityPane.action.dialog.uri.msgs = URI: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = Propriedades da acção Ir para -viewer.utilityPane.action.dialog.goto.page.label = Página: -viewer.utilityPane.action.dialog.goto.type.label = Tipo -viewer.utilityPane.action.dialog.goto.type.xyz.label = Absoluto -viewer.utilityPane.action.dialog.goto.type.fit.label = Ajustar página -viewer.utilityPane.action.dialog.goto.type.fith.label = Ajustar largura superior -viewer.utilityPane.action.dialog.goto.type.fitv.label = Ajustar largura esquerda -viewer.utilityPane.action.dialog.goto.type.fitr.label = Ajustar caixa de zoom -viewer.utilityPane.action.dialog.goto.type.fitb.label = Ajustar limites da página -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Ajustar parte superior dos limites -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Ajustar lado esquerdo dos limites -viewer.utilityPane.action.dialog.goto.right.label = Direita: -viewer.utilityPane.action.dialog.goto.left.label = Esquerda: -viewer.utilityPane.action.dialog.goto.top.label = Topo: -viewer.utilityPane.action.dialog.goto.bottom.label = Fundo: -viewer.utilityPane.action.dialog.goto.zoom.label = Zoom: -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Vista actual: -viewer.utilityPane.action.dialog.goto.current = Definir localização -viewer.utilityPane.action.dialog.goto.name.label = Nome: -viewer.utilityPane.action.dialog.goto.browse = Procurar... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Destino implícito -viewer.utilityPane.action.dialog.goto.nameDestination.title = Destino nomeado -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Árvore de nomes de documentos -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Árvore de nomes -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = De {0} a {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Procurar -viewer.utilityPane.search.searchText.label = Texto da procura: -viewer.utilityPane.search.results.label = Resultados: -viewer.utilityPane.search.searchButton.label = Procurar -viewer.utilityPane.search.clearSearchButton.label = Apagar -viewer.utilityPane.search.caseSenstiveCheckbox.label = Sensível às maiúsculas -viewer.utilityPane.search.wholeWordCheckbox.label = Apenas palavras inteiras -viewer.utilityPane.search.cumlitiveCheckbox.label = Cumulativa -viewer.utilityPane.search.showPagesCheckbox.label = Mostrar páginas -viewer.utilityPane.search.stopButton.label = Parar -viewer.utilityPane.search.searching.msg = Procurar... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = A procurar {0} de {1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} página -viewer.utilityPane.search.searching1.moreFile.msg = {2} páginas -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Página {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} resultado -viewer.utilityPane.search.result.moreFile.msg = {2} resultados -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = Procurado {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = página -viewer.utilityPane.search.progress.morePage.msg = páginas -viewer.utilityPane.search.progress.oneMatch.msg = {2} correspondência -viewer.utilityPane.search.progress.moreMatch.msg = {2} correspondências - -## Common Button Labels -viewer.button.ok.label = Ok -viewer.button.ok.mnemonic = O -viewer.button.cancel.label = Cancelar -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - Erro do piloto ICEpdf -pilot.loading.msg =A abrir documento {0} ... -pilot.display.msg = A mostrar {0} -pilot.loading.error.msg = Piloto PDF: Falha ao carregar {0}. -pilot.error.classLoading = Classe necessária {0} não localizada. Biblioteca necessária \ - 'icepdf.jar' pode não estar no caminho da classe - Piloto PDF desactivado."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - Utilização: java org.icepdf.ri.visualizador.Principal [-carregarficheiro ] [-carregarurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = O ICEpdf não conseguiu abrir o ficheiro especificado. {0} no URL: {1}. -viewer.launcher.lookAndFeel.error.message = O aspecto e reconhecimento especificados ({0}) não são acessíveis a partir desta plataforma. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Erro de análise das propriedades -parse.integer = Aviso: {0} não é um número inteiro correcto. -parse.float = Aviso: {0} não é um flutuante correcto. -parse.double = Aviso: {0} não é um duplo correcto. -parse.choice = Aviso: {0} não é uma escolha válida. -parse.laf = Aviso: aspecto e reconhecimento {0} não são suportados. - -### Properties Manager Errors -manager.properties.title = Gestor de propriedades do ICEpdf -fontManager.properties.title = Gestor de tipos de letra do ICEpdf - -manager.properties.createNewDirectory = \ - Para criar o directório {0},\n\ - em que o Visualizador ICEpdf guardará as alterações da configuração, clique em Sim.\n\n\ - Se clicar em "Não", todas as alterações efectuadas na configuração do Visualizador ICEpdf\n\ - serão perdidas quando sair da aplicação. - -manager.properties.failedCreation = \ - O directório do Visualizador ICEpdf para guardar dados do utilizador não pode ser criado:\n\ - {0}\n\ - O Visualizador ICEpdf não guardará as alterações à configuração predefinida. - -manager.properties.session.nolock = \ - Erro ao criar o ficheiro de bloqueio:\n\ - {0}\n - -manager.properties.session.readError = \ - Erro ao carregar o ficheiro das propriedades: \n\ - {0} - -manager.properties.deleted = O ficheiro das propriedades foi eliminado\n\ - ({0})\n\ - Recriá-lo? - -manager.properties.modified = O ficheiro das propriedades foi modificado desde a última actualização\n\ - ({0,date,long})\n\ - Deseja intercalar as alterações do ficheiro com as propriedades actuais? - -manager.properties.saveError = Impossível guardar o ficheiro das propriedades.\n\ - Encontrado o erro seguinte:\n\ - {0} - -manager.properties.lafError = \ - O aspecto e reconhecimento {0} fornecidos nas propriedades predefinidas não são suportados.\n\ - Utilizar predefinição do sistema. - -manager.properties.brokenProperty = Valor predefinido {0} da propriedade partido: {1} - -manager.properties.missingProperty = Valor predefinido {0} da propriedade inexistente: {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_sv.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_sv.properties deleted file mode 100644 index 0dfc708263..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_sv.properties +++ /dev/null @@ -1,480 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf Viewer -viewer.window.title.open.default = ICEpdf Viewer - [{0}] - -#status bar -viewer.statusbar.currentPage = Sida {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = Dölj verktygsfält -viewer.toolbar.showToolBar.label = Visa verktygsfält -viewer.toolbar.showUtilityPane.label = Visa verktygspanel -viewer.toolbar.hideUtilityPane.label = Dölj verktygspanel -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = Öppna dokument -viewer.toolbar.saveAs.label = Spara som -viewer.toolbar.saveAs.tooltip = Spara som... -viewer.toolbar.print.label = Skriv ut -viewer.toolbar.print.tooltip = Skriv ut dokument -viewer.toolbar.search.label = Sök -viewer.toolbar.search.tooltip = Sök dokument -viewer.toolbar.utilityPane.label = Verktygspanel -viewer.toolbar.utilityPane.tooltip = Visa/Dölj verktygspanel -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = Antal sidor -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = Aktuellt sidnummer -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = Första sidan -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = Föregående sida -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = Nästa sida -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = Sista sidan -viewer.toolbar.pageIndicator = av {0} -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = Zooma -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = Zooma ut -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = Zooma in -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = Verklig storlek -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = Anpassa i fönster -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = Anpassa bredd -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = Rotera vänster -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = Rotera höger -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = Välj text, verktyg -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = Välj text, verktyg -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = Välj, verktyg -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = Länka annoteringsverktyg -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = Zooma in, verktyg -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = Zooma ut, verktyg -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = Aktivera/Inaktivera fontmotor - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = Single Page View Non-Continuous (En sida, ej sammanhängande vy) -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = Facing Page View Non-Continuous (Uppslag, ej sammanhängande vy) -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = Single Page View Continuous (En sida, sammanhängande vy) -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = Facing Page View Continuous (Uppslag, sammanhängande vy) - - -## File Menu and submenu items -viewer.menu.file.label = Arkiv -viewer.menu.file.mnemonic = F -viewer.menu.open.label = Öppna -viewer.menu.open.file.label = Arkiv... -viewer.menu.open.URL.label = URL... -viewer.menu.close.label = Stäng -viewer.menu.saveAs.label = Spara som... -viewer.menu.exportText.label = Exportera text... -viewer.menu.documentProperties.label=Dokumentinformation... -viewer.menu.documentPermission.label = Dokumentbehörigheter... -viewer.menu.documentInformation.label = Dokumentinformation... -viewer.menu.printSetup.label = Utskriftsinställning... -viewer.menu.print.label = Skriv ut... -viewer.menu.exit.label = Avsluta - -## View Menu and submenu items -viewer.menu.edit.label = Redigera -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = Ångra -viewer.menu.edit.redo.label = Upprepa -viewer.menu.edit.copy.label = Kopiera -viewer.menu.edit.delete.label = Ta bort -viewer.menu.edit.selectAll.label = Markera alla -viewer.menu.edit.deselectAll.label = Avmarkera Alla -## View Menu and submenu items -viewer.menu.view.label = Visa -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = Verklig storlek -viewer.menu.view.fitInWindow.label = Anpassa i fönster -viewer.menu.view.fitWidth.label = Anpassa bredd -viewer.menu.view.zoomIn.label = Zooma in -viewer.menu.view.zoomOut.label = Zooma ut -viewer.menu.view.rotateLeft.label = Rotera vänster -viewer.menu.view.rotateRight.label = Rotera höger -viewer.menu.view.hideToolBar.label = Dölj verktygsfält -viewer.menu.view.showToolBar.label = Visa verktygsfält -viewer.menu.view.showUtilityPane.label = Visa verktygspanel -viewer.menu.view.hideUtilityPane.label = Dölj verktygspanel - -## Document Menu and submenu items -viewer.menu.document.label = Dokument -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = Första sidan -viewer.menu.document.previousPage.label = Föregående sida -viewer.menu.document.nextPage.label = Nästa sida -viewer.menu.document.lastPage.label = Sista sidan -viewer.menu.document.search.label = Sök... -viewer.menu.document.gotToPage.label = Gå till sida... - -## Window Menu and submenu items -viewer.menu.window.label = Fönster -viewer.menu.window.mnemonic = W -viewer.menu.window.minAll.label = Minimera alla -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = Lägg alla överst -viewer.menu.window.frontAll.mnemonic = B -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = Hjälp -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = Om ICEpdf Viewer... - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - Undantag -viewer.dialog.error.exception.msg = \ - Ett fel uppstod vid exekveringen av ditt kommando på grund av följande undantag\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = Öppna fil -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Fel vid öppning av fil -viewer.dialog.openFile.error.msg = \ - ICEpdf kunde ej öppna den angivna filen på {0}\n\ - Filen kan vara skadad eller filtypen kanske inte stöds. - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - PDF-undantag -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf kunde ej öppna den angivna filen {0}\n\ - Filen kan vara skadad eller filtypen kanske inte stöds. - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - PDF-säkerhetsundantag -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf kunde ej öppna den krypterade filen på {0}\n\ - Detta kan bero på ett ogiltigt lösenord eller att en JCE Security Provider saknas.\n\n\ - Se ICEpdf Developer's Guide för mer information. - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Undantag -viewer.dialog.openDocument.exception.msg = \ - ICEpdf kunde ej öppna den angivna filen på {0}\n\ - Filen kan vara skadad eller filtypen kanske inte stöds. - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - URL-undantag -viewer.dialog.openURL.exception.msg = \ - ICEpdf kunde ej öppna den angivna filen. {0} \n\ - på URL: {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Information -viewer.dialog.information.copyAll.msg = \ - Dokumentet innehåller mer än {0} sidor, använd\n\ - "Exportera text..." för att extrahera dokumenttext. - -## Open URL Dialog -viewer.dialog.security.title = Dokumentsäkerhet -viewer.dialog.security.msg = Denna PDF är skyddad -viewer.dialog.security.password.label = Lösenord: -viewer.dialog.security.okButton.label = Ok -viewer.dialog.security.okButton.mnemonic = O -viewer.dialog.security.cancelButton.label = Avbryt -viewer.dialog.security.cancelButton.mnemonic = C - - -## Open URL Dialog -viewer.dialog.openURL.title = Öppna URL - -### Save a Copy Dialog -viewer.dialog.saveAs.title = Spara som -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Fel vid Spara-åtgärd -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf kunde inte spara till {0} på grund av att filtypen inte stöds. -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Fel vid Spara-åtgärd -viewer.dialog.saveAs.noExtensionError.msg = Ange ett filsuffix. - - -## Export Text Dialog -viewer.dialog.exportText.title = Exportera dokumenttext -viewer.dialog.exportText.progress.msg = Extraherar PDF-text -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - Fel vid Spara-åtgärd -viewer.dialog.exportText.noExtensionError.msg = Ange ett filsuffix. -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = Slutfört {0} av {1}. -viewer.exportText.fileStamp.progress.oneFile.msg = {2} sida -viewer.exportText.fileStamp.progress.moreFile.msg = {2} sidor - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = Sida {0} av {1} -viewer.dialog.printing.status.start.msg = Mellanlagrar sida/sidor till skrivare - - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = Dokumentbehörigheter -viewer.dialog.documentPermissions.securityMethod.label = Säkerhetsmetod: -viewer.dialog.documentPermissions.userPassword.label = Användarens lösenord: -viewer.dialog.documentPermissions.ownerPassword.label = Ägarens lösenord: -viewer.dialog.documentPermissions.printing.label = Skriver ut: -viewer.dialog.documentPermissions.changing.label = Ändrar dokumentet: -viewer.dialog.documentPermissions.copyExtraction.label = Kopiering eller extraktion av innehåll: -viewer.dialog.documentPermissions.comments.label = Författarkommentarer och formulärfält: -viewer.dialog.documentPermissions.formFillingIn.label = Formulärfält för ifyllning eller undertecknande: -viewer.dialog.documentPermissions.accessibility.label = Åtkomst till innehåll aktiverad: -viewer.dialog.documentPermissions.assembly.label = Dokumentegenskaper: -viewer.dialog.documentPermissions.encryptionLevel.label = Krypteringsnivå: -viewer.dialog.documentPermissions.securityLevel = {0} bitar v{1} R {2} -viewer.dialog.documentPermissions.none = Inga -viewer.dialog.documentPermissions.no = Nej -viewer.dialog.documentPermissions.yes = Ja -viewer.dialog.documentPermissions.allowed = Tillåten -viewer.dialog.documentPermissions.notAllowed = Ej tillåten -viewer.dialog.documentPermissions.fullyAllowed = Helt tillåten -viewer.dialog.documentPermissions.standardSecurity = Adobe Acrobat Standard Security -viewer.dialog.documentPermissions.partial = Partiell (låg kvalitet) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = Dokumentinformation -viewer.dialog.documentInformation.title.label = Rubrik: -viewer.dialog.documentInformation.subject.label = Ärende: -viewer.dialog.documentInformation.author.label = Författare: -viewer.dialog.documentInformation.keywords.label = Nyckelord: -viewer.dialog.documentInformation.creator.label = Upphovsman: -viewer.dialog.documentInformation.producer.label = Producent: -viewer.dialog.documentInformation.created.label = Skapad: -viewer.dialog.documentInformation.modified.label = Modifierad: -viewer.dialog.documentInformation.notAvailable = Ej tillgänglig - -## Go to Page Dialog -viewer.dialog.goToPage.title = Gå till sida... -viewer.dialog.goToPage.description.label = Sidnummer - -## About Dialog -viewer.dialog.about.title = Om ICEpdf Viewer -viewer.dialog.about.pageNumber.label = \ - Besök webbplatsen för ICEpdf för de senaste nyheterna:\n\ - http://www.icepdf.org/ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = Bokmärken - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = Annoteringar -viewer.utilityPane.link.appearanceTitle = Utseende -viewer.utilityPane.link.linkType = Länktyp: -viewer.utilityPane.annotation.link.highlightType = Markera stil: -viewer.utilityPane.link.lineThickness = Linjetjocklek: -viewer.utilityPane.link.lineStyle = Linjestil: -viewer.utilityPane.link.colorChooserTitle = Annoteringsfärg -viewer.utilityPane.link.colorLabel = Färg: -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = Åtgärd -viewer.utilityPane.action.addAction = Lägg till -viewer.utilityPane.action.editAction = Redigera -viewer.utilityPane.action.removeAction = Ta bort -viewer.utilityPane.action.type.destination.label = Destination -viewer.utilityPane.action.type.uriAction.label = URI-åtgärd -viewer.utilityPane.action.type.goToAction.label = GoTo-åtgärd -viewer.utilityPane.action.dialog.new.title = Lägg till ny åtgärd -viewer.utilityPane.action.dialog.new.msgs = Typ av åtgärd: -viewer.utilityPane.action.dialog.delete.title = Ta bort bekräftelse -viewer.utilityPane.action.dialog.delete.msgs = Är du säker på att du vill ta bort denna åtgärd? -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = URI åtgärdsegenskaper -viewer.utilityPane.action.dialog.uri.msgs = URI: -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = GoTo åtgärdsegenskaper -viewer.utilityPane.action.dialog.goto.page.label = Sida: -viewer.utilityPane.action.dialog.goto.type.label = Typ -viewer.utilityPane.action.dialog.goto.type.xyz.label = Absolut -viewer.utilityPane.action.dialog.goto.type.fit.label = Anpassa sida -viewer.utilityPane.action.dialog.goto.type.fith.label = Anpassa bredd i överkant -viewer.utilityPane.action.dialog.goto.type.fitv.label = Anpassa bredd åt vänster -viewer.utilityPane.action.dialog.goto.type.fitr.label = Anpassa zoomruta -viewer.utilityPane.action.dialog.goto.type.fitb.label = Anpassa sidgränser -viewer.utilityPane.action.dialog.goto.type.fitbh.label = Anpassa gränser i överkant -viewer.utilityPane.action.dialog.goto.type.fitbv.label = Anpassa gränser åt vänster -viewer.utilityPane.action.dialog.goto.right.label = Höger: -viewer.utilityPane.action.dialog.goto.left.label = Vänster: -viewer.utilityPane.action.dialog.goto.top.label = Överkant: -viewer.utilityPane.action.dialog.goto.bottom.label = Underkant: -viewer.utilityPane.action.dialog.goto.zoom.label = Zooma: -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = Aktuell vy: -viewer.utilityPane.action.dialog.goto.current = Ställ in plats -viewer.utilityPane.action.dialog.goto.name.label = Namn: -viewer.utilityPane.action.dialog.goto.browse = Bläddra... -viewer.utilityPane.action.dialog.goto.explicitDestination.title = Implicit destination -viewer.utilityPane.action.dialog.goto.nameDestination.title = Benämnd destination -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = Dokumentnamnträd -viewer.utilityPane.action.dialog.goto.nameTree.root.label = Namnträd -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} till {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = Sök -viewer.utilityPane.search.searchText.label = Sök text: -viewer.utilityPane.search.results.label = Resultat: -viewer.utilityPane.search.searchButton.label = Sök -viewer.utilityPane.search.clearSearchButton.label = Rensa -viewer.utilityPane.search.caseSenstiveCheckbox.label = Skiftlägeskänslig -viewer.utilityPane.search.wholeWordCheckbox.label = Endast hela ord -viewer.utilityPane.search.cumlitiveCheckbox.label = Kumulativ -viewer.utilityPane.search.showPagesCheckbox.label = Visa sidor -viewer.utilityPane.search.stopButton.label = Stoppa -viewer.utilityPane.search.searching.msg = Sök... -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = Söker {0} av {1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} sida -viewer.utilityPane.search.searching1.moreFile.msg = {2} sidor -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = Sida {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} resultat -viewer.utilityPane.search.result.moreFile.msg = {2} resultat -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = Sökt {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = sida -viewer.utilityPane.search.progress.morePage.msg = sidor -viewer.utilityPane.search.progress.oneMatch.msg = {2} matchning -viewer.utilityPane.search.progress.moreMatch.msg = {2} matchningar - -## Common Button Labels -viewer.button.ok.label = Ok -viewer.button.ok.mnemonic = O -viewer.button.cancel.label = Avbryt -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - ICEpdf pilotfel -pilot.loading.msg =Öppnar dokument {0}... -pilot.display.msg = Visar {0} -pilot.loading.error.msg = PDF-pilot: Kunde ej ladda {0}. -pilot.error.classLoading = Den begärda klassen {0} kunde inte hittas. Det begärda biblioteket \ - 'icepdf.jar' kanske inte finns på klassökvägen - PDF-pilot inaktiverad."; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - Användning: java org.icepdf.ri.viewer.Huvud [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf kunde inte öppna den angivna filen. {0} på URL: {1}. -viewer.launcher.lookAndFeel.error.message = Angiven look-and-feel ({0}) är ej tillgänglig från denna plattform. - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = Fel vid analys av egenskaper -parse.integer = Varning: {0} är ej ett korrekt heltal. -parse.float = Varning: {0} är ej ett korrekt flyttal. -parse.double = Varning: {0} är ej en korrekt dubblering. -parse.choice = Varning: {0} är ej ett korrekt val. -parse.laf = Varning: look-and-feel {0} stöds inte. - -### Properties Manager Errors -manager.properties.title = ICEpdf Properties Manager -fontManager.properties.title = ICEpdf Font Manager - -manager.properties.createNewDirectory = \ - För att skapa mappen {0}\n\ - där ICEpdf Viewer kommer att spara ändringar av dess inställningar, klicka på Ja.\n\n\ - Om du klickar på "Nej" kommer alla ändringar du gör av inställningarna för ICEpdf Viewer\n\ - att förloras när du stänger applikationen. \n\n - -manager.properties.failedCreation = \ - ICEpdf Viewer-mappen för lagring av användardata kan inte skapas:\n\ - {0}\n\ - ICEpdf Viewer kommer inte att spara ändringar av dess förinställningar. - -manager.properties.session.nolock = \ - Ett fel inträffade när låsfilen skapades:\n\ - {0} - -manager.properties.session.readError = \ - Ett fel inträffade när egenskapsfilen laddades: \n\ - {0} - -manager.properties.deleted = Egenskapsfilen har tagits bort\n\ - ({0})\n\ - Skapa den på nytt? - -manager.properties.modified = Egenskapsfilen har modifierats efter den senaste uppdateringen \n\ - ({0,date,long})\n\ - Vill du slå ihop ändringarna i filen med de aktuella egenskaperna? - -manager.properties.saveError = Omöjligt att spara egenskapsfil.\n\ - Följande fel påträffades:\n\ - {0} - -manager.properties.lafError = \ - Look&Feel {0} som anges i de förinställda egenskaperna stöds inte.\n\ - Använder systemets förinställning. - -manager.properties.brokenProperty = Värdet för den förinställda egenskapen {0} är inte korrekt: {1} -manager.properties.missingProperty = Värdet för den förinställda egenskapen {0} saknas: {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_zh_CN.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_zh_CN.properties deleted file mode 100644 index 2594a1e738..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_zh_CN.properties +++ /dev/null @@ -1,486 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf Viewer -viewer.window.title.open.default = ICEpdf Viewer - [{0}] - -#status bar -viewer.statusbar.currentPage = \u9875 {0} / {1} - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = \u9690\u85cf\u5de5\u5177\u6761 -viewer.toolbar.showToolBar.label = \u663e\u793a\u5de5\u5177\u6761 -viewer.toolbar.showUtilityPane.label = \u663e\u793a\u5b9e\u7528\u5de5\u5177\u7a97\u683c -viewer.toolbar.hideUtilityPane.label = \u9690\u85cf\u5b9e\u7528\u5de5\u5177\u7a97\u683c -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = \u6253\u5f00\u6587\u6863 -viewer.toolbar.saveAs.label = \u53e6\u5b58\u4e3a -viewer.toolbar.saveAs.tooltip = \u53e6\u5b58\u4e3a.. -viewer.toolbar.print.label = \u6253\u5370 -viewer.toolbar.print.tooltip = \u6253\u5370\u6587\u6863 -viewer.toolbar.search.label = \u641c\u7d22 -viewer.toolbar.search.tooltip = \u641c\u7d22\u6587\u6863 -viewer.toolbar.utilityPane.label = \u5b9e\u7528\u5de5\u5177\u7a97\u683c -viewer.toolbar.utilityPane.tooltip = \u663e\u793a/\u9690\u85cf\u5b9e\u7528\u5de5\u5177\u7a97\u683c -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = \u9875\u6570 -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = \u5f53\u524d\u9875\u7801 -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = \u9996\u9875 -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = \u524d\u4e00\u9875 -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = \u4e0b\u4e00\u9875 -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = \u6700\u540e\u4e00\u9875 -viewer.toolbar.pageIndicator = \u5171 {0} \u9875 -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = \u7f29\u653e -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = \u7f29\u5c0f -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = \u653e\u5927 -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = \u5b9e\u9645\u5927\u5c0f -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = \u6309\u7a97\u53e3\u5927\u5c0f\u663e\u793a -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = \u6309\u5bbd\u5ea6\u663e\u793a -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = \u5411\u5de6\u65cb\u8f6c -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = \u5411\u53f3\u65cb\u8f6c -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = \u6587\u672c\u9009\u62e9\u5de5\u5177 -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = \u6587\u672c\u9009\u62e9\u5de5\u5177 -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = \u9009\u62e9\u5de5\u5177 -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = \u94fe\u63a5\u6279\u6ce8\u5de5\u5177 -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = \u653e\u5927\u5de5\u5177 -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = \u7f29\u5c0f\u5de5\u5177 -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = \u542f\u7528/\u7981\u7528\u5b57\u4f53\u5f15\u64ce - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = \u5355\u9875\u9762\u89c6\u56fe\uff0c\u4e0d\u8fde\u7eed -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = \u76f8\u5bf9\u9875\u9762\u89c6\u56fe\uff0c\u4e0d\u8fde\u7eed -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = \u5355\u9875\u9762\u89c6\u56fe\uff0c\u8fde\u7eed -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = \u76f8\u5bf9\u9875\u9762\u89c6\u56fe\uff0c\u8fde\u7eed - - -## File Menu and submenu items -viewer.menu.file.label = \u6587\u4ef6 -viewer.menu.file.mnemonic = F -viewer.menu.open.label = \u6253\u5f00 -viewer.menu.open.file.label = \u6587\u4ef6.. -viewer.menu.open.URL.label = URL\u3002.. -viewer.menu.close.label = \u5173\u95ed -viewer.menu.saveAs.label = \u53e6\u5b58\u4e3a.. -viewer.menu.exportText.label = \u5bfc\u51fa\u6587\u672c.. -viewer.menu.documentProperties.label=\u6587\u6863\u4fe1\u606f.. -viewer.menu.documentPermission.label = \u6587\u6863\u8bb8\u53ef.. -viewer.menu.documentInformation.label = \u6587\u6863\u4fe1\u606f.. -viewer.menu.printSetup.label = \u6253\u5370\u8bbe\u7f6e.. -viewer.menu.print.label = \u6253\u5370.. -viewer.menu.exit.label = \u9000\u51fa - -## View Menu and submenu items -viewer.menu.edit.label = \u7f16\u8f91 -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = \u64a4\u9500 -viewer.menu.edit.redo.label = \u6062\u590d -viewer.menu.edit.copy.label = \u590d\u5236 -viewer.menu.edit.delete.label = \u5220\u9664 -viewer.menu.edit.selectAll.label = \u5168\u9009 -viewer.menu.edit.deselectAll.label = \u53d6\u6d88\u5168\u9009 -## View Menu and submenu items -viewer.menu.view.label = \u67e5\u770b -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = \u5b9e\u9645\u5927\u5c0f -viewer.menu.view.fitInWindow.label = \u6309\u7a97\u53e3\u5927\u5c0f\u663e\u793a -viewer.menu.view.fitWidth.label = \u6309\u5bbd\u5ea6\u663e\u793a -viewer.menu.view.zoomIn.label = \u653e\u5927 -viewer.menu.view.zoomOut.label = \u7f29\u5c0f -viewer.menu.view.rotateLeft.label = \u5411\u5de6\u65cb\u8f6c -viewer.menu.view.rotateRight.label = \u5411\u53f3\u65cb\u8f6c -viewer.menu.view.hideToolBar.label = \u9690\u85cf\u5de5\u5177\u6761 -viewer.menu.view.showToolBar.label = \u663e\u793a\u5de5\u5177\u6761 -viewer.menu.view.showUtilityPane.label = \u663e\u793a\u5b9e\u7528\u5de5\u5177\u7a97\u683c -viewer.menu.view.hideUtilityPane.label = \u9690\u85cf\u5b9e\u7528\u5de5\u5177\u7a97\u683c - -## Document Menu and submenu items -viewer.menu.document.label = \u6587\u6863 -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = \u9996\u9875 -viewer.menu.document.previousPage.label = \u524d\u4e00\u9875 -viewer.menu.document.nextPage.label = \u4e0b\u4e00\u9875 -viewer.menu.document.lastPage.label = \u6700\u540e\u4e00\u9875 -viewer.menu.document.search.label = \u641c\u7d22.. -viewer.menu.document.gotToPage.label = \u8f6c\u81f3\u9875.. - -## Window Menu and submenu items -viewer.menu.window.label = \u7a97\u53e3 -viewer.menu.window.mnemonic = W -viewer.menu.window.minAll.label = \u6700\u5c0f\u5316\u5168\u90e8 -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = \u5168\u90e8\u7f6e\u4e8e\u9876\u5c42 -viewer.menu.window.frontAll.mnemonic = B -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = \u5e2e\u52a9 -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = \u5173\u4e8e ICEpdf viewer.. - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf - \u5f02\u5e38 -viewer.dialog.error.exception.msg = \ - \u6267\u884c\u60a8\u7684\u547d\u4ee4\u65f6\u53d1\u751f\u9519\u8bef\uff0c\u51fa\u73b0\u4ee5\u4e0b\u5f02\u5e38\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = \u6253\u5f00\u6587\u4ef6 -viewer.dialog.openFile.error.title = ICEsoft ICEpdf - \u6253\u5f00\u6587\u4ef6\u51fa\u9519 -viewer.dialog.openFile.error.msg = \ - ICEpdf \u65e0\u6cd5\u6253\u5f00\u5728 {0} \u7684\u6307\u5b9a\u6587\u4ef6\n\ - \u6587\u4ef6\u53ef\u80fd\u5df2\u635f\u574f\u6216\u5e76\u975e\u53d7\u652f\u6301\u7684\u6587\u4ef6\u7c7b\u578b\u3002 - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - PDF \u5f02\u5e38 -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf \u65e0\u6cd5\u6253\u5f00\u6307\u5b9a\u6587\u4ef6 {0}\n\ - \u6587\u4ef6\u53ef\u80fd\u5df2\u635f\u574f\u6216\u5e76\u975e\u53d7\u652f\u6301\u7684\u6587\u4ef6\u7c7b\u578b\u3002 - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - PDF \u5b89\u5168\u6027\u5f02\u5e38 -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf \u65e0\u6cd5\u6253\u5f00\u5728 {0} \u7684\u52a0\u5bc6\u6587\u4ef6\n\ - \u8fd9\u53ef\u80fd\u662f\u7531\u4e8e\u5bc6\u7801\u65e0\u6548\u6216 JCE Security Provider \u7f3a\u5931\u3002\n\n\ - \u66f4\u591a\u4fe1\u606f\uff0c\u8bf7\u53c2\u89c1 ICEpdf \u5f00\u53d1\u4eba\u5458\u6307\u5357\u3002 - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - \u5f02\u5e38 -viewer.dialog.openDocument.exception.msg = \ - ICEpdf \u65e0\u6cd5\u6253\u5f00\u5728 {0} \u7684\u6307\u5b9a\u6587\u4ef6\n\ - \u6587\u4ef6\u53ef\u80fd\u5df2\u635f\u574f\u6216\u5e76\u975e\u53d7\u652f\u6301\u7684\u6587\u4ef6\u7c7b\u578b\u3002 - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - URL \u5f02\u5e38 -viewer.dialog.openURL.exception.msg = \ - ICEpdf \u65e0\u6cd5\u6253\u5f00\u6307\u5b9a\u6587\u4ef6\u3002 {0} \n\ - \u5176 URL \u4e3a\uff1a {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - \u4fe1\u606f -viewer.dialog.information.copyAll.msg = \ - \u8be5\u6587\u6863\u5305\u542b\u7684\u9875\u9762\u8d85\u8fc7 {0} \u9875\uff0c\u8bf7\u4f7f\u7528\n\ - \u201c\u5bfc\u51fa\u6587\u672c..\u201d\u4ee5\u63d0\u53d6\u6587\u6863\u6587\u672c\u3002 - -## Open URL Dialog -viewer.dialog.security.title = \u6587\u6863\u5b89\u5168\u6027 -viewer.dialog.security.msg = \u6b64 PDF \u53d7\u4fdd\u62a4 -viewer.dialog.security.password.label = \u5bc6\u7801\uff1a -viewer.dialog.security.okButton.label = \u786e\u5b9a -viewer.dialog.security.okButton.mnemonic = O -viewer.dialog.security.cancelButton.label = \u53d6\u6d88 -viewer.dialog.security.cancelButton.mnemonic = C - - -## Open URL Dialog -viewer.dialog.openURL.title = \u6253\u5f00 URL - -### Save a Copy Dialog -viewer.dialog.saveAs.title = \u53e6\u5b58\u4e3a -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - \u4fdd\u5b58\u51fa\u9519 -viewer.dialog.saveAs.extensionError.msg = \ - ICEpdf \u65e0\u6cd5\u4fdd\u5b58\u5230 {0}\uff0c\u56e0\u4e3a\u5176\u5e76\u975e\u53d7\u652f\u6301\u7684\u6587\u4ef6\u7c7b\u578b\u3002 -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - \u4fdd\u5b58\u51fa\u9519 -viewer.dialog.saveAs.noExtensionError.msg = \u8bf7\u6307\u5b9a\u4e00\u4e2a\u6587\u4ef6\u6269\u5c55\u540d\u3002 - - -## Export Text Dialog -viewer.dialog.exportText.title = \u5bfc\u51fa\u6587\u6863\u6587\u672c -viewer.dialog.exportText.progress.msg = \u6b63\u5728\u63d0\u53d6 PDF \u6587\u672c -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf - \u4fdd\u5b58\u51fa\u9519 -viewer.dialog.exportText.noExtensionError.msg = \u8bf7\u6307\u5b9a\u4e00\u4e2a\u6587\u4ef6\u6269\u5c55\u540d\u3002 -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = \ - \u5b8c\u6210 {0}\uff0c\u5171 {1}\u3002 -viewer.exportText.fileStamp.progress.oneFile.msg = {2} \u9875 -viewer.exportText.fileStamp.progress.moreFile.msg = {2} \u9875 - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = \u9875 {0} / {1} -viewer.dialog.printing.status.start.msg = \u6b63\u5728\u540e\u53f0\u5904\u7406\u9875\u9762\u5230\u6253\u5370\u673a - - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = \u6587\u6863\u8bb8\u53ef -viewer.dialog.documentPermissions.securityMethod.label = \u5b89\u5168\u63aa\u65bd\uff1a -viewer.dialog.documentPermissions.userPassword.label = \u7528\u6237\u5bc6\u7801\uff1a -viewer.dialog.documentPermissions.ownerPassword.label = \u6240\u6709\u8005\u5bc6\u7801\uff1a -viewer.dialog.documentPermissions.printing.label = \u6253\u5370\uff1a -viewer.dialog.documentPermissions.changing.label = \u66f4\u6539\u6587\u6863\uff1a -viewer.dialog.documentPermissions.copyExtraction.label = \u5185\u5bb9\u590d\u5236\u6216\u63d0\u53d6\uff1a -viewer.dialog.documentPermissions.comments.label = \u521b\u4f5c\u6ce8\u91ca\u4e0e\u8868\u5355\u5b57\u6bb5\uff1a -viewer.dialog.documentPermissions.formFillingIn.label = \u8868\u5355\u5b57\u6bb5\u586b\u5199\u4e0e\u7b7e\u540d\uff1a -viewer.dialog.documentPermissions.accessibility.label = \u542f\u7528\u5185\u5bb9\u53ef\u8bbf\u95ee\u6027\uff1a -viewer.dialog.documentPermissions.assembly.label = \u6587\u6863\u7ec4\u4ef6\uff1a -viewer.dialog.documentPermissions.encryptionLevel.label = \u52a0\u5bc6\u5c42\u7ea7\uff1a -viewer.dialog.documentPermissions.securityLevel = {0} \u4f4d v{1} R {2} -viewer.dialog.documentPermissions.none = \u65e0 -viewer.dialog.documentPermissions.no = \u5426 -viewer.dialog.documentPermissions.yes = \u662f -viewer.dialog.documentPermissions.allowed = \u8bb8\u53ef -viewer.dialog.documentPermissions.notAllowed = \u7981\u6b62 -viewer.dialog.documentPermissions.fullyAllowed = \u5b8c\u6574\u8bb8\u53ef -viewer.dialog.documentPermissions.standardSecurity = Adobe Acrobat \u6807\u51c6\u5b89\u5168\u6027 -viewer.dialog.documentPermissions.partial = \u90e8\u5206\uff08\u4f4e\u8d28\u91cf\uff09 - - -## Document Information Dialog -viewer.dialog.documentInformation.title = \u6587\u6863\u4fe1\u606f -viewer.dialog.documentInformation.title.label = \u6807\u9898\uff1a -viewer.dialog.documentInformation.subject.label = \u4e3b\u9898\uff1a -viewer.dialog.documentInformation.author.label = \u4f5c\u8005\uff1a -viewer.dialog.documentInformation.keywords.label = \u5173\u952e\u8bcd\uff1a -viewer.dialog.documentInformation.creator.label = \u521b\u5efa\u8005\uff1a -viewer.dialog.documentInformation.producer.label = \u5236\u4f5c\u8005\uff1a -viewer.dialog.documentInformation.created.label = \u521b\u5efa\u65e5\u671f\uff1a -viewer.dialog.documentInformation.modified.label = \u4fee\u6539\u65e5\u671f\uff1a -viewer.dialog.documentInformation.notAvailable = \u4e0d\u53ef\u7528 - -## Go to Page Dialog -viewer.dialog.goToPage.title = \u8f6c\u81f3\u9875.. -viewer.dialog.goToPage.description.label = \u9875\u7801 - -## About Dialog -viewer.dialog.about.title = \u5173\u4e8e ICEpdf Viewer -viewer.dialog.about.pageNumber.label = \n\ -\n\ -\u8bbf\u95ee ICEpdf \u7f51\u7ad9\u83b7\u53d6\u6700\u65b0\u65b0\u95fb\uff1a\n\ -http://www.icepdf.org/ \n\ -\n\ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = \u4e66\u7b7e - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = \u6279\u6ce8 -viewer.utilityPane.link.appearanceTitle = \u5916\u89c2 -viewer.utilityPane.link.linkType = \u94fe\u63a5\u7c7b\u578b\uff1a -viewer.utilityPane.annotation.link.highlightType = \u7a81\u51fa\u663e\u793a\u98ce\u683c\uff1a -viewer.utilityPane.link.lineThickness = \u7ebf\u6761\u5bbd\u5ea6\uff1a -viewer.utilityPane.link.lineStyle = \u7ebf\u578b\uff1a -viewer.utilityPane.link.colorChooserTitle = \u6279\u6ce8\u989c\u8272 -viewer.utilityPane.link.colorLabel = \u989c\u8272\uff1a -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = \u52a8\u4f5c -viewer.utilityPane.action.addAction = \u6dfb\u52a0 -viewer.utilityPane.action.editAction = \u7f16\u8f91 -viewer.utilityPane.action.removeAction = \u79fb\u9664 -viewer.utilityPane.action.type.destination.label = \u76ee\u6807 -viewer.utilityPane.action.type.uriAction.label = URI \u52a8\u4f5c -viewer.utilityPane.action.type.goToAction.label = \u8f6c\u81f3\u52a8\u4f5c -viewer.utilityPane.action.dialog.new.title = \u6dfb\u52a0\u65b0\u52a8\u4f5c -viewer.utilityPane.action.dialog.new.msgs = \u52a8\u4f5c\u7c7b\u578b\uff1a -viewer.utilityPane.action.dialog.delete.title = \u5220\u9664\u786e\u8ba4 -viewer.utilityPane.action.dialog.delete.msgs = \u60a8\u786e\u5b9a\u8981\u5220\u9664\u6b64\u52a8\u4f5c\uff1f -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = URI \u52a8\u4f5c\u5c5e\u6027 -viewer.utilityPane.action.dialog.uri.msgs = URI\uff1a -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = \u8f6c\u81f3\u52a8\u4f5c\u5c5e\u6027 -viewer.utilityPane.action.dialog.goto.page.label = \u9875\u9762\uff1a -viewer.utilityPane.action.dialog.goto.type.label = \u7c7b\u578b -viewer.utilityPane.action.dialog.goto.type.xyz.label = \u7edd\u5bf9\u5927\u5c0f -viewer.utilityPane.action.dialog.goto.type.fit.label = \u6309\u9875\u9762\u5927\u5c0f\u8c03\u6574 -viewer.utilityPane.action.dialog.goto.type.fith.label = \u6309\u9876\u90e8\u5bbd\u5ea6\u8c03\u6574 -viewer.utilityPane.action.dialog.goto.type.fitv.label = \u6309\u5de6\u4fa7\u5bbd\u5ea6\u8c03\u6574 -viewer.utilityPane.action.dialog.goto.type.fitr.label = \u6309\u7f29\u653e\u6846\u8c03\u6574 -viewer.utilityPane.action.dialog.goto.type.fitb.label = \u6309\u9875\u9762\u8fb9\u754c\u8c03\u6574 -viewer.utilityPane.action.dialog.goto.type.fitbh.label = \u6309\u9876\u90e8\u8fb9\u754c\u8c03\u6574 -viewer.utilityPane.action.dialog.goto.type.fitbv.label = \u6309\u5de6\u8fb9\u754c\u8c03\u6574 -viewer.utilityPane.action.dialog.goto.right.label = \u53f3\uff1a -viewer.utilityPane.action.dialog.goto.left.label = \u5de6\uff1a -viewer.utilityPane.action.dialog.goto.top.label = \u9876\u90e8\uff1a -viewer.utilityPane.action.dialog.goto.bottom.label = \u5e95\u90e8\uff1a -viewer.utilityPane.action.dialog.goto.zoom.label = \u7f29\u653e\uff1a -viewer.utilityPane.action.dialog.goto.unassigned.label = NaN -viewer.utilityPane.action.dialog.goto.current.label = \u5f53\u524d\u89c6\u56fe\uff1a -viewer.utilityPane.action.dialog.goto.current = \u8bbe\u7f6e\u4f4d\u7f6e -viewer.utilityPane.action.dialog.goto.name.label = \u540d\u79f0\uff1a -viewer.utilityPane.action.dialog.goto.browse = \u6d4f\u89c8.. -viewer.utilityPane.action.dialog.goto.explicitDestination.title = \u9690\u5f0f\u76ee\u6807 -viewer.utilityPane.action.dialog.goto.nameDestination.title = \u5df2\u547d\u540d\u76ee\u6807 -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = \u6587\u6863\u540d\u79f0\u6811 -viewer.utilityPane.action.dialog.goto.nameTree.root.label = \u540d\u79f0\u6811 -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} \u5230 {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = \u641c\u7d22 -viewer.utilityPane.search.searchText.label = \u641c\u7d22\u6587\u672c\uff1a -viewer.utilityPane.search.results.label = \u7ed3\u679c\uff1a -viewer.utilityPane.search.searchButton.label = \u641c\u7d22 -viewer.utilityPane.search.clearSearchButton.label = \u6e05\u9664 -viewer.utilityPane.search.caseSenstiveCheckbox.label = \u533a\u5206\u5927\u5c0f\u5199 -viewer.utilityPane.search.wholeWordCheckbox.label = \u5168\u5b57\u5339\u914d -viewer.utilityPane.search.cumlitiveCheckbox.label = \u7d2f\u8ba1 -viewer.utilityPane.search.showPagesCheckbox.label = \u663e\u793a\u9875\u9762 -viewer.utilityPane.search.stopButton.label = \u505c\u6b62 -viewer.utilityPane.search.searching.msg = \u641c\u7d22.. -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = \ - \u641c\u7d22 {0} \u9879\uff0c\u5171 {1} \u9879 -viewer.utilityPane.search.searching1.oneFile.msg = {2} \u9875 -viewer.utilityPane.search.searching1.moreFile.msg = {2} \u9875 -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = \u9875 {0} ({1}) -viewer.utilityPane.search.result.oneFile.msg = {2} \u7ed3\u679c -viewer.utilityPane.search.result.moreFile.msg = {2} \u7ed3\u679c -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = \ - \u5df2\u641c\u7d22 {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = \u9875 -viewer.utilityPane.search.progress.morePage.msg = \u9875 -viewer.utilityPane.search.progress.oneMatch.msg = {2} \u5339\u914d -viewer.utilityPane.search.progress.moreMatch.msg = {2} \u5339\u914d - -## Common Button Labels -viewer.button.ok.label = \u786e\u5b9a -viewer.button.ok.mnemonic = O -viewer.button.cancel.label = \u53d6\u6d88 -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser - ICEpdf Pilot \u51fa\u9519 -pilot.loading.msg =\u6b63\u5728\u6253\u5f00\u6587\u6863 {0}\u3002.. -pilot.display.msg = \u6b63\u5728\u663e\u793a {0} -pilot.loading.error.msg = PDF Pilot\uff1a \u52a0\u8f7d {0} \u5931\u8d25\u3002 -pilot.error.classLoading = \u672a\u627e\u5230\u9700\u8981\u7684\u5206\u7c7b {0}\u3002 \u9700\u8981\u7684\u5e93 \ 'icepdf \ - icepdf.jar' \u53ef\u80fd\u4e0d\u5728\u5206\u7c7b\u8def\u5f84\u4e0a - PDF Pilot \u5df2\u7981\u7528\u3002"; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - \u4f7f\u7528\uff1a java org.icepdf.ri.viewer.Main [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf \u65e0\u6cd5\u6253\u5f00\u6307\u5b9a\u6587\u4ef6\u3002 {0}\uff0c\u5176 URL \u4e3a\uff1a {1}. -viewer.launcher.lookAndFeel.error.message = \u65e0\u6cd5\u4ece\u6b64\u5e73\u53f0\u8bbf\u95ee\u6307\u5b9a\u89c2\u611f ({0})\u3002 - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = \u5c5e\u6027\u5206\u6790\u51fa\u9519 -parse.integer = \u8b66\u544a\uff1a {0} \u5e76\u975e\u6b63\u786e\u7684\u6574\u6570\u3002 -parse.float = \u8b66\u544a\uff1a {0} \u5e76\u975e\u6b63\u786e\u7684\u6d6e\u70b9\u3002 -parse.double = \u8b66\u544a\uff1a {0} \u5e76\u975e\u6b63\u786e\u7684\u500d\u6570\u3002 -parse.choice = \u8b66\u544a\uff1a {0} \u5e76\u975e\u6709\u6548\u7684\u9009\u62e9\u3002 -parse.laf = \u8b66\u544a\uff1a \u4e0d\u652f\u6301\u89c2\u611f {0}\u3002 - -### Properties Manager Errors -manager.properties.title = ICEpdf \u5c5e\u6027\u7ba1\u7406\u5668 -fontManager.properties.title = ICEpdf \u5b57\u4f53\u7ba1\u7406\u5668 - -manager.properties.createNewDirectory = \ - \u8981\u521b\u5efa\u7528\u4e8e ICEpdf Viewer \u4fdd\u5b58\u5176\u8bbe\u7f6e\u66f4\u6539\u7684\u76ee\u5f55 {0}\uff0c\n\ - \u5355\u51fb\u201c\u662f\u201d\u3002\n\n\ - \u5982\u679c\u60a8\u5355\u51fb\u201c\u5426\u201d\uff0c\u60a8\u5bf9 ICEpdf Viewer \u8bbe\u7f6e\u6240\u8fdb\u884c\u7684\u6240\u6709\u66f4\u6539\n\ - \u90fd\u5c06\u5728\u60a8\u9000\u51fa\u8be5\u5e94\u7528\u7a0b\u5e8f\u65f6\u4e22\u5931\u3002 \n\n - -manager.properties.failedCreation = \ - \u65e0\u6cd5\u521b\u5efa\u7528\u4e8e\u4fdd\u5b58\u7528\u6237\u6570\u636e\u7684 ICEpdf Viewer \u76ee\u5f55\uff1a\n\ - {0}\n\ - ICEpdf Viewer \u5c06\u4e0d\u4f1a\u4fdd\u5b58\u66f4\u6539\u5230\u5176\u9ed8\u8ba4\u8bbe\u7f6e\u3002 - -manager.properties.session.nolock = \ - \u521b\u5efa\u9501\u5b9a\u6587\u4ef6\u51fa\u9519\uff1a\n\ - {0}\n - -manager.properties.session.readError = \ - \u52a0\u8f7d\u5c5e\u6027\u6587\u4ef6\u51fa\u9519\uff1a \n\ - {0} - -manager.properties.deleted = \u5c5e\u6027\u6587\u4ef6\u5df2\u88ab\u5220\u9664\n\ - ({0})\n\ - \u91cd\u65b0\u521b\u5efa\uff1f - -manager.properties.modified = \u5c5e\u6027\u6587\u4ef6\u5df2\u5728\u4e0a\u6b21\u66f4\u65b0\u65f6\u8fdb\u884c\u4e86\u4fee\u6539\n\ -({0,date,long})\n\ -\u60a8\u662f\u5426\u8981\u5c06\u5f53\u524d\u5c5e\u6027\u4e0e\u6587\u4ef6\u4e2d\u7684\u66f4\u6539\u5408\u5e76\uff1f - -manager.properties.saveError = \u65e0\u6cd5\u4fdd\u5b58\u5c5e\u6027\u6587\u4ef6\u3002\n\ -\u9047\u5230\u4e0b\u5217\u9519\u8bef\uff1a\n\ -{0} - -manager.properties.lafError =\ - \u4e0d\u652f\u6301\u9ed8\u8ba4\u5c5e\u6027\u4e2d\u7ed9\u51fa\u7684\u89c2\u611f {0}\u3002\n\ - \u4f7f\u7528\u7cfb\u7edf\u9ed8\u8ba4\u8bbe\u7f6e\u3002 - -manager.properties.brokenProperty = \u9ed8\u8ba4\u5c5e\u6027 {0} \u7684\u503c\u635f\u574f\uff1a {1} - -manager.properties.missingProperty = \u9ed8\u8ba4\u5c5e\u6027 {0} \u7684\u503c\u7f3a\u5931\uff1a {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_zh_TW.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_zh_TW.properties deleted file mode 100644 index b1be6d2033..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/resources/MessageBundle_zh_TW.properties +++ /dev/null @@ -1,486 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -##### -### This MessageBundle contains English text for ICEpdf View and Pilot RI's -## -# - - -## Window toolbar Title -viewer.window.title.default = ICEpdf \u700f\u89bd\u7a0b\u5f0f -viewer.window.title.open.default = ICEpdf \u700f\u89bd\u7a0b\u5f0f - [{0}] - -#status bar -viewer.statusbar.currentPage = {0} / {1} \u9801 - -## Top Page Control Toolbar -viewer.toolbar.hideToolBar.label = \u96b1\u85cf\u5de5\u5177\u5217 -viewer.toolbar.showToolBar.label = \u986f\u793a\u5de5\u5177\u5217 -viewer.toolbar.showUtilityPane.label = \u986f\u793a\u516c\u7528\u7a0b\u5f0f\u9762\u677f -viewer.toolbar.hideUtilityPane.label = \u96b1\u85cf\u516c\u7528\u7a0b\u5f0f\u9762\u677f -viewer.toolbar.open.label = -viewer.toolbar.open.tooltip = \u958b\u555f\u6587\u4ef6 -viewer.toolbar.saveAs.label = \u53e6\u5b58\u65b0\u6a94 -viewer.toolbar.saveAs.tooltip = \u53e6\u5b58\u65b0\u6a94\u3002.. -viewer.toolbar.print.label = \u5217\u5370 -viewer.toolbar.print.tooltip = \u5217\u5370\u6587\u4ef6 -viewer.toolbar.search.label = \u641c\u5c0b -viewer.toolbar.search.tooltip = \u641c\u5c0b\u6587\u4ef6 -viewer.toolbar.utilityPane.label = \u516c\u7528\u7a0b\u5f0f\u9762\u677f -viewer.toolbar.utilityPane.tooltip = \u986f\u793a/\u96b1\u85cf\u516c\u7528\u7a0b\u5f0f\u9762\u677f -viewer.toolbar.navigation.label = -viewer.toolbar.navigation.pages.tooltip = \u9801\u6578 -viewer.toolbar.navigation.pages.firstPage.label = -viewer.toolbar.navigation.current.tooltip = \u76ee\u524d\u9801\u78bc -viewer.toolbar.navigation.current.firstPage.label = -viewer.toolbar.navigation.firstPage.label = -viewer.toolbar.navigation.firstPage.tooltip = \u7b2c\u4e00\u9801 -viewer.toolbar.navigation.previousPage.label = -viewer.toolbar.navigation.previousPage.tooltip = \u4e0a\u4e00\u9801 -viewer.toolbar.navigation.nextPage.label = -viewer.toolbar.navigation.nextPage.tooltip = \u4e0b\u4e00\u9801 -viewer.toolbar.navigation.lastPage.label = -viewer.toolbar.navigation.lastPage.tooltip = \u6700\u5f8c\u4e00\u9801 -viewer.toolbar.pageIndicator = (\u5171 {0} \u9801) -viewer.toolbar.zoom.label = -viewer.toolbar.zoom.tooltip = \u7e2e\u653e -viewer.toolbar.zoom.out.label = -viewer.toolbar.zoom.out.tooltip = \u7e2e\u5c0f -viewer.toolbar.zoom.in.label = -viewer.toolbar.zoom.in.tooltip = \u653e\u5927 -viewer.toolbar.pageFit.actualsize.label = -viewer.toolbar.pageFit.actualsize.tooltip = \u5be6\u969b\u5927\u5c0f -viewer.toolbar.pageFit.fitWindow.label = -viewer.toolbar.pageFit.fitWindow.tooltip = \u7e2e\u653e\u5230\u8996\u7a97\u5927\u5c0f -viewer.toolbar.pageFit.fitWidth.label = -viewer.toolbar.pageFit.fitWidth.tooltip = \u7e2e\u653e\u5230\u7b26\u5408\u5bec\u5ea6 -viewer.toolbar.rotation.left.label = -viewer.toolbar.rotation.left.tooltip = \u5411\u5de6\u65cb\u8f49 -viewer.toolbar.rotation.right.label = -viewer.toolbar.rotation.right.tooltip = \u5411\u53f3\u65cb\u8f49 -viewer.toolbar.tool.pan.label = -viewer.toolbar.tool.pan.tooltip = \u6587\u5b57\u9078\u53d6\u5de5\u5177 -viewer.toolbar.tool.text.label = -viewer.toolbar.tool.text.tooltip = \u6587\u5b57\u9078\u53d6\u5de5\u5177 -viewer.toolbar.tool.select.label = -viewer.toolbar.tool.select.tooltip = \u9078\u53d6\u5de5\u5177 -viewer.toolbar.tool.link.label = -viewer.toolbar.tool.link.tooltip = \u9023\u7d50\u8a3b\u89e3\u5de5\u5177 -viewer.toolbar.tool.zoomIn.label = -viewer.toolbar.tool.zoomIn.tooltip = \u653e\u5927\u5de5\u5177 -viewer.toolbar.tool.zoomOut.label = -viewer.toolbar.tool.zoomOut.tooltip = \u7e2e\u5c0f\u5de5\u5177 -viewer.toolbar.pageFit.fontEngine.label = -viewer.toolbar.pageFit.fontEngine.tooltip = \u555f\u7528/\u505c\u7528\u5b57\u578b\u5f15\u64ce - -## Bottom Page View Control Toolbar -viewer.toolbar.pageView.nonContinuous.singlePage.label = -viewer.toolbar.pageView.nonContinuous.singlePage.tooltip = \u55ae\u9801\u4e0d\u9023\u7e8c\u700f\u89bd -viewer.toolbar.pageView.nonContinuous.facingPage.label = -viewer.toolbar.pageView.nonContinuous.facingPage.tooltip = \u5c0d\u958b\u4e0d\u9023\u7e8c\u700f\u89bd -viewer.toolbar.pageView.continuous.singlePage.label = -viewer.toolbar.pageView.continuous.singlePage.tooltip = \u55ae\u9801\u9023\u7e8c\u700f\u89bd -viewer.toolbar.pageView.continuous.facingPage.label = -viewer.toolbar.pageView.continuous.facingPage.tooltip = \u5c0d\u958b\u9023\u7e8c\u700f\u89bd - - -## File Menu and submenu items -viewer.menu.file.label = \u6a94\u6848 -viewer.menu.file.mnemonic = F -viewer.menu.open.label = \u958b\u555f -viewer.menu.open.file.label = \u6a94\u6848\u3002.. -viewer.menu.open.URL.label = \u7db2\u5740\u3002.. -viewer.menu.close.label = \u95dc\u9589 -viewer.menu.saveAs.label = \u53e6\u5b58\u65b0\u6a94\u3002.. -viewer.menu.exportText.label = \u532f\u51fa\u6587\u5b57\u3002.. -viewer.menu.documentProperties.label=\u6587\u4ef6\u8cc7\u8a0a\u3002.. -viewer.menu.documentPermission.label = \u6587\u4ef6\u6b0a\u9650\u3002.. -viewer.menu.documentInformation.label = \u6587\u4ef6\u8cc7\u8a0a\u3002.. -viewer.menu.printSetup.label = \u5217\u5370\u8a2d\u5b9a\u3002.. -viewer.menu.print.label = \u5217\u5370\u3002.. -viewer.menu.exit.label = \u96e2\u958b - -## View Menu and submenu items -viewer.menu.edit.label = \u7de8\u8f2f -viewer.menu.edit.mnemonic = E -viewer.menu.edit.undo.label = \u5fa9\u539f -viewer.menu.edit.redo.label = \u91cd\u8907 -viewer.menu.edit.copy.label = \u8907\u88fd -viewer.menu.edit.delete.label = \u522a\u9664 -viewer.menu.edit.selectAll.label = \u5168\u9078 -viewer.menu.edit.deselectAll.label = \u53d6\u6d88\u5168\u9078 -## View Menu and submenu items -viewer.menu.view.label = \u6aa2\u8996 -viewer.menu.view.mnemonic = V -viewer.menu.view.actualSize.label = \u5be6\u969b\u5927\u5c0f -viewer.menu.view.fitInWindow.label = \u7e2e\u653e\u5230\u8996\u7a97\u5927\u5c0f -viewer.menu.view.fitWidth.label = \u7e2e\u653e\u5230\u7b26\u5408\u5bec\u5ea6 -viewer.menu.view.zoomIn.label = \u653e\u5927 -viewer.menu.view.zoomOut.label = \u7e2e\u5c0f -viewer.menu.view.rotateLeft.label = \u5411\u5de6\u65cb\u8f49 -viewer.menu.view.rotateRight.label = \u5411\u53f3\u65cb\u8f49 -viewer.menu.view.hideToolBar.label = \u96b1\u85cf\u5de5\u5177\u5217 -viewer.menu.view.showToolBar.label = \u986f\u793a\u5de5\u5177\u5217 -viewer.menu.view.showUtilityPane.label = \u986f\u793a\u516c\u7528\u7a0b\u5f0f\u9762\u677f -viewer.menu.view.hideUtilityPane.label = \u96b1\u85cf\u516c\u7528\u7a0b\u5f0f\u9762\u677f - -## Document Menu and submenu items -viewer.menu.document.label = \u6587\u4ef6 -viewer.menu.document.mnemonic = D -viewer.menu.document.firstPage.label = \u7b2c\u4e00\u9801 -viewer.menu.document.previousPage.label = \u4e0a\u4e00\u9801 -viewer.menu.document.nextPage.label = \u4e0b\u4e00\u9801 -viewer.menu.document.lastPage.label = \u6700\u5f8c\u4e00\u9801 -viewer.menu.document.search.label = \u641c\u5c0b\u3002.. -viewer.menu.document.gotToPage.label = \u524d\u5f80\u6307\u5b9a\u9801\u3002.. - -## Window Menu and submenu items -viewer.menu.window.label = \u8996\u7a97 -viewer.menu.window.mnemonic = W -viewer.menu.window.minAll.label = \u5168\u90e8\u7e2e\u5230\u6700\u5c0f -viewer.menu.window.minAll.mnemonic = M -viewer.menu.window.frontAll.label = \u5168\u90e8\u63d0\u5230\u6700\u4e0a\u5c64 -viewer.menu.window.frontAll.mnemonic = B -viewer.menu.window.1.label = 1 -viewer.menu.window.1.mnemonic = 1 -viewer.menu.window.2.label = 2 -viewer.menu.window.2.mnemonic = 2 -viewer.menu.window.3.label = 3 -viewer.menu.window.3.mnemonic = 3 -viewer.menu.window.4.label = 4 -viewer.menu.window.4.mnemonic = 4 -viewer.menu.window.5.label = 5 -viewer.menu.window.5.mnemonic = 5 -viewer.menu.window.6.label = 6 -viewer.menu.window.6.mnemonic = 6 -viewer.menu.window.7.label = 7 -viewer.menu.window.7.mnemonic = 7 -viewer.menu.window.8.label = 8 -viewer.menu.window.8.mnemonic = 8 -viewer.menu.window.9.label = 9 -viewer.menu.window.9.mnemonic = 9 -## Add as many entries as you want, to viewer.menu.window.X.label and mnemonic -## where X is an incrementing integer. The mnemonic should be one unique -## character found within the label - -## Help Menu and submenu items -viewer.menu.help.label = \u8aaa\u660e -viewer.menu.help.mnemonic = H -viewer.menu.help.about.label = \u95dc\u65bc ICEpdf \u700f\u89bd\u7a0b\u5f0f\u3002.. - -## General error dialog -viewer.dialog.error.exception.title = ICEsoft ICEpdf\uff1a\u4f8b\u5916 -viewer.dialog.error.exception.msg = \ - \u57f7\u884c\u6307\u4ee4\u6642\u51fa\u73fe\u932f\u8aa4\uff0c\u56e0\u70ba\u6709\u4ee5\u4e0b\u4f8b\u5916\n\ - {0}. - -## Open File Dialog -viewer.dialog.openFile.title = \u958b\u555f\u820a\u6a94 -viewer.dialog.openFile.error.title = ICEsoft ICEpdf\uff1a\u958b\u555f\u820a\u6a94\u932f\u8aa4 -viewer.dialog.openFile.error.msg = \ - ICEpdf \u7121\u6cd5\u958b\u555f\u4f4d\u65bc {0} \u7684\u6307\u5b9a\u6a94\u6848\n\ - \u6a94\u6848\u53ef\u80fd\u6bc0\u640d\u6216\u8005\u662f\u4e0d\u652f\u63f4\u7684\u6a94\u6848\u985e\u578b\u3002 - -viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf\uff1aPDF \u4f8b\u5916 -viewer.dialog.openDocument.pdfException.msg = \ - ICEpdf \u7121\u6cd5\u958b\u555f\u6307\u5b9a\u7684\u6a94\u6848 {0}\n\ - \u6a94\u6848\u53ef\u80fd\u6bc0\u640d\u6216\u8005\u662f\u4e0d\u652f\u63f4\u7684\u6a94\u6848\u985e\u578b\u3002 - -viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf\uff1aPDF \u5b89\u5168\u6027\u4f8b\u5916 -viewer.dialog.openDocument.pdfSecurityException.msg = \ - ICEpdf \u7121\u6cd5\u958b\u555f\u4f4d\u65bc {0} \u7684\u52a0\u5bc6\u6a94\u6848\n\ - \u9019\u53ef\u80fd\u662f\u5bc6\u78bc\u932f\u8aa4\u6216\u7f3a\u5c11 JCE Security Provider \u4e4b\u6545\u3002\n\n\ - \u8a73\u60c5\u8acb\u53c3\u8003\u300aICEpdf Developer's Guide\u300b\u3002 - -viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf\uff1a\u4f8b\u5916 -viewer.dialog.openDocument.exception.msg = \ - ICEpdf \u7121\u6cd5\u958b\u555f\u4f4d\u65bc {0} \u7684\u6307\u5b9a\u6a94\u6848\n\ - \u6a94\u6848\u53ef\u80fd\u6bc0\u640d\u6216\u8005\u662f\u4e0d\u652f\u63f4\u7684\u6a94\u6848\u985e\u578b\u3002 - -viewer.dialog.openURL.exception.title = ICEsoft ICEpdf\uff1a\u7db2\u5740\u4f8b\u5916 -viewer.dialog.openURL.exception.msg = \ - ICEpdf \u7121\u6cd5\u958b\u555f\u6307\u5b9a\u7684\u6a94\u6848\u3002 {0} \n\ - \u7db2\u5740\u662f\uff1a {1} - -## General error dialog -viewer.dialog.information.copyAll.title = ICEsoft ICEpdf\uff1a\u8cc7\u8a0a -viewer.dialog.information.copyAll.msg = \ - \u6b64\u6587\u4ef6\u8d85\u904e {0} \u9801\uff0c\u8acb\u4f7f\u7528\n\ - \u300c\u532f\u51fa\u6587\u5b57\u3002..\u300d\u64f7\u53d6\u6587\u4ef6\u4e2d\u7684\u6587\u5b57\u3002 - -## Open URL Dialog -viewer.dialog.security.title = \u6587\u4ef6\u5b89\u5168\u6027 -viewer.dialog.security.msg = \u672c PDF \u5df2\u7d93\u53d7\u5230\u4fdd\u8b77 -viewer.dialog.security.password.label = \u5bc6\u78bc\uff1a -viewer.dialog.security.okButton.label = \u78ba\u5b9a -viewer.dialog.security.okButton.mnemonic = O -viewer.dialog.security.cancelButton.label = \u53d6\u6d88 -viewer.dialog.security.cancelButton.mnemonic = C - - -## Open URL Dialog -viewer.dialog.openURL.title = \u958b\u555f\u7db2\u5740 - -### Save a Copy Dialog -viewer.dialog.saveAs.title = \u53e6\u5b58\u65b0\u6a94 -viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf\uff1a\u5132\u5b58\u932f\u8aa4 -viewer.dialog.saveAs.extensionError.msg = \ - \u7121\u6cd5\u5c07 ICEpdf \u5132\u5b58\u6210 {0}\uff0c\u56e0\u70ba\u4e26\u975e\u652f\u63f4\u7684\u6a94\u6848\u985e\u578b\u3002 -viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf\uff1a\u5132\u5b58\u932f\u8aa4 -viewer.dialog.saveAs.noExtensionError.msg = \u8acb\u6307\u5b9a\u526f\u6a94\u540d\u3002 - - -## Export Text Dialog -viewer.dialog.exportText.title = \u532f\u51fa\u6587\u4ef6\u4e2d\u7684\u6587\u5b57 -viewer.dialog.exportText.progress.msg = \u6b63\u5728\u64f7\u53d6 PDF \u6587\u5b57 -viewer.dialog.exportText.noExtensionError.title = ICEsoft ICEpdf\uff1a\u5132\u5b58\u932f\u8aa4 -viewer.dialog.exportText.noExtensionError.msg = \u8acb\u6307\u5b9a\u526f\u6a94\u540d\u3002 -# Text extraction output file -viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. -viewer.exportText.pageStamp.msg = -# Completed x out of y page(s). -viewer.exportText.fileStamp.progress.msg = \ - \u5df2\u5b8c\u6210 {0}/{1}\u3002 -viewer.exportText.fileStamp.progress.oneFile.msg = {2} \u9801 -viewer.exportText.fileStamp.progress.moreFile.msg = {2} \u9801 - -# Printing Progress bar -viewer.dialog.printing.status.progress.msg = \u7b2c {0} / {1} \u9801 -viewer.dialog.printing.status.start.msg = \u6b63\u5c07\u9801\u9762\u9032\u884c\u591a\u5de5\u7de9\u885d\u8655\u7406\u4ee5\u9001\u5165\u5370\u8868\u6a5f - - -## Document Permissions Dialog -viewer.dialog.documentPermissions.title = \u6587\u4ef6\u6b0a\u9650 -viewer.dialog.documentPermissions.securityMethod.label = \u5b89\u5168\u65b9\u6cd5\uff1a -viewer.dialog.documentPermissions.userPassword.label = \u4f7f\u7528\u8005\u5bc6\u78bc\uff1a -viewer.dialog.documentPermissions.ownerPassword.label = \u6240\u6709\u4eba\u5bc6\u78bc\uff1a -viewer.dialog.documentPermissions.printing.label = \u6b63\u5728\u5217\u5370\uff1a -viewer.dialog.documentPermissions.changing.label = \u6b63\u5728\u66f4\u6539\u6587\u4ef6\uff1a -viewer.dialog.documentPermissions.copyExtraction.label = \u8907\u88fd\u6216\u64f7\u53d6\u5167\u5bb9\uff1a -viewer.dialog.documentPermissions.comments.label = \u6b63\u5728\u7de8\u5beb\u8a3b\u89e3\u548c\u8868\u55ae\u6b04\u4f4d\uff1a -viewer.dialog.documentPermissions.formFillingIn.label = \u586b\u5beb\u8868\u55ae\u6b04\u4f4d\u6216\u7c3d\u540d\uff1a -viewer.dialog.documentPermissions.accessibility.label = \u555f\u7528\u5167\u5bb9\u5b58\u53d6\u529f\u80fd\uff1a -viewer.dialog.documentPermissions.assembly.label = \u6587\u4ef6\u7d44\u5408\uff1a -viewer.dialog.documentPermissions.encryptionLevel.label = \u52a0\u5bc6\u7b49\u7d1a\uff1a -viewer.dialog.documentPermissions.securityLevel = {0} \u4f4d\u5143 v{1} R {2} -viewer.dialog.documentPermissions.none = \u7121 -viewer.dialog.documentPermissions.no = \u5426 -viewer.dialog.documentPermissions.yes = \u662f -viewer.dialog.documentPermissions.allowed = \u5141\u8a31 -viewer.dialog.documentPermissions.notAllowed = \u4e0d\u5141\u8a31 -viewer.dialog.documentPermissions.fullyAllowed = \u5b8c\u5168\u5141\u8a31 -viewer.dialog.documentPermissions.standardSecurity = Adobe Acrobat \u6a19\u6e96\u5b89\u5168\u6027 -viewer.dialog.documentPermissions.partial = \u90e8\u4efd (\u4f4e\u54c1\u8cea) - - -## Document Information Dialog -viewer.dialog.documentInformation.title = \u6587\u4ef6\u8cc7\u8a0a -viewer.dialog.documentInformation.title.label = \u6a19\u984c\uff1a -viewer.dialog.documentInformation.subject.label = \u4e3b\u65e8\uff1a -viewer.dialog.documentInformation.author.label = \u4f5c\u8005\uff1a -viewer.dialog.documentInformation.keywords.label = \u95dc\u9375\u5b57\uff1a -viewer.dialog.documentInformation.creator.label = \u5efa\u7acb\u8005\uff1a -viewer.dialog.documentInformation.producer.label = \u88fd\u4f5c\u8005\uff1a -viewer.dialog.documentInformation.created.label = \u5efa\u7acb\u65e5\u671f\uff1a -viewer.dialog.documentInformation.modified.label = \u4fee\u6539\u65e5\u671f\uff1a -viewer.dialog.documentInformation.notAvailable = \u7121 - -## Go to Page Dialog -viewer.dialog.goToPage.title = \u524d\u5f80\u6307\u5b9a\u9801\u3002.. -viewer.dialog.goToPage.description.label = \u9801\u78bc - -## About Dialog -viewer.dialog.about.title = \u95dc\u65bc ICEpdf \u700f\u89bd\u7a0b\u5f0f -viewer.dialog.about.pageNumber.label = \n\ -\n\ -\u8acb\u81f3 ICEpdf \u7db2\u7ad9\u4e86\u89e3\u6700\u65b0\u6d88\u606f\uff1a\n\ -http://www.icepdf.org/ \n\ -\n\ -## Utility Pane Bookmarks Tab -viewer.utilityPane.bookmarks.tab.title = \u66f8\u7c64 - -## Utility Pane Annotation Link Tab -viewer.utilityPane.link.tab.title = \u8a3b\u89e3 -viewer.utilityPane.link.appearanceTitle = \u5916\u89c0 -viewer.utilityPane.link.linkType = \u9023\u7d50\u985e\u578b\uff1a -viewer.utilityPane.annotation.link.highlightType = \u9192\u76ee\u63d0\u793a\u6a23\u5f0f\uff1a -viewer.utilityPane.link.lineThickness = \u7dda\u689d\u7c97\u7d30\uff1a -viewer.utilityPane.link.lineStyle = \u7dda\u689d\u6a23\u5f0f\uff1a -viewer.utilityPane.link.colorChooserTitle = \u8a3b\u89e3\u984f\u8272 -viewer.utilityPane.link.colorLabel = \u984f\u8272\uff1a -## annotation action pane and dialogs. -viewer.utilityPane.action.selectionTitle = \u52d5\u4f5c -viewer.utilityPane.action.addAction = \u65b0\u589e -viewer.utilityPane.action.editAction = \u7de8\u8f2f -viewer.utilityPane.action.removeAction = \u79fb\u9664 -viewer.utilityPane.action.type.destination.label = \u76ee\u7684\u5730 -viewer.utilityPane.action.type.uriAction.label = URI \u52d5\u4f5c -viewer.utilityPane.action.type.goToAction.label = GoTo \u52d5\u4f5c -viewer.utilityPane.action.dialog.new.title = \u65b0\u589e\u52d5\u4f5c -viewer.utilityPane.action.dialog.new.msgs = \u52d5\u4f5c\u985e\u578b\uff1a -viewer.utilityPane.action.dialog.delete.title = \u78ba\u5b9a\u522a\u9664 -viewer.utilityPane.action.dialog.delete.msgs = \u60a8\u78ba\u5b9a\u8981\u522a\u9664\u9019\u500b\u52d5\u4f5c\u55ce\uff1f -## uri action dialog test -viewer.utilityPane.action.dialog.uri.title = URI \u52d5\u4f5c\u7279\u6027 -viewer.utilityPane.action.dialog.uri.msgs = URI\uff1a -## GoTo action dialog text -viewer.utilityPane.action.dialog.goto.title = GoTo \u52d5\u4f5c\u7279\u6027 -viewer.utilityPane.action.dialog.goto.page.label = \u9801\u78bc\uff1a -viewer.utilityPane.action.dialog.goto.type.label = \u985e\u578b -viewer.utilityPane.action.dialog.goto.type.xyz.label = \u7d55\u5c0d -viewer.utilityPane.action.dialog.goto.type.fit.label = \u7b26\u5408\u9801\u9762\u5927\u5c0f -viewer.utilityPane.action.dialog.goto.type.fith.label = \u7b26\u5408\u4e0a\u65b9\u5bec\u5ea6 -viewer.utilityPane.action.dialog.goto.type.fitv.label = \u7b26\u5408\u5de6\u908a\u5bec\u5ea6 -viewer.utilityPane.action.dialog.goto.type.fitr.label = \u7b26\u5408\u7e2e\u653e\u5340\u57df -viewer.utilityPane.action.dialog.goto.type.fitb.label = \u7b26\u5408\u9801\u9762\u908a\u754c -viewer.utilityPane.action.dialog.goto.type.fitbh.label = \u7b26\u5408\u4e0a\u908a\u754c -viewer.utilityPane.action.dialog.goto.type.fitbv.label = \u7b26\u5408\u5de6\u908a\u754c -viewer.utilityPane.action.dialog.goto.right.label = \u53f3\uff1a -viewer.utilityPane.action.dialog.goto.left.label = \u5de6\uff1a -viewer.utilityPane.action.dialog.goto.top.label = \u4e0a\uff1a -viewer.utilityPane.action.dialog.goto.bottom.label = \u4e0b\uff1a -viewer.utilityPane.action.dialog.goto.zoom.label = \u7e2e\u653e\uff1a -viewer.utilityPane.action.dialog.goto.unassigned.label = \u4e0d\u662f\u6578\u503c -viewer.utilityPane.action.dialog.goto.current.label = \u76ee\u524d\u756b\u9762\uff1a -viewer.utilityPane.action.dialog.goto.current = \u8a2d\u5b9a\u4f4d\u7f6e -viewer.utilityPane.action.dialog.goto.name.label = \u540d\u7a31\uff1a -viewer.utilityPane.action.dialog.goto.browse = \u700f\u89bd\u3002.. -viewer.utilityPane.action.dialog.goto.explicitDestination.title = \u5df2\u542b\u76ee\u7684\u5730 -viewer.utilityPane.action.dialog.goto.nameDestination.title = \u5177\u540d\u76ee\u7684\u5730 -# Destination Named Tree -viewer.utilityPane.action.dialog.goto.nameTree.title = \u6587\u4ef6\u540d\u7a31\u6a39\u72c0\u986f\u793a -viewer.utilityPane.action.dialog.goto.nameTree.root.label = \u6a94\u540d\u6a39\u72c0\u986f\u793a -viewer.utilityPane.action.dialog.goto.nameTree.branch.label = {0} \u81f3 {1} - -## Utility Pane Search Tab -viewer.utilityPane.search.tab.title = \u641c\u5c0b -viewer.utilityPane.search.searchText.label = \u641c\u5c0b\u6587\u5b57\uff1a -viewer.utilityPane.search.results.label = \u7d50\u679c\uff1a -viewer.utilityPane.search.searchButton.label = \u641c\u5c0b -viewer.utilityPane.search.clearSearchButton.label = \u6e05\u9664 -viewer.utilityPane.search.caseSenstiveCheckbox.label = \u5340\u5206\u5927\u5c0f\u5beb -viewer.utilityPane.search.wholeWordCheckbox.label = \u50c5\u5b8c\u6574\u55ae\u5b57 -viewer.utilityPane.search.cumlitiveCheckbox.label = \u7d2f\u7a4d -viewer.utilityPane.search.showPagesCheckbox.label = \u986f\u793a\u9801\u9762 -viewer.utilityPane.search.stopButton.label = \u505c\u6b62 -viewer.utilityPane.search.searching.msg = \u641c\u5c0b\u3002.. -# Searching x out of y page(s) -viewer.utilityPane.search.searching1.msg = \ - \u6b63\u5728\u641c\u5c0b {0}/{1} -viewer.utilityPane.search.searching1.oneFile.msg = {2} \u9801 -viewer.utilityPane.search.searching1.moreFile.msg = {2} \u9801 -# Page x (y result(s)) -viewer.utilityPane.search.result.msg = \u7b2c {0} ({1}) \u9801 -viewer.utilityPane.search.result.oneFile.msg = {2} \u500b\u7d50\u679c -viewer.utilityPane.search.result.moreFile.msg = {2} \u500b\u7d50\u679c -# Searched x page(s) (y matches) -viewer.utilityPane.search.progress.msg = \ - \u5df2\u7d93\u641c\u5c0b {0} {1} ({2}) -viewer.utilityPane.search.progress.onePage.msg = \u9801 -viewer.utilityPane.search.progress.morePage.msg = \u9801 -viewer.utilityPane.search.progress.oneMatch.msg = {2} \u7b46\u7b26\u5408\u9805\u76ee -viewer.utilityPane.search.progress.moreMatch.msg = {2} \u7b46\u7b26\u5408\u9805\u76ee - -## Common Button Labels -viewer.button.ok.label = \u78ba\u5b9a -viewer.button.ok.mnemonic = O -viewer.button.cancel.label = \u53d6\u6d88 -viewer.button.cancel.mnemonic = C - -## Pilot Specific Mesages -pilot.title = ICEbrowser\uff1aICEpdf Pilot \u932f\u8aa4 -pilot.loading.msg =\u6b63\u5728\u958b\u555f\u6587\u4ef6 {0}\u3002.. -pilot.display.msg = \u6b63\u5728\u986f\u793a {0} -pilot.loading.error.msg = PDF Pilot\uff1a \u7121\u6cd5\u8f09\u5165 {0}\u3002 -pilot.error.classLoading = \u627e\u4e0d\u5230\u5fc5\u8981\u7684 {0} \u985e\u5225\u3002 \u5fc5\u8981\u7a0b\u5f0f\u5eab \\u300cicepdf. \ - icepdf.jar\u300d\u53ef\u80fd\u4e0d\u5728\u985e\u5225\u8def\u5f91\u4e0a\uff1a\u5df2\u505c\u7528 PDF Pilot\u3002"; - -### -# General Error Messages - - -# Command Line Errors -viewer.commandLin.error = \ - \u7528\u6cd5\uff1a java org.icepdf.ri.viewer\u3002Main [-loadfile ] [-loadurl ] -# Launcher errors -viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf -viewer.launcher.URLError.dialog.message = ICEpdf \u7121\u6cd5\u958b\u555f\u6307\u5b9a\u7684\u6a94\u6848\u3002 {0} \u7db2\u5740\u662f\uff1a {1}. -viewer.launcher.lookAndFeel.error.message = \u6b64\u5e73\u53f0\u4e0d\u63d0\u4f9b\u6307\u5b9a\u7684\u5916\u89c0 ({0})\u3002 - -# Pilot Loading Errors - - -### parser error dialogs -parse.title = \u7279\u6027\u5256\u6790\u932f\u8aa4 -parse.integer = \u8b66\u544a\uff1a {0} \u4e0d\u662f\u6b63\u78ba\u6574\u6578\u3002 -parse.float = \u8b66\u544a\uff1a {0} \u4e0d\u662f\u6b63\u78ba\u7684\u55ae\u7cbe\u5ea6\u6d6e\u9ede\u6578\u3002 -parse.double = \u8b66\u544a\uff1a {0} \u4e0d\u662f\u6b63\u78ba\u96d9\u500d\u7cbe\u5ea6\u6578\u503c\u3002 -parse.choice = \u8b66\u544a\uff1a {0} \u4e0d\u662f\u6709\u6548\u9078\u9805\u3002 -parse.laf = \u8b66\u544a\uff1a \u4e0d\u652f\u63f4 {0} \u5916\u89c0\u3002 - -### Properties Manager Errors -manager.properties.title = ICEpdf \u7279\u6027\u7ba1\u7406\u54e1 -fontManager.properties.title = ICEpdf \u5b57\u578b\u7ba1\u7406\u54e1 - -manager.properties.createNewDirectory = \ - \u5982\u679c\u8981\u5efa\u7acb {0} \u76ee\u9304\uff0c\n\ - \u8b93 ICEpdf \u700f\u89bd\u7a0b\u5f0f\u5c07\u66f4\u6539\u5167\u5bb9\u5132\u5b58\u5230\u8a2d\u5b9a\u4e2d\uff0c\u8acb\u6309\u4e00\u4e0b [\u662f]\u3002\n\n\ - \u5982\u679c\u6309\u4e00\u4e0b [\u5426]\uff0c\u5247\u60a8\u66f4\u6539\u7684 ICEpdf \u700f\u89bd\u7a0b\u5f0f\u8a2d\u5b9a\u5167\u5bb9\uff0c\n\ - \u90fd\u6703\u5728\u7d50\u675f\u61c9\u7528\u7a0b\u5f0f\u5f8c\u5168\u90e8\u6d88\u5931\u3002 \n\n - -manager.properties.failedCreation = \ - \u7121\u6cd5\u5efa\u7acb ICEpdf \u700f\u89bd\u7a0b\u5f0f\u7684\u4f7f\u7528\u8005\u8cc7\u6599\u5132\u5b58\u76ee\u9304\uff1a\n\ - {0}\n\ - ICEpdf \u700f\u89bd\u7a0b\u5f0f\u7121\u6cd5\u5c07\u66f4\u6539\u5167\u5bb9\u5132\u5b58\u5230\u9810\u8a2d\u8a2d\u5b9a\u4e2d\u3002 - -manager.properties.session.nolock = \ - \u5efa\u7acb\u9396\u5b9a\u6a94\u6848\u6642\u51fa\u73fe\u932f\u8aa4\uff1a\n\ - {0}\n - -manager.properties.session.readError = \ - \u8f09\u5165\u7279\u6027\u6a94\u6848\u6642\u51fa\u73fe\u932f\u8aa4\uff1a \n\ - {0} - -manager.properties.deleted = \u7279\u6027\u6a94\u6848\u5df2\u7d93\u906d\u5230\u522a\u9664\n\ - ({0})\n\ - \u662f\u5426\u91cd\u65b0\u5efa\u7acb\uff1f - -manager.properties.modified = \u7279\u6027\u6a94\u6848\u5df2\u7d93\u5728\u4e0a\u6b21\u66f4\u65b0\u5f8c\u6709\u6240\u4fee\u6539\n\ -({0,date,long})\n\ -\u60a8\u8981\u5c07\u6a94\u6848\u7684\u66f4\u6539\u5167\u5bb9\u5408\u4f75\u5230\u76ee\u524d\u7279\u6027\u55ce\uff1f - -manager.properties.saveError = \u7121\u6cd5\u5132\u5b58\u7279\u6027\u6a94\u6848\u3002\n\ -\u51fa\u73fe\u4ee5\u4e0b\u932f\u8aa4\uff1a\n\ -{0} - -manager.properties.lafError =\ - \u4e0d\u652f\u63f4\u9810\u8a2d\u7279\u6027\u63d0\u4f9b\u7684 {0} \u5916\u89c0\u3002\n\ - \u4f7f\u7528\u7cfb\u7d71\u9810\u8a2d\u503c\u3002 - -manager.properties.brokenProperty = \u9810\u8a2d\u7279\u6027 {0} \u503c\u4e0d\u5168\uff1a {1} - -manager.properties.missingProperty = \u7f3a\u5c11\u9810\u8a2d\u7279\u6027 {0} \u503c\uff1a {1} - - - - - - - - - - diff --git a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/viewer/res/ICEpdfDefault.properties b/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/viewer/res/ICEpdfDefault.properties deleted file mode 100644 index 9fc130140a..0000000000 --- a/mucommander-viewer-pdf/src/main/resources/org/icepdf/ri/viewer/res/ICEpdfDefault.properties +++ /dev/null @@ -1,90 +0,0 @@ -# -# Copyright 2006-2017 ICEsoft Technologies Canada Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the -# License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an "AS -# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language -# governing permissions and limitations under the License. -# - -# -#-- Viewer Default application properties -- -# If a property is not given in user property file, it is taken from here - -# IMPORTANT: if a file is specified here, it MUST exists -# ========= in the com/icepdf/ri/viewer/icons/ directory. Otherwise -# Viewer -RI crashes -application.language = en -application.region = -application.width = 800 -application.height = 600 -application.divider.location = 260 -application.always.show.image.splash.window=yes -application.menu.recent.file.size=8 -document.proportionalfont.name = SansSerif -document.proportionalfont.size = 11 -document.fixedfont.name = Monospaced -document.fixedfont.size = 11 -# annotation toolbar -application.toolbar.annotation.selection.enabled=true -application.toolbar.annotation.highlight.enabled=true -application.toolbar.annotation.underline.enabled=false -application.toolbar.annotation.strikeout.enabled=false -application.toolbar.annotation.line.enabled=false -application.toolbar.annotation.link.enabled=false -application.toolbar.annotation.arrow.enabled=false -application.toolbar.annotation.rectangle.enabled=false -application.toolbar.annotation.circle.enabled=false -application.toolbar.annotation.ink.enabled=false -application.toolbar.annotation.freetext.enabled=false -application.toolbar.annotation.text.enabled=true -# annotations that default selection tool after creation -application.annotation.highlight.selection.enabled=false -application.annotation.line.selection.enabled=true -application.annotation.link.selection.enabled=true -application.annotation.rectangle.selection.enabled=true -application.annotation.circle.selection.enabled=true -application.annotation.ink.selection.enabled=true -application.annotation.freetext.selection.enabled=true -application.annotation.text.selection.enabled=false -# default Document View is single page view -document.viewtype = 1 -# default value is fit page height -document.pagefit.mode=1 -# document rotation -document.rotation=0 -# default paper size can be customized as follows. -# -# Units must be specified in inches or millimeters. -# -# Millimeters = 1000 -# Inches = 25400 -# -# Common Paper sizes in inches: -# -# NA Letter 8.5 x 11.0 -# NA Legal 8.5 x 14.0 -# ISO A4 8.267716 X 11.692913 -# -# Common Paper Sizes in millimeters: -# NA Letter 215.9 x 279.4 -# NA Legal 215.9 x 355.6 -# ISO A4 210.0 x 297.0 -# -# default paper size is NA Letter in millimeters. -document.print.media.size.width=215.9 -document.print.media.size.height=279.4 -document.print.media.size.unit=1000 - -# thumbnail view zoom value. -application.utilitypane.thumbnail.zoom = 0.1 -# Default annotation properties, mainly colour and opacity options... - - diff --git a/mucommander-viewer-text/build.gradle b/mucommander-viewer-text/build.gradle index d16ef28b59..90fd5ce1cf 100644 --- a/mucommander-viewer-text/build.gradle +++ b/mucommander-viewer-text/build.gradle @@ -9,15 +9,21 @@ dependencies { api project(':mucommander-encoding') api project(":mucommander-preferences") + compileOnly 'com.google.code.findbugs:jsr305:1.3.9' + comprise group: 'com.fifesoft', name: 'rsyntaxtextarea', version: '3.3.2' + testImplementation 'org.testng:testng:6.11' } jar { + from configurations.comprise.collect { it.isDirectory() ? it : zipTree(it)} + duplicatesStrategy = DuplicatesStrategy.EXCLUDE bnd ('Bundle-Name': 'muCommander-viewer-text', 'Bundle-Vendor': 'muCommander', 'Bundle-Description': 'Library for textual viewer/editor', 'Bundle-DocURL': 'https://www.mucommander.com', 'Export-Package': 'com.mucommander.viewer.text', + 'Import-Package': 'org.fife.ui.rsyntaxtextarea;resolution:=dynamic,*', 'Bundle-Activator': 'com.mucommander.viewer.text.Activator', 'Specification-Title': "muCommander", 'Specification-Vendor': "Arik Hadas", @@ -26,5 +32,5 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/BasicFileEditor.java b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/BasicFileEditor.java index b2bbaf74a7..230687dbb5 100644 --- a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/BasicFileEditor.java +++ b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/BasicFileEditor.java @@ -37,7 +37,6 @@ import com.mucommander.viewer.CloseCancelledException; import com.mucommander.viewer.EditorPresenter; import com.mucommander.viewer.FileEditor; -import java.awt.event.KeyEvent; import java.util.Arrays; import javax.swing.JComponent; @@ -45,7 +44,6 @@ import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; -import javax.swing.KeyStroke; /** * Abstract file editor with basic support for save operation. @@ -126,6 +124,10 @@ public void setCurrentFile(AbstractFile currentFile) { this.currentFile = currentFile; } + protected boolean isSaveNeeded(){ + return saveNeeded; + } + protected void setSaveNeeded(boolean saveNeeded) { if (getFrame() != null && this.saveNeeded != saveNeeded) { this.saveNeeded = saveNeeded; diff --git a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextEditor.java b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextEditor.java index e12b5aa31d..c132d9e68c 100644 --- a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextEditor.java +++ b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextEditor.java @@ -23,10 +23,12 @@ import java.io.InputStream; import java.io.OutputStream; +import javax.swing.ButtonGroup; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; +import javax.swing.JRadioButtonMenuItem; import javax.swing.KeyStroke; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -42,18 +44,24 @@ import com.mucommander.commons.util.ui.helper.MnemonicHelper; import com.mucommander.core.desktop.DesktopManager; import com.mucommander.desktop.ActionType; +import com.mucommander.snapshot.MuSnapshot; import com.mucommander.text.Translator; import com.mucommander.ui.dialog.InformationDialog; import com.mucommander.ui.encoding.EncodingListener; import com.mucommander.ui.encoding.EncodingMenu; import com.mucommander.viewer.CloseCancelledException; -import com.mucommander.viewer.EditorPresenter; -import static com.mucommander.viewer.text.TextViewer.CUSTOM_FULL_SCREEN_EVENT; -import static com.mucommander.viewer.text.TextViewer.isFullScreen; -import static com.mucommander.viewer.text.TextViewer.setFullScreen; + + import java.awt.event.ActionListener; -import javax.swing.AbstractAction; +import java.io.OutputStreamWriter; +import java.util.Collections; +import java.util.Map; + import javax.swing.JScrollPane; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; + +import static com.mucommander.viewer.text.TextViewerSnapshot.TEXT_FILE_PRESENTER_SECTION; /** @@ -62,12 +70,13 @@ * @author Maxence Bernard, Nicolas Rinaudo, Arik Hadas */ class TextEditor extends BasicFileEditor implements DocumentListener, EncodingListener, ActionListener { - private static final Logger LOGGER = LoggerFactory.getLogger(TextEditor.class); + private static final Logger LOGGER = LoggerFactory.getLogger(TextEditor.class); - private JScrollPane ui = new JScrollPane(); - private TextLineNumbersPanel lineNumbersPanel; + private JScrollPane ui; - /** Menu bar */ + /** + * Menu bar + */ // Menus // private JMenu editMenu; private JMenu viewMenu; @@ -79,65 +88,135 @@ class TextEditor extends BasicFileEditor implements DocumentListener, EncodingLi private JMenuItem findItem; private JMenuItem findNextItem; private JMenuItem findPreviousItem; - private JMenuItem toggleLineWrapItem; - private JMenuItem toggleLineNumbersItem; - private TextEditorImpl textEditorImpl; - private TextViewer textViewerDelegate; + private final TextEditorImpl textEditorImpl; + private final TextViewer textViewerDelegate; public TextEditor() { - textViewerDelegate = new TextViewer(textEditorImpl = new TextEditorImpl(true)) { + textViewerDelegate = new TextViewer(textEditorImpl = new TextEditorImpl(true)) { @Override protected void attachView() { - ui.getViewport().setView(textEditorImpl.getTextArea()); + ui = textEditorImpl.getScrollPane(); } - - @Override - protected void showLineNumbers(boolean show) { - ui.setRowHeaderView(show ? lineNumbersPanel : null); - setLineNumbers(show); - } - + @Override - protected void initLineNumbersPanel() { - lineNumbersPanel = new TextLineNumbersPanel(textEditorImpl.getTextArea()); + protected void showLineNumbers(boolean show) { + textEditorImpl.showLineNumbers(show); + setLineNumbers(show); } - @Override - protected void initMenuBarItems() { - // Edit menu + @Override + protected void initMenuBarItems() { // TODO code dup with TextViewer, fix it + // Edit menu ActionListener listener = TextEditor.this; - editMenu = new JMenu(Translator.get("text_editor.edit")); - MnemonicHelper menuItemMnemonicHelper = new MnemonicHelper(); - - copyItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.copy"), menuItemMnemonicHelper, null, listener); - - cutItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.cut"), menuItemMnemonicHelper, null, listener); - pasteItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.paste"), menuItemMnemonicHelper, null, listener); - - selectAllItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.select_all"), menuItemMnemonicHelper, null, listener); - editMenu.addSeparator(); - - findItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.find"), menuItemMnemonicHelper, DesktopManager.getActionShortcuts().getDefaultKeystroke(ActionType.Find), listener); - findNextItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.find_next"), menuItemMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0), listener); - findPreviousItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.find_previous"), menuItemMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_F3, KeyEvent.SHIFT_DOWN_MASK), listener); - - viewMenu = new JMenu(Translator.get("text_editor.view")); - - toggleLineWrapItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, Translator.get("text_editor.line_wrap"), menuItemMnemonicHelper, null, listener); - toggleLineWrapItem.setSelected(textEditorImpl.isWrap()); - toggleLineNumbersItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, Translator.get("text_editor.line_numbers"), menuItemMnemonicHelper, null, listener); - toggleLineNumbersItem.setSelected(ui.getRowHeader().getView() != null); - } - }; + editMenu = new JMenu(Translator.get("text_editor.edit")); + MnemonicHelper menuItemMnemonicHelper = new MnemonicHelper(); + + JMenuItem undoItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.undo"), menuItemMnemonicHelper, DesktopManager.getActionShortcuts().getDefaultKeystroke(ActionType.Undo), listener); + undoItem.addActionListener(e -> textEditorImpl.undo()); + JMenuItem redoItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.redo"), menuItemMnemonicHelper, DesktopManager.getActionShortcuts().getDefaultKeystroke(ActionType.Redo), listener); + redoItem.addActionListener(e -> textEditorImpl.redo()); + editMenu.addMenuListener(menuSelectedListener(() -> { + undoItem.setEnabled(textEditorImpl.canUndo()); + redoItem.setEnabled(textEditorImpl.canRedo()); + })); + editMenu.addSeparator(); + + copyItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.copy"), menuItemMnemonicHelper, null, listener); + + cutItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.cut"), menuItemMnemonicHelper, null, listener); + pasteItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.paste"), menuItemMnemonicHelper, null, listener); + + selectAllItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.select_all"), menuItemMnemonicHelper, null, listener); + editMenu.addSeparator(); + + findItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.find"), menuItemMnemonicHelper, DesktopManager.getActionShortcuts().getDefaultKeystroke(ActionType.Find), listener); + findNextItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.find_next"), menuItemMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0), listener); + findPreviousItem = MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.find_previous"), menuItemMnemonicHelper, KeyStroke.getKeyStroke(KeyEvent.VK_F3, KeyEvent.SHIFT_DOWN_MASK), listener); + + editMenu.addSeparator(); + + MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.spaces_to_tabs"), menuItemMnemonicHelper, null, e -> textEditorImpl.convertSpacesToTabs()); + MenuToolkit.addMenuItem(editMenu, Translator.get("text_editor.tabs_to_spaces"), menuItemMnemonicHelper, null, e -> textEditorImpl.convertTabsToSpaces()); + + viewMenu = new JMenu(Translator.get("text_editor.view")); + + JMenu tabSyntaxMenu = new JMenu(Translator.get("text_editor.syntax_style")); + + ButtonGroup syntaxGroup = new ButtonGroup(); + for (Map.Entry syntaxStyle : textEditorImpl.getSyntaxStyles().entrySet()) { + JRadioButtonMenuItem radio = new JRadioButtonMenuItem(syntaxStyle.getValue(), false); + radio.setName(syntaxStyle.getKey()); + radio.addActionListener( + e -> { + boolean saveNeededKeeper = isSaveNeeded(); + textEditorImpl.setSyntaxStyle(syntaxStyle.getKey()); + setSaveNeeded(saveNeededKeeper); + } + ); + syntaxGroup.add(radio); + tabSyntaxMenu.add(radio); + } + textEditorImpl.setSyntaxStyleChangeListener(syntaxMime -> + Collections.list(syntaxGroup.getElements()).stream() + .filter(radio -> syntaxMime.equals(radio.getName())) + .findFirst().ifPresent(radio -> radio.setSelected(true)) + ); + viewMenu.add(tabSyntaxMenu); + viewMenu.addSeparator(); + + JMenuItem item; + for (TextViewerPreferences pref : TextViewerPreferences.values()) { + if (pref.isTextEditorPref()) { + item = MenuToolkit.addCheckBoxMenuItem(viewMenu, + Translator.get(pref.getI18nKey()), menuItemMnemonicHelper, + null, e -> pref.setValue(textEditorImpl, ((JMenuItem)e.getSource()).isSelected())); + item.setSelected(pref.getValue()); // the last known (or current) value + } + } + viewMenu.addSeparator(); + JMenuItem toggleLineNumbersItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, + Translator.get(TextViewerPreferences.LINE_NUMBERS.getI18nKey()), + menuItemMnemonicHelper, null, listener); + toggleLineNumbersItem.setSelected(textEditorImpl.getLineNumbersEnabled()); + toggleLineNumbersItem.addActionListener(e -> + textViewerDelegate.showLineNumbers(toggleLineNumbersItem.isSelected())); + + viewMenu.addSeparator(); + int tabSize = textEditorImpl.getTabSize(); + JMenu tabSizeMenu = new JMenu(Translator.get("text_editor.tab_size")); + + ButtonGroup tabGroup = new ButtonGroup(); + for (int i : new int[]{2, 4, 8}) { + JRadioButtonMenuItem radio = new JRadioButtonMenuItem(Integer.toString(i), tabSize == i); + radio.addActionListener( + e -> { + textEditorImpl.setTabSize(i); + MuSnapshot.getSnapshot().setVariable( + TEXT_FILE_PRESENTER_SECTION + ".tab_size", i); + } + ); + tabGroup.add(radio); + tabSizeMenu.add(radio); + } + viewMenu.add(tabSizeMenu); + } + }; } - + void loadDocument(InputStream in, String encoding, DocumentListener documentListener) throws IOException { - textViewerDelegate.loadDocument(in, encoding, documentListener); + textViewerDelegate.loadDocument(getCurrentFile(), in, encoding, documentListener); } - + private void write(OutputStream out) throws IOException { - textEditorImpl.write(new BOMWriter(out, textViewerDelegate.getEncoding())); + var isUtf8 = "UTF-8".equalsIgnoreCase(textViewerDelegate.getEncoding()); + textEditorImpl.write(isUtf8 ? + new OutputStreamWriter(out) : new BOMWriter(out, textViewerDelegate.getEncoding())); + } + + @Override + public void requestFocus() { + textEditorImpl.setFocusAndCursorOnFirstLine(); } /////////////////////////////// @@ -151,11 +230,11 @@ protected void saveAs(AbstractFile destFile) throws IOException { try { out = destFile.getOutputStream(); write(out); - } - finally { - if(out != null) { - try {out.close();} - catch(IOException e) { + } finally { + if (out != null) { + try { + out.close(); + } catch (IOException e) { // Ignored } } @@ -166,40 +245,22 @@ protected void saveAs(AbstractFile destFile) throws IOException { setSaveNeeded(false); // Change the parent folder's date to now, so that changes are picked up by folder auto-refresh (see ticket #258) - if(destFile.isFileOperationSupported(FileOperation.CHANGE_DATE)) { + if (destFile.isFileOperationSupported(FileOperation.CHANGE_DATE)) { try { destFile.getParent().changeDate(System.currentTimeMillis()); - } - catch (IOException e) { - LOGGER.debug("failed to change the date of "+destFile, e); + } catch (IOException e) { + LOGGER.debug("failed to change the date of " + destFile, e); // Fail silently } } } - @Override - public void setPresenter(EditorPresenter presenter) { - super.setPresenter(presenter); - - presenter.setFullScreen(isFullScreen()); - - ui.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.CTRL_MASK), CUSTOM_FULL_SCREEN_EVENT); - ui.getActionMap().put(CUSTOM_FULL_SCREEN_EVENT, new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - setFullScreen(!presenter.isFullScreen()); - presenter.setFullScreen(isFullScreen()); - } - }); - } - @Override public void open(AbstractFile file) throws IOException { setCurrentFile(file); textViewerDelegate.startEditing(file, this); - lineNumbersPanel.setPreferredWidth(); } - + @Override public void close() throws CloseCancelledException { if (!askSave()) { @@ -211,29 +272,29 @@ public void close() throws CloseCancelledException { public void extendMenu(JMenuBar menuBar) { super.extendMenu(menuBar); - // Encoding menu - EncodingMenu encodingMenu = new EncodingMenu(new DialogOwner(presenter.getWindowFrame()), textViewerDelegate.getEncoding()); - encodingMenu.addEncodingListener(this); + // Encoding menu + EncodingMenu encodingMenu = new EncodingMenu(new DialogOwner(presenter.getWindowFrame()), textViewerDelegate.getEncoding()); + encodingMenu.addEncodingListener(this); - menuBar.add(editMenu); - menuBar.add(viewMenu); - menuBar.add(encodingMenu); + menuBar.add(editMenu); + menuBar.add(viewMenu); + menuBar.add(encodingMenu); } @Override public JComponent getUI() { return ui; } - + ///////////////////////////////////// // DocumentListener implementation // ///////////////////////////////////// - + @Override public void changedUpdate(DocumentEvent e) { setSaveNeeded(true); } - + @Override public void insertUpdate(DocumentEvent e) { setSaveNeeded(true); @@ -243,7 +304,7 @@ public void insertUpdate(DocumentEvent e) { public void removeUpdate(DocumentEvent e) { setSaveNeeded(true); } - + /////////////////////////////////// // ActionListener implementation // /////////////////////////////////// @@ -252,42 +313,54 @@ public void removeUpdate(DocumentEvent e) { public void actionPerformed(ActionEvent e) { Object source = e.getSource(); - if(source == copyItem) - textEditorImpl.copy(); - else if(source == cutItem) - textEditorImpl.cut(); - else if(source == pasteItem) - textEditorImpl.paste(); - else if(source == selectAllItem) - textEditorImpl.selectAll(); - else if(source == findItem) - textEditorImpl.find(); - else if(source == findNextItem) - textEditorImpl.findNext(); - else if(source == findPreviousItem) - textEditorImpl.findPrevious(); - else if(source == toggleLineWrapItem) - textViewerDelegate.wrapLines(toggleLineWrapItem.isSelected()); - else if(source == toggleLineNumbersItem) - textViewerDelegate.showLineNumbers(toggleLineNumbersItem.isSelected()); + if (source == copyItem) + textEditorImpl.copy(); + else if (source == cutItem) + textEditorImpl.cut(); + else if (source == pasteItem) + textEditorImpl.paste(); + else if (source == selectAllItem) + textEditorImpl.selectAll(); + else if (source == findItem) + textEditorImpl.find(); + else if (source == findNextItem) + textEditorImpl.findNext(); + else if (source == findPreviousItem) + textEditorImpl.findPrevious(); } - + ///////////////////////////////////// // EncodingListener implementation // ///////////////////////////////////// @Override public void encodingChanged(Object source, String oldEncoding, String newEncoding) { - if(!askSave()) - return; // Abort if the file could not be saved - - try { - // Reload the file using the new encoding - // Note: loadDocument closes the InputStream - loadDocument(getCurrentFile().getInputStream(), newEncoding, null); - } - catch(IOException ex) { - InformationDialog.showErrorDialog(presenter.getWindowFrame(), Translator.get("read_error"), Translator.get("file_editor.cannot_read_file", getCurrentFile().getName())); - } + if (!askSave()) + return; // Abort if the file could not be saved + + try { + // Reload the file using the new encoding + // Note: loadDocument closes the InputStream + loadDocument(getCurrentFile().getInputStream(), newEncoding, null); + } catch (IOException ex) { + InformationDialog.showErrorDialog(presenter.getWindowFrame(), Translator.get("read_error"), Translator.get("file_editor.cannot_read_file", getCurrentFile().getName())); + } + } + + private MenuListener menuSelectedListener(Runnable r) { + return new MenuListener() { + @Override + public void menuSelected(MenuEvent e) { + r.run(); + } + + @Override + public void menuDeselected(MenuEvent e) { + } + + @Override + public void menuCanceled(MenuEvent e) { + } + }; } } diff --git a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextEditorImpl.java b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextEditorImpl.java index 788ae99934..f8cee16175 100644 --- a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextEditorImpl.java +++ b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextEditorImpl.java @@ -17,25 +17,51 @@ package com.mucommander.viewer.text; +import java.awt.Color; +import java.awt.Cursor; import java.awt.Font; import java.awt.Insets; +import java.awt.Point; import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.io.BufferedWriter; +import java.io.File; import java.io.IOException; import java.io.Reader; import java.io.Writer; +import java.lang.reflect.Field; +import java.net.URL; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.swing.JFrame; -import javax.swing.JTextArea; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; import javax.swing.event.DocumentListener; +import javax.swing.event.HyperlinkEvent; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultEditorKit; import javax.swing.text.Document; +import org.fife.ui.rsyntaxtextarea.FileTypeUtil; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; +import org.fife.ui.rtextarea.RTextScrollPane; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mucommander.commons.file.AbstractFile; +import com.mucommander.commons.runtime.OsFamily; import com.mucommander.commons.util.StringUtils; +import com.mucommander.core.desktop.DesktopManager; import com.mucommander.job.impl.SearchJob; import com.mucommander.ui.theme.ColorChangedEvent; import com.mucommander.ui.theme.FontChangedEvent; @@ -50,228 +76,440 @@ */ class TextEditorImpl implements ThemeListener { - private JFrame frame; - - private JTextArea textArea; - - /** Indicates whether there is a line separator in the original file */ - private boolean lineSeparatorExists; - - //////////////////// - // Initialization // - //////////////////// - - public TextEditorImpl(boolean isEditable) { - // Initialize text area - initTextArea(isEditable); - - // Listen to theme changes to update the text area if it is visible - ThemeManager.addCurrentThemeListener(this); - } - - private void initTextArea(boolean isEditable) { - textArea = new JTextArea() { - @Override - public Insets getInsets() { - return new Insets(4, 3, 4, 3); - } - }; - - textArea.setEditable(isEditable); - // Use theme colors and font - textArea.setForeground(ThemeManager.getCurrentColor(Theme.EDITOR_FOREGROUND_COLOR)); - textArea.setCaretColor(ThemeManager.getCurrentColor(Theme.EDITOR_FOREGROUND_COLOR)); - textArea.setBackground(ThemeManager.getCurrentColor(Theme.EDITOR_BACKGROUND_COLOR)); - textArea.setSelectedTextColor(ThemeManager.getCurrentColor(Theme.EDITOR_SELECTED_FOREGROUND_COLOR)); - textArea.setSelectionColor(ThemeManager.getCurrentColor(Theme.EDITOR_SELECTED_BACKGROUND_COLOR)); - textArea.setFont(ThemeManager.getCurrentFont(Theme.EDITOR_FONT)); - - textArea.setWrapStyleWord(true); - - textArea.addMouseWheelListener(new MouseWheelListener() { - - /** - * Mouse events bubble up until finding a component with a relative listener. - * That's why in case we get an event that needs to initiate its default behavior, - * we just bubble it up to the parent component of the JTextArea. - */ - public void mouseWheelMoved(MouseWheelEvent e) { - boolean isCtrlPressed = (e.getModifiers() & KeyEvent.CTRL_MASK)!=0; - if (isCtrlPressed) { - Font currentFont = textArea.getFont(); - int currentFontSize = currentFont.getSize(); - boolean rotationUp = e.getWheelRotation() < 0; - if ((!rotationUp && currentFontSize > 1) || rotationUp) { - Font newFont = new Font(currentFont.getName(), currentFont.getStyle(), currentFontSize + (rotationUp ? 1 : -1)); - textArea.setFont(newFont); - } - } - else { - textArea.getParent().dispatchEvent(e); - } - } - }); - } - - ///////////////// - // Search code // - ///////////////// - - void find() { - FindDialog findDialog = new FindDialog(frame); - - if (findDialog.wasValidated()) { - String searchString = findDialog.getSearchString().toLowerCase(); - - if (!StringUtils.isNullOrEmpty(searchString)) { - SearchJob.lastSearchString = searchString; - doSearch(0, true); - } - } - } - - - void findNext() { - if (StringUtils.isNullOrEmpty(SearchJob.lastSearchString)) - find(); - else - doSearch(textArea.getSelectionEnd(), true); - } - - void findPrevious() { - doSearch(textArea.getSelectionStart() - 1, false); - } - - private String getTextLC() { - return textArea.getText().toLowerCase(); - } - - private void doSearch(int startPos, boolean forward) { - String searchString = SearchJob.lastSearchString; - if (StringUtils.isNullOrEmpty(searchString)) - return; - - textArea.requestFocus(); - - int pos; - if (forward) { - pos = getTextLC().indexOf(searchString, startPos); - } else { - pos = getTextLC().lastIndexOf(searchString, startPos); - } - if (pos >= 0) { - textArea.select(pos, pos + searchString.length()); - } else { - // Beep when no match has been found. - // The beep method is called from a separate thread because this method seems to lock until the beep has - // been played entirely. If the 'Find next' shortcut is left pressed, a series of beeps will be played when - // the end of the file is reached, and we don't want those beeps to played one after the other as to: - // 1/ not lock the event thread - // 2/ have those beeps to end rather sooner than later - new Thread(() -> Toolkit.getDefaultToolkit().beep()).start(); - } - } - - public boolean isWrap() { - return textArea.getLineWrap(); - } - - //////////////////////////// - // Package-access methods // - //////////////////////////// - - void wrap(boolean isWrap) { - textArea.setLineWrap(isWrap); - textArea.repaint(); - } - - void copy() { - textArea.copy(); - } - - void cut() { - textArea.cut(); - } - - void paste() { - textArea.paste(); - } - - void selectAll() { - textArea.selectAll(); - } - - void requestFocus() { - textArea.requestFocus(); - } - - JTextArea getTextArea() { - return textArea; - } - - void addDocumentListener(DocumentListener documentListener) { - textArea.getDocument().addDocumentListener(documentListener); - } - - void read(Reader reader) throws IOException { - // Feed the file's contents to text area - textArea.read(reader, null); - - // If there are more than one lines, there is a line separator - lineSeparatorExists = textArea.getLineCount() > 1; - - // Move cursor to the top - textArea.setCaretPosition(0); - } - - void write(Writer writer) throws IOException { - Document document = textArea.getDocument(); - - // According to the documentation in DefaultEditorKit, the line separator is set to be as the system property - // if no other line separator exists in the file, but in practice it is not, so this is a workaround for it - if (!lineSeparatorExists) - document.putProperty(DefaultEditorKit.EndOfLineStringProperty, System.getProperty("line.separator")); - - try { - textArea.getUI().getEditorKit(textArea).write(new BufferedWriter(writer), document, 0, document.getLength()); - } - catch(BadLocationException e) { - throw new IOException(e.getMessage()); - } - } - - ////////////////////////////////// - // ThemeListener implementation // - ////////////////////////////////// - - /** - * Receives theme color changes notifications. - */ - public void colorChanged(ColorChangedEvent event) { - switch(event.getColorId()) { - case Theme.EDITOR_FOREGROUND_COLOR: - textArea.setForeground(event.getColor()); - break; - - case Theme.EDITOR_BACKGROUND_COLOR: - textArea.setBackground(event.getColor()); - break; - - case Theme.EDITOR_SELECTED_FOREGROUND_COLOR: - textArea.setSelectedTextColor(event.getColor()); - break; - - case Theme.EDITOR_SELECTED_BACKGROUND_COLOR: - textArea.setSelectionColor(event.getColor()); - break; - } - } - - /** - * Receives theme font changes notifications. - */ - public void fontChanged(FontChangedEvent event) { - if(event.getFontId() == Theme.EDITOR_FONT) - textArea.setFont(event.getFont()); - } + private static final Logger LOGGER = LoggerFactory.getLogger(TextEditorImpl.class); + + private JFrame frame; + + private RSyntaxTextArea textArea; + + private RTextScrollPane scrollPane; + + /** + * Indicates whether there is a line separator in the original file + */ + private boolean lineSeparatorExists; + + /** + * A listener that is being called when syntax style has been changed. + */ + private Consumer syntaxChangeListener; + + //////////////////// + // Initialization // + //////////////////// + + public TextEditorImpl(boolean isEditable) { + // Initialize text area + initTextArea(isEditable); + + // Listen to theme changes to update the text area if it is visible + ThemeManager.addCurrentThemeListener(this); + } + + private void initTextArea(boolean isEditable) { + textArea = new RSyntaxTextArea() { + @Override + public Insets getInsets() { + return new Insets(0, 3, 4, 3); + } + }; + scrollPane = new RTextScrollPane(textArea, TextViewerPreferences.LINE_NUMBERS.getValue()); + + if (DesktopManager.canBrowse()) { + int linkScanningMask = OsFamily.MAC_OS.isCurrent() ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK; + textArea.setLinkScanningMask(linkScanningMask); + textArea.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + if ((e.getModifiersEx() & linkScanningMask) == linkScanningMask) + fakeMouseMove(e); + } + + @Override + public void keyReleased(KeyEvent e) { + fakeMouseMove(e); + } + + private void fakeMouseMove(KeyEvent e) { + Point mousePosition = textArea.getMousePosition(); + if (mousePosition != null) { + MouseEvent mouseEvent = new MouseEvent(textArea, e.getID(), e.getWhen(), e.getModifiersEx(), mousePosition.x, mousePosition.y, 0, false); + Stream.of(textArea.getMouseMotionListeners()).forEach(listener -> listener.mouseMoved(mouseEvent)); + } + } + }); + textArea.addHyperlinkListener((event) -> { + URL url = event.getURL(); + if (url != null && event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { + SwingUtilities.invokeLater(() -> { + try { + DesktopManager.browse(url); + } catch (IOException e) { + LOGGER.error("Error opening link in a browser", e); + } + }); + } + }); + textArea.setHyperlinksEnabled(true); + } else { + textArea.setHyperlinksEnabled(false); + } + textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE); + + textArea.setEditable(isEditable); + // Use theme colors and font + textArea.setForeground(ThemeManager.getCurrentColor(Theme.EDITOR_FOREGROUND_COLOR)); + textArea.setCaretColor(ThemeManager.getCurrentColor(Theme.EDITOR_FOREGROUND_COLOR)); + textArea.setBackground(ThemeManager.getCurrentColor(Theme.EDITOR_BACKGROUND_COLOR)); + Color selFgColor = ThemeManager.getCurrentColor(Theme.EDITOR_SELECTED_FOREGROUND_COLOR); + // Override Alpha to make selection visible across almost all L&Fs. + int alpha = 170; + textArea.setSelectedTextColor(new Color(selFgColor.getRed(), selFgColor.getGreen(), selFgColor.getBlue(), alpha)); + Color selBgColor = ThemeManager.getCurrentColor(Theme.EDITOR_SELECTED_BACKGROUND_COLOR); + textArea.setSelectionColor(new Color(selBgColor.getRed(), selBgColor.getGreen(), selBgColor.getBlue(), alpha)); + // TODO by default I guess, at least on macOS in SolarizedDark theme, the editor font is not-monospaced! + // tabs may not be shown properly in length (dots are much smaller than letters). + textArea.setFont(ThemeManager.getCurrentFont(Theme.EDITOR_FONT)); + + textArea.setWrapStyleWord(true); + + textArea.addMouseWheelListener(new MouseWheelListener() { + + /** + * Mouse events bubble up until finding a component with a relative listener. + * That's why in case we get an event that needs to initiate its default behavior, + * we just bubble it up to the parent component of the JTextArea. + */ + public void mouseWheelMoved(MouseWheelEvent e) { + boolean isCtrlPressed = (e.getModifiers() & KeyEvent.CTRL_MASK) != 0; + if (isCtrlPressed) { + Font currentFont = textArea.getFont(); + int currentFontSize = currentFont.getSize(); + boolean rotationUp = e.getWheelRotation() < 0; + if (rotationUp || currentFontSize > 1) { + Font newFont = new Font(currentFont.getName(), currentFont.getStyle(), currentFontSize + (rotationUp ? 1 : -1)); + textArea.setFont(newFont); + } + } else { + scrollPane.dispatchEvent(e); + } + } + }); + // Setting TEXT_CURSOR for text area regardless if it is editable or readonly - for both it makes sense. + // TODO still not ideal - initially most often it opens with DEFAULT_CURSOR, moving to line numbers panel and back to editor it shows TEXT_CURSOR properly + textArea.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); + } + + ///////////////// + // Search code // + ///////////////// + + void find() { + FindDialog findDialog = new FindDialog(frame); + + if (findDialog.wasValidated()) { + String searchString = findDialog.getSearchString(); + + if (!StringUtils.isNullOrEmpty(searchString)) { + SearchJob.lastSearchString = searchString; + doSearch(0, true); + } + } + } + + void findNext() { + if (StringUtils.isNullOrEmpty(SearchJob.lastSearchString)) { + find(); + } else { + doSearch(textArea.getSelectionEnd(), true); + } + } + + void findPrevious() { + doSearch(textArea.getSelectionStart() - 1, false); + } + + void convertTabsToSpaces() { textArea.convertTabsToSpaces(); } + + void convertSpacesToTabs() { textArea.convertSpacesToTabs(); } + + private String getTextLC() { + return textArea.getText().toLowerCase(); + } + + private void doSearch(int startPos, boolean forward) { + String searchString = SearchJob.lastSearchString; + if (StringUtils.isNullOrEmpty(searchString)) { + return; + } + + // The search is case-insensitive at the moment + searchString = searchString.toLowerCase(); + + textArea.requestFocus(); + + int pos; + if (forward) { + pos = getTextLC().indexOf(searchString, startPos); + } else { + pos = getTextLC().lastIndexOf(searchString, startPos); + } + if (pos >= 0) { + textArea.select(pos, pos + searchString.length()); + } else { + // Beep when no match has been found. + // The beep method is called from a separate thread because this method seems to lock until the beep has + // been played entirely. If the 'Find next' shortcut is left pressed, a series of beeps will be played when + // the end of the file is reached, and we don't want those beeps to played one after the other as to: + // 1/ not lock the event thread + // 2/ have those beeps to end rather sooner than later + new Thread(Toolkit.getDefaultToolkit()::beep).start(); + } + } + + //////////////////////////// + // Package-access methods // + //////////////////////////// + + void wrap(boolean isWrap) { + textArea.setLineWrap(isWrap); + textArea.repaint(); + } + + void animateBracketMatching(boolean aBool) { + textArea.setAnimateBracketMatching(aBool); + } + + void antiAliasing(boolean aBool) { + textArea.setAntiAliasingEnabled(aBool); + } + + void autoIndent(boolean aBool) { + textArea.setAutoIndentEnabled(aBool); + } + + void bracketMatching(boolean aBool) { + textArea.setBracketMatchingEnabled(aBool); + } + + void clearWhitespaceLines(boolean aBool) { + textArea.setClearWhitespaceLinesEnabled(aBool); + } + + void closeCurlyBraces(boolean aBool) { + textArea.setCloseCurlyBraces(aBool); + } + + void closeMarkupTags(boolean aBool) { + textArea.setCloseMarkupTags(aBool); + } + + void codeFolding(boolean aBool) { + scrollPane.setFoldIndicatorEnabled(aBool); + textArea.setCodeFoldingEnabled(aBool); + } + + void dragEnabled(boolean aBool) { + textArea.setDragEnabled(aBool); + } + + void eolMarkersVisible(boolean aBool) { + textArea.setEOLMarkersVisible(aBool); + } + + void fadeCurrentLineHighlight(boolean aBool) { + textArea.setFadeCurrentLineHighlight(aBool); + } + + void highlightCurrentLine(boolean aBool) { + textArea.setHighlightCurrentLine(aBool); + } + + void markOccurrences(boolean aBool) { + textArea.setMarkOccurrences(aBool); + } + + void paintTabLines(boolean aBool) { + textArea.setPaintTabLines(aBool); + } + + void roundedSelectionEdges(boolean aBool) { + textArea.setRoundedSelectionEdges(aBool); + } + + void showMatchedBracketPopup(boolean aBool) { + textArea.setShowMatchedBracketPopup(aBool); + } + + void tabsEmulated(boolean aBool) { + textArea.setTabsEmulated(aBool); + } + + void whitespaceVisible(boolean aBool) { + textArea.setWhitespaceVisible(aBool); + } + + int getTabSize() { + return textArea.getTabSize(); + } + + void setTabSize(int size) { + textArea.setTabSize(size); + } + + public void undo() { + textArea.undoLastAction(); + } + + public boolean canUndo() { + return textArea.canUndo(); + } + + public void redo() { + textArea.redoLastAction(); + } + + public boolean canRedo() { + return textArea.canRedo(); + } + + void copy() { + textArea.copy(); + } + + void cut() { + textArea.cut(); + } + + void paste() { + textArea.paste(); + } + + void selectAll() { + textArea.selectAll(); + } + + public void showLineNumbers(boolean show) { + scrollPane.setLineNumbersEnabled(show); + } + + public boolean getLineNumbersEnabled() { + return scrollPane.getLineNumbersEnabled(); + } + + /** + * Returns the map of supported syntax styles, where key is mime-type and value is + * human-readable name of the style. + * @return the map, won't be null. + */ + Map getSyntaxStyles() { + Map syntaxMap = new LinkedHashMap<>(); + // TODO remove reflection when/if https://github.com/bobbylight/RSyntaxTextArea/issues/479 implemented + Field[] fields = SyntaxConstants.class.getFields(); + for (Field field : fields) { + String name = field.getName(); + if (name.startsWith("SYNTAX_STYLE_")) { + String[] parts = name.substring("SYNTAX_STYLE_".length()).split("_"); + String prettyName = Stream.of(parts).map(String::toLowerCase).collect(Collectors.joining(" ")); + try { + syntaxMap.put((String) field.get(null), prettyName); + } catch (IllegalAccessException e) { + LOGGER.error("Ooops while trying to get syntax style mime-type", e); + } + } + } + return syntaxMap; + } + + void setSyntaxStyle(String syntaxStyleMimeType) { + textArea.setSyntaxEditingStyle(syntaxStyleMimeType); + } + + public void setSyntaxStyle(AbstractFile file) { + String mimeType = FileTypeUtil.get().guessContentType( + new File(file.getCanonicalPath()), true); + textArea.setSyntaxEditingStyle(mimeType); + if (syntaxChangeListener != null) { + syntaxChangeListener.accept(mimeType); + } + } + + public void setSyntaxStyleChangeListener(Consumer syntaxChangeListener) { + this.syntaxChangeListener = syntaxChangeListener; + } + + JScrollPane getScrollPane() { + return scrollPane; + } + + void addDocumentListener(DocumentListener documentListener) { + textArea.getDocument().addDocumentListener(documentListener); + } + + void read(Reader reader) throws IOException { + // Feed the file's contents to text area + textArea.read(reader, null); + + // If there are more than one lines, there is a line separator + lineSeparatorExists = textArea.getLineCount() > 1; + + // Move cursor to the top + textArea.setCaretPosition(0); + } + + void write(Writer writer) throws IOException { + Document document = textArea.getDocument(); + + // According to the documentation in DefaultEditorKit, the line separator is set to be as the system property + // if no other line separator exists in the file, but in practice it is not, so this is a workaround for it + if (!lineSeparatorExists) { + document.putProperty(DefaultEditorKit.EndOfLineStringProperty, System.getProperty("line.separator")); + } + try { + textArea.getUI().getEditorKit(textArea).write(new BufferedWriter(writer), document, 0, document.getLength()); + } catch (BadLocationException e) { + throw new IOException(e.getMessage()); + } + } + + public void setFocusAndCursorOnFirstLine() { + textArea.requestFocusInWindow(); + textArea.setCaretPosition(0); + } + + ////////////////////////////////// + // ThemeListener implementation // + ////////////////////////////////// + + /** + * Receives theme color changes notifications. + */ + public void colorChanged(ColorChangedEvent event) { + switch (event.getColorId()) { + case Theme.EDITOR_FOREGROUND_COLOR: + textArea.setForeground(event.getColor()); + break; + + case Theme.EDITOR_BACKGROUND_COLOR: + textArea.setBackground(event.getColor()); + break; + + case Theme.EDITOR_SELECTED_FOREGROUND_COLOR: + textArea.setSelectedTextColor(event.getColor()); + break; + + case Theme.EDITOR_SELECTED_BACKGROUND_COLOR: + textArea.setSelectionColor(event.getColor()); + break; + } + } + + /** + * Receives theme font changes notifications. + */ + public void fontChanged(FontChangedEvent event) { + if (event.getFontId() == Theme.EDITOR_FONT) { + textArea.setFont(event.getFont()); + } + } } diff --git a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextFileViewerService.java b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextFileViewerService.java index 5d128c74b5..cfe0548f9b 100644 --- a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextFileViewerService.java +++ b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextFileViewerService.java @@ -36,6 +36,11 @@ */ public class TextFileViewerService implements FileViewerService, FileEditorService { + /** + * Max file size the editor can open. + */ + private static final int MAX_FILE_SIZE_FOR_EDIT = 1024*1024; + @Override public String getName() { return "Text"; @@ -61,7 +66,7 @@ public boolean canViewFile(AbstractFile file) throws WarnUserException { return false; } } catch (IOException e) { - // Not much too do + // Not much to do } finally { if (in != null) { try { @@ -73,7 +78,7 @@ public boolean canViewFile(AbstractFile file) throws WarnUserException { // Warn the user if the file is large that a certain size as the whole file is loaded into memory // (in a JTextArea) - if (file.getSize() > 1048576) { + if (file.getSize() > MAX_FILE_SIZE_FOR_EDIT) { throw new WarnUserException(Translator.get("file_viewer.large_file_warning")); } diff --git a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextLineNumbersPanel.java b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextLineNumbersPanel.java deleted file mode 100644 index 52b7a66297..0000000000 --- a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextLineNumbersPanel.java +++ /dev/null @@ -1,360 +0,0 @@ -package com.mucommander.viewer.text; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Insets; -import java.awt.Point; -import java.awt.Rectangle; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.HashMap; - -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import javax.swing.border.Border; -import javax.swing.border.CompoundBorder; -import javax.swing.border.EmptyBorder; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; -import javax.swing.text.AttributeSet; -import javax.swing.text.BadLocationException; -import javax.swing.text.Element; -import javax.swing.text.JTextComponent; -import javax.swing.text.StyleConstants; -import javax.swing.text.Utilities; - -/** - * Panel in which the line numbers at a given text component are presented. - * it is used in JScrollPane as a row header. - * - * @author Arik Hadas - */ -public class TextLineNumbersPanel extends JPanel implements CaretListener, DocumentListener, PropertyChangeListener { - - private final static int HEIGHT = Integer.MAX_VALUE - 1000000; - - public static enum ALIGNMENT{ LEFT, CENTER, RIGHT } - - // Text component this TextTextLineNumber component is in sync with - private JTextComponent component; - - // Properties that can be changed - private Color currentLineForeground; - private int minimumDisplayDigits; - private double digitAlignment; - - // Keep history information to reduce the number of times the component needs to be repainted - private int lastDigits; - private int lastHeight; - private int lastLine; - - private HashMap fonts; - - /** - * Create a line number component for a text component. This minimum - * display width will be based on 3 digits. - * - * @param component the related text component - */ - public TextLineNumbersPanel(JTextComponent component) { - this(component, 3); - } - - /** - * Create a line number component for a text component. - * - * @param component the related text component - * @param minimumDisplayDigits the number of digits used to calculate - * the minimum width of the component - */ - public TextLineNumbersPanel(JTextComponent component, int minimumDisplayDigits) { - this(component, minimumDisplayDigits, new EmptyBorder(0, 0, 0, 2), 4, ALIGNMENT.CENTER); - } - - public TextLineNumbersPanel(JTextComponent component, int minimumDisplayDigits, Border border, int borderGap, - ALIGNMENT alignment) { - this.component = component; - - setBackground(Color.LIGHT_GRAY); - setForeground(Color.black); - setCurrentLineForeground(new Color(0,0,255)); - setDigitAlignment(alignment); - setBorder(border, borderGap); - setMinimumDisplayDigits( minimumDisplayDigits); - setFont(component.getFont()); - - component.getDocument().addDocumentListener(this); - component.addPropertyChangeListener("font", this); - component.addCaretListener(this); - } - - /** - * Set the alignment of the line numbers strings within the panel - * - * @param alignment the line numbers alignment - */ - private void setDigitAlignment(ALIGNMENT alignment) { - switch(alignment) { - case LEFT: - digitAlignment = 0; - case RIGHT: - digitAlignment = 1; - case CENTER: - digitAlignment = 0.5; - } - } - - /** - * If we'll want to highlight current line , we should - * set the current line number color using this method - * - * @param currentLineForeground current line number color - */ - private void setCurrentLineForeground( Color currentLineForeground ) { - this.currentLineForeground = currentLineForeground; - } - - /** - * The border gap is used in calculating the left and right insets of the - * border. Default value is 5. - * - * @param borderGap the gap in pixels - */ - private void setBorder(Border border, int borderGap) { - Border inner = new EmptyBorder(0, borderGap, 0, borderGap); - setBorder( new CompoundBorder(border, inner) ); - lastDigits = 0; - setPreferredWidth(); - } - - /** - * Specify the minimum number of digits used to calculate the preferred - * width of the component. Default is 3. - * - * @param minimumDisplayDigits the number digits used in the preferred - * width calculation - */ - private void setMinimumDisplayDigits(int minimumDisplayDigits) { - this.minimumDisplayDigits = minimumDisplayDigits; - setPreferredWidth(); - } - - /** - * Calculate the width needed to display the maximum line number - */ - protected void setPreferredWidth() { - Element root = component.getDocument().getDefaultRootElement(); - int lines = root.getElementCount(); - int digits = Math.max(String.valueOf(lines).length() + 2, minimumDisplayDigits); - - // Update sizes when number of digits in the line number changes - if (lastDigits != digits) { - lastDigits = digits; - FontMetrics fontMetrics = getFontMetrics( getFont() ); - int width = fontMetrics.charWidth( '0' ) * digits; - Insets insets = getInsets(); - int preferredWidth = insets.left + insets.right + width; - - Dimension d = getPreferredSize(); - d.setSize(preferredWidth, HEIGHT); - setPreferredSize( d ); - setSize( d ); - } - } - - /* - * We need to know if the caret is currently positioned on the line we - * are about to paint so the line number can be highlighted. - * if the current line foreground is not set, just return false - */ - private boolean isCurrentLine(int rowStartOffset) - { - if (currentLineForeground == null) - return false; - - int caretPosition = component.getCaretPosition(); - Element root = component.getDocument().getDefaultRootElement(); - - return root.getElementIndex( rowStartOffset ) == root.getElementIndex(caretPosition); - } - - /** - * Draw the line numbers - */ - @Override - public void paintComponent(Graphics g) { - super.paintComponent(g); - - // Determine the width of the space available to draw the line number - FontMetrics fontMetrics = component.getFontMetrics( component.getFont() ); - Insets insets = getInsets(); - int availableWidth = getSize().width - insets.left - insets.right; - - // Determine the rows to draw within the clipped bounds. - Rectangle clip = g.getClipBounds(); - int rowStartOffset = component.viewToModel( new Point(0, clip.y) ); - int endOffset = component.viewToModel( new Point(0, clip.y + clip.height) ); - - while (rowStartOffset <= endOffset) { - try { - g.setColor(isCurrentLine(rowStartOffset) ? currentLineForeground : getForeground()); - - // Get the line number as a string and then determine the - // "X" and "Y" offsets for drawing the string. - String lineNumber = getTextLineNumber(rowStartOffset); - int stringWidth = fontMetrics.stringWidth( lineNumber ); - int x = getOffsetX(availableWidth, stringWidth) + insets.left; - int y = getOffsetY(rowStartOffset, fontMetrics); - g.drawString(lineNumber, x, y); - - // Move to the next row - rowStartOffset = Utilities.getRowEnd(component, rowStartOffset) + 1; - } - catch(Exception e) {} - } - } - - /* - * Get the line number to be drawn. The empty string will be returned - * when a line of text has wrapped. - */ - protected String getTextLineNumber(int rowStartOffset) { - Element root = component.getDocument().getDefaultRootElement(); - int index = root.getElementIndex( rowStartOffset ); - Element line = root.getElement( index ); - - return line.getStartOffset() == rowStartOffset ? String.valueOf(index + 1) : ""; - } - - /* - * Determine the X offset to properly align the line number when drawn - */ - private int getOffsetX(int availableWidth, int stringWidth) { - return (int)((availableWidth - stringWidth) * digitAlignment); - } - - /* - * Determine the Y offset for the current row - */ - private int getOffsetY(int rowStartOffset, FontMetrics fontMetrics) throws BadLocationException { - // Get the bounding rectangle of the row - - Rectangle r = component.modelToView( rowStartOffset ); - int lineHeight = fontMetrics.getHeight(); - int y = r.y + r.height; - int descent = 0; - - // The text needs to be positioned above the bottom of the bounding - // rectangle based on the descent of the font(s) contained on the row. - - - if (r.height == lineHeight) { // default font is being used - descent = fontMetrics.getDescent(); - } - else { // We need to check all the attributes for font changes - if (fonts == null) - fonts = new HashMap(); - - Element root = component.getDocument().getDefaultRootElement(); - int index = root.getElementIndex( rowStartOffset ); - Element line = root.getElement( index ); - - for (int i = 0; i < line.getElementCount(); i++) { - Element child = line.getElement(i); - AttributeSet as = child.getAttributes(); - String fontFamily = (String)as.getAttribute(StyleConstants.FontFamily); - Integer fontSize = (Integer)as.getAttribute(StyleConstants.FontSize); - String key = fontFamily + fontSize; - - FontMetrics fm = fonts.get( key ); - - if (fm == null) - { - Font font = new Font(fontFamily, Font.PLAIN, fontSize); - fm = component.getFontMetrics( font ); - fonts.put(key, fm); - } - - descent = Math.max(descent, fm.getDescent()); - } - } - - return y - descent; - } - - ///////////////////////////////////// - // DocumentListener implementation // - ///////////////////////////////////// - - public void changedUpdate(DocumentEvent e) { - documentChanged(); - } - - public void insertUpdate(DocumentEvent e) { - documentChanged(); - } - - public void removeUpdate(DocumentEvent e) { - documentChanged(); - } - - /* - * A document change may affect the number of displayed lines of text. - * Therefore the lines numbers will also change. - */ - private void documentChanged() { - // Preferred size of the component has not been updated at the time - // the DocumentEvent is fired - SwingUtilities.invokeLater(() -> { - int preferredHeight = component.getPreferredSize().height; - - // Document change has caused a change in the number of lines. - // Repaint to reflect the new line numbers - if (lastHeight != preferredHeight) { - setPreferredWidth(); - repaint(); - lastHeight = preferredHeight; - } - }); - } - - ////////////////////////////////// - // CaretListener implementation // - ////////////////////////////////// - - public void caretUpdate(CaretEvent e) - { - if (currentLineForeground == null) - return; - - // Get the line the caret is positioned on - int caretPosition = component.getCaretPosition(); - Element root = component.getDocument().getDefaultRootElement(); - int currentLine = root.getElementIndex( caretPosition ); - - // Need to repaint so the correct line number can be highlighted - - if (lastLine != currentLine) - { - repaint(); - lastLine = currentLine; - } - } - - /////////////////////////////////////////// - // PropertyChangeListener implementation // - /////////////////////////////////////////// - - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getNewValue() instanceof Font) { - setFont((Font) evt.getNewValue()); - lastDigits = 0; - setPreferredWidth(); - } - } -} diff --git a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewer.java b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewer.java index 2ef32f8a74..291b580a14 100644 --- a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewer.java +++ b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewer.java @@ -17,21 +17,34 @@ package com.mucommander.viewer.text; +import static com.mucommander.viewer.text.TextViewerSnapshot.TEXT_FILE_PRESENTER_SECTION; + import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.io.BufferedReader; +import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.ButtonGroup; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JScrollPane; import javax.swing.KeyStroke; import javax.swing.event.DocumentListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.mucommander.commons.file.AbstractFile; import com.mucommander.commons.file.FileOperation; import com.mucommander.commons.io.EncodingDetector; @@ -49,9 +62,6 @@ import com.mucommander.ui.encoding.EncodingMenu; import com.mucommander.viewer.FileViewer; import com.mucommander.viewer.ViewerPresenter; -import java.awt.event.ActionListener; -import javax.swing.AbstractAction; -import javax.swing.JScrollPane; /** * A simple text viewer. Most of the implementation is located in {@link TextEditorImpl}. @@ -60,21 +70,13 @@ */ public class TextViewer implements FileViewer, EncodingListener, ActionListener { - public final static String CUSTOM_FULL_SCREEN_EVENT = "CUSTOM_FULL_SCREEN_EVENT"; + private static final Logger LOGGER = LoggerFactory.getLogger(TextViewer.class); - private JScrollPane ui = new JScrollPane(); + private JScrollPane ui; private ViewerPresenter presenter; private TextEditorImpl textEditorImpl; private AbstractFile currentFile; - private static boolean fullScreen = MuSnapshot.getSnapshot().getBooleanVariable(TextViewerSnapshot.TEXT_FILE_PRESENTER_FULL_SCREEN); - - private static boolean lineWrap = MuSnapshot.getSnapshot().getVariable(TextViewerSnapshot.TEXT_FILE_PRESENTER_LINE_WRAP, TextViewerSnapshot.DEFAULT_LINE_WRAP); - - private static boolean lineNumbers = MuSnapshot.getSnapshot().getVariable(TextViewerSnapshot.TEXT_FILE_PRESENTER_LINE_NUMBERS, TextViewerSnapshot.DEFAULT_LINE_NUMBERS); - - private TextLineNumbersPanel lineNumbersPanel; - /** Menu items */ // Menus // private JMenu editMenu; @@ -85,8 +87,6 @@ public class TextViewer implements FileViewer, EncodingListener, ActionListener private JMenuItem findItem; private JMenuItem findNextItem; private JMenuItem findPreviousItem; - private JMenuItem toggleLineWrapItem; - private JMenuItem toggleLineNumbersItem; private String encoding; @@ -102,40 +102,25 @@ public class TextViewer implements FileViewer, EncodingListener, ActionListener private void init() { attachView(); - initLineNumbersPanel(); - showLineNumbers(lineNumbers); - - textEditorImpl.wrap(lineWrap); + showLineNumbers(TextViewerPreferences.LINE_NUMBERS.getValue()); + for (TextViewerPreferences pref : TextViewerPreferences.values()) { + if (pref.isTextEditorPref()) { + pref.setValue(textEditorImpl, pref.getValue()); + } + } + textEditorImpl.setTabSize(MuSnapshot.getSnapshot().getVariable( + TEXT_FILE_PRESENTER_SECTION + ".tab_size", 4)); initMenuBarItems(); } protected void attachView() { - ui.getViewport().setView(textEditorImpl.getTextArea()); + ui = textEditorImpl.getScrollPane(); } - static void setFullScreen(boolean fullScreen) { - TextViewer.fullScreen = fullScreen; - } - - public static boolean isFullScreen() { - return fullScreen; - } - - static void setLineWrap(boolean lineWrap) { - TextViewer.lineWrap = lineWrap; - } - - public static boolean isLineWrap() { - return lineWrap; - } - - static void setLineNumbers(boolean lineNumbers) { - TextViewer.lineNumbers = lineNumbers; - } - - public static boolean isLineNumbers() { - return lineNumbers; + void setLineNumbers(boolean lineNumbers) { + TextViewerPreferences.LINE_NUMBERS.setValue(lineNumbers); + textEditorImpl.showLineNumbers(lineNumbers); } void startEditing(AbstractFile file, DocumentListener documentListener) throws IOException { @@ -149,15 +134,65 @@ void startEditing(AbstractFile file, DocumentListener documentListener) throws I try { in = file.getRandomAccessInputStream(); } catch (IOException e) { + LOGGER.debug("There was an exception", e); // In that case we simply get an InputStream + in = file.getInputStream(); } - } - - if (in == null) { + } else { in = file.getInputStream(); } - String encoding = EncodingDetector.detectEncoding(in); + AtomicBoolean is8bit = new AtomicBoolean(); + // The FilterInputStream Wraps/Proxies a given InputStream to snoop if any read characters were + // 8bit to distinguish ISO-8859-1 (and others) from 7-bit ASCII (US-ASCII). + // See: https://github.com/mucommander/mucommander/issues/824 + String encoding = EncodingDetector.detectEncoding(new FilterInputStream(in) { + @Override + public int read() throws IOException { + int b = in.read(); + if (!is8bit.get() && check8Bit(b)) { + is8bit.set(true); + } + return b; + } + + @Override + public int read(byte[] bytes) throws IOException { + int ret = in.read(bytes); + if (ret > 0 && !is8bit.get()) { + for (byte b : bytes) { + if (check8Bit(b)) { + is8bit.set(true); + break; + } + } + } + return ret; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int ret = in.read(b, off, len); + if (ret > 0 && !is8bit.get()) { + for (int i = off; i < off + ret; i++) { + if (check8Bit(b[i])) { + is8bit.set(true); + break; + } + } + } + return ret; + } + + private boolean check8Bit(int b) { + return (b & 0x80) != 0; + } + }); + + // Override 7-bit ISO-8859-1 encoding to ensure UTF-8 chars that user may enter are saved correctly. + if (!is8bit.get() && "ISO-8859-1".equalsIgnoreCase(encoding)) { + encoding = "UTF-8"; + } if (in instanceof RandomAccessInputStream) { // Seek to the beginning of the file and reuse the stream @@ -173,7 +208,7 @@ void startEditing(AbstractFile file, DocumentListener documentListener) throws I } // Load the file into the text area - loadDocument(in, encoding, documentListener); + loadDocument(file, in, encoding, documentListener); } finally { if (in != null) { try { @@ -185,7 +220,7 @@ void startEditing(AbstractFile file, DocumentListener documentListener) throws I } } - void loadDocument(InputStream in, final String encoding, DocumentListener documentListener) throws IOException { + void loadDocument(AbstractFile file, InputStream in, final String encoding, DocumentListener documentListener) throws IOException { // If the encoding is UTF-something, wrap the stream in a BOMInputStream to filter out the byte-order mark // (see ticket #245) if (encoding != null && encoding.toLowerCase().startsWith("utf")) { @@ -196,10 +231,12 @@ void loadDocument(InputStream in, final String encoding, DocumentListener docume this.encoding = encoding == null || !Charset.isSupported(encoding) ? "UTF-8" : encoding; textEditorImpl.read(new BufferedReader(new InputStreamReader(in, this.encoding))); + textEditorImpl.setSyntaxStyle(file); // Listen to document changes - if(documentListener!=null) + if (documentListener!=null) { textEditorImpl.addDocumentListener(documentListener); + } } @Override @@ -210,17 +247,6 @@ public JComponent getUI() { @Override public void setPresenter(ViewerPresenter presenter) { this.presenter = presenter; - - presenter.setFullScreen(isFullScreen()); - - ui.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.CTRL_MASK), CUSTOM_FULL_SCREEN_EVENT); - ui.getActionMap().put(CUSTOM_FULL_SCREEN_EVENT, new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - setFullScreen(!presenter.isFullScreen()); - presenter.setFullScreen(isFullScreen()); - } - }); } @Override @@ -239,20 +265,10 @@ String getEncoding() { } protected void showLineNumbers(boolean show) { - ui.setRowHeaderView(show ? lineNumbersPanel : null); setLineNumbers(show); } - protected void wrapLines(boolean wrap) { - textEditorImpl.wrap(wrap); - setLineWrap(wrap); - } - - protected void initLineNumbersPanel() { - lineNumbersPanel = new TextLineNumbersPanel(textEditorImpl.getTextArea()); - } - - protected void initMenuBarItems() { + protected void initMenuBarItems() { // TODO code dup with TextEditor, fix it // Edit menu editMenu = new JMenu(Translator.get("text_viewer.edit")); MnemonicHelper menuItemMnemonicHelper = new MnemonicHelper(); @@ -269,10 +285,68 @@ protected void initMenuBarItems() { // View menu viewMenu = new JMenu(Translator.get("text_viewer.view")); - toggleLineWrapItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, Translator.get("text_viewer.line_wrap"), menuItemMnemonicHelper, null, this); - toggleLineWrapItem.setSelected(textEditorImpl.isWrap()); - toggleLineNumbersItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, Translator.get("text_viewer.line_numbers"), menuItemMnemonicHelper, null, this); - toggleLineNumbersItem.setSelected(ui.getRowHeader().getView() != null); + JMenuItem item; + + JMenu tabSyntaxMenu = new JMenu(Translator.get("text_viewer.syntax_style")); + + ButtonGroup syntaxGroup = new ButtonGroup(); + for (Map.Entry syntaxStyle : textEditorImpl.getSyntaxStyles().entrySet()) { + // TODO reflect the current style (that was automagically set on open) + JRadioButtonMenuItem radio = new JRadioButtonMenuItem(syntaxStyle.getValue(), false); + radio.setName(syntaxStyle.getKey()); + radio.addActionListener(e -> textEditorImpl.setSyntaxStyle(syntaxStyle.getKey())); + syntaxGroup.add(radio); + tabSyntaxMenu.add(radio); + } + textEditorImpl.setSyntaxStyleChangeListener(syntaxMime -> + Collections.list(syntaxGroup.getElements()).stream() + .filter(radio -> syntaxMime.equals(radio.getName())) + .findFirst().ifPresent(radio -> radio.setSelected(true)) + ); + viewMenu.add(tabSyntaxMenu); + viewMenu.addSeparator(); + + for (TextViewerPreferences pref : TextViewerPreferences.values()) { + if (pref.isTextEditorPref() && !pref.isEditorOnly()) { + item = MenuToolkit.addCheckBoxMenuItem(viewMenu, + Translator.get(pref.getI18nKey()), menuItemMnemonicHelper, + null, e -> pref.setValue(textEditorImpl, ((JMenuItem)e.getSource()).isSelected())); + item.setSelected(pref.getValue()); // the last known (or the most current) value + } + } + + viewMenu.addSeparator(); + + JMenuItem toggleLineNumbersItem = MenuToolkit.addCheckBoxMenuItem(viewMenu, + Translator.get(TextViewerPreferences.LINE_NUMBERS.getI18nKey()), + menuItemMnemonicHelper, null, this); + toggleLineNumbersItem.setSelected(textEditorImpl.getLineNumbersEnabled()); + toggleLineNumbersItem.addActionListener(e -> + showLineNumbers(toggleLineNumbersItem.isSelected())); + + viewMenu.addSeparator(); + int tabSize = textEditorImpl.getTabSize(); + JMenu tabSizeMenu = new JMenu(Translator.get("text_viewer.tab_size")); + + ButtonGroup tabGroup = new ButtonGroup(); + for (int i : new int[]{2, 4, 8}) { + JRadioButtonMenuItem radio = new JRadioButtonMenuItem(Integer.toString(i), tabSize == i); + radio.addActionListener( + e -> { + textEditorImpl.setTabSize(i); + MuSnapshot.getSnapshot().setVariable( + TEXT_FILE_PRESENTER_SECTION + ".tab_size", i); + } + ); + tabGroup.add(radio); + tabSizeMenu.add(radio); + } + viewMenu.add(tabSizeMenu); + } + + @Override + public void requestFocus() { + textEditorImpl.setFocusAndCursorOnFirstLine(); } /////////////////////////////// @@ -283,7 +357,6 @@ protected void initMenuBarItems() { public void open(AbstractFile file) throws IOException { currentFile = file; startEditing(file, null); - lineNumbersPanel.setPreferredWidth(); } @Override @@ -297,7 +370,7 @@ public void close() { @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); - + // TODO declare inline action handlers instead of those ifs if(source == copyItem) textEditorImpl.copy(); else if(source == selectAllItem) @@ -308,10 +381,6 @@ else if(source == findNextItem) textEditorImpl.findNext(); else if(source == findPreviousItem) textEditorImpl.findPrevious(); - else if(source == toggleLineWrapItem) - wrapLines(toggleLineWrapItem.isSelected()); - else if(source == toggleLineNumbersItem) - showLineNumbers(toggleLineNumbersItem.isSelected()); } ///////////////////////////////////// @@ -323,7 +392,7 @@ public void encodingChanged(Object source, String oldEncoding, String newEncodin try { // Reload the file using the new encoding // Note: loadDocument closes the InputStream - loadDocument(currentFile.getInputStream(), newEncoding, null); + loadDocument(currentFile, currentFile.getInputStream(), newEncoding, null); } catch (IOException ex) { InformationDialog.showErrorDialog(presenter.getWindowFrame(), Translator.get("read_error"), Translator.get("file_editor.cannot_read_file", currentFile.getName())); } diff --git a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewerPreferences.java b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewerPreferences.java new file mode 100644 index 0000000000..7754f883c4 --- /dev/null +++ b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewerPreferences.java @@ -0,0 +1,167 @@ +/* + * This file is part of muCommander, http://www.mucommander.com + * + * muCommander is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * muCommander is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.mucommander.viewer.text; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * TextEditor preferences gluing visual aspects (like i18n, source of menu generation), + * configuration to be stored and actual setter for TextArea UI. + * + * @author Piotr Skowronek + */ +enum TextViewerPreferences { + + // Whether to wrap long lines. + @Metadata(false) + LINE_WRAP("line_wrap", "text_viewer.line_wrap", t -> t::wrap), + // Whether to show line numbers. + @Metadata + LINE_NUMBERS("line_numbers", "text_viewer.line_numbers"), + // Whether to animate bracket matching + @Metadata + ANIMATE_BRACKET_MATCHING("animate_bracket_matching", "text_viewer.animate_bracket_matching", t -> t::animateBracketMatching), + // Whether to use anti-aliasing + @Metadata + ANTI_ALIASING("anti_aliasing", "text_viewer.anti_aliasing", t -> t::antiAliasing), + // Whether to use auto-indent + @Metadata(value = false, mode = EditorViewerMode.EDITOR) + AUTO_INDENT("auto_indent", "text_viewer.auto_indent", t -> t::autoIndent), + // Whether to match brackets + @Metadata + BRACKET_MATCHING("bracket_matching", "text_viewer.bracket_matching", t -> t::bracketMatching), + // Whether to clear lines with whitespaces + @Metadata(mode = EditorViewerMode.EDITOR) + CLEAR_WHITE_SPACE("clear_whitespace_lines", "text_viewer.clear_whitespace_lines", t -> t::clearWhitespaceLines), + // Whether to close curly braces + @Metadata(mode = EditorViewerMode.EDITOR) + CLOSE_CURLY_BRACES("close_curly_braces", "text_viewer.close_curly_braces", t -> t::closeCurlyBraces), + // Whether to markup tags (only honored for markup languages, such as HTML, XML and PHP) + @Metadata(mode = EditorViewerMode.EDITOR) + CLOSE_MARKUP_TAGS("close_markup_tags", "text_viewer.close_markup_tags", t -> t::closeMarkupTags), + // Whether to use code folding + @Metadata + CODE_FOLDING("code_folding", "text_viewer.code_folding", t -> t::codeFolding), + // Whether text drag-n-drop is enabled + @Metadata + DRAG_ENABLED("drag_n_drop", "text_viewer.drag_n_drop", t -> t::dragEnabled), + // Whether to show EOL markers + @Metadata(false) + EOL_MARKERS("eol_markers", "text_viewer.eol_markers", t -> t::eolMarkersVisible), + // Whether to slightly fade current line highlight + @Metadata + FADE_CURRENT_LINE_HL("fade_current_line", "text_viewer.fade_current_line", t -> t::fadeCurrentLineHighlight), + // Whether to highlight a current line + @Metadata + HIGHLIGHT_CURRENT_LINE("highlight_current_line", "text_viewer.highlight_current_line", t -> t::highlightCurrentLine), + // Whether to mark occurrences + @Metadata + MARK_OCCURRENCES("mark_occurrences", "text_viewer.mark_occurrences", t -> t::markOccurrences), + // Whether to paint tab lines + @Metadata + PAINT_TAB_LINES("tab_lines", "text_viewer.tab_lines", t -> t::paintTabLines), + // Whether to paint rounded edges of selection + @Metadata + ROUNDED_SELECTION("rounded_selection", "text_viewer.rounded_selection", t -> t::roundedSelectionEdges), + // Whether to show popup with matched end-bracket (when off-screen) + @Metadata + SHOW_MATCHED_BRACKET("show_matched_bracket_popup", "text_viewer.show_matched_bracket_popup", t -> t::showMatchedBracketPopup), + // Whether to emulated tabs with spaces + @Metadata(mode = EditorViewerMode.EDITOR) + TABS_EMULATED("tabs_emulated", "text_viewer.tabs_emulated", t -> t::tabsEmulated), + // Whether to show whitespace chars + @Metadata(false) + WHITESPACE_VISIBLE("whitespace_visible", "text_viewer.whitespace_visible", t -> t::whitespaceVisible), + + ; // end of prefs (syntax sugar aka developer vanity marker) + + enum EditorViewerMode { + BOTH, + EDITOR + }; + + String prefKey; + String i18nKey; + Function> textEditorSetter; + + boolean value = true; + EditorViewerMode mode = EditorViewerMode.BOTH; + + @Retention(RetentionPolicy.RUNTIME) + private @interface Metadata { + // Default value + boolean value() default true; + EditorViewerMode mode() default EditorViewerMode.BOTH; + } + + TextViewerPreferences(String prefKey, String i18nKey) { + this(prefKey, i18nKey, null); + } + + TextViewerPreferences(String prefKey, String i18nKey, Function> textEditorSetter) { + this.prefKey = prefKey; + this.i18nKey = i18nKey; + this.textEditorSetter = textEditorSetter; + + Metadata metadata; + try { + metadata = getDeclaringClass().getDeclaredField(this.name()).getDeclaredAnnotation(Metadata.class); + mode = metadata.mode(); + value = metadata.value(); + } catch (NoSuchFieldException | SecurityException e) { + // ignore, the properties are initialized with the annotation's default values + Logger LOGGER = LoggerFactory.getLogger(TextViewerPreferences.class); + LOGGER.trace("Failed to parse metadata of " + name(), e); + } + } + + public String getPrefKey() { + return prefKey; + } + + public String getI18nKey() { + return i18nKey; + } + + public boolean getValue() { + return value; + } + + public void setValue(boolean value) { + this.value = value; + } + + public void setValue(TextEditorImpl editorImpl, boolean value) { + if (textEditorSetter != null) { + textEditorSetter.apply(editorImpl).accept(value); + } + setValue(value); + } + + public boolean isTextEditorPref() { + return textEditorSetter != null; + } + + public boolean isEditorOnly() { return mode == EditorViewerMode.EDITOR; } +} diff --git a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewerSnapshot.java b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewerSnapshot.java index d1d2705fb3..3f2aed2fb6 100644 --- a/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewerSnapshot.java +++ b/mucommander-viewer-text/src/main/java/com/mucommander/viewer/text/TextViewerSnapshot.java @@ -16,50 +16,25 @@ */ package com.mucommander.viewer.text; -import com.mucommander.commons.conf.Configuration; import static com.mucommander.snapshot.MuSnapshot.FILE_PRESENTER_SECTION; + import com.mucommander.snapshot.MuSnapshotable; /** - * Snapshot preferences for text editor. + * Snapshot preferences for text editor & viewer. * - * @author Miroslav Hajda + * @author Miroslav Hajda, Piotr Skowronek, Arik Hadas */ -public final class TextViewerSnapshot implements MuSnapshotable { - +public final class TextViewerSnapshot extends MuSnapshotable { /** * Section describing information specific to text file presenter. */ - private static final String TEXT_FILE_PRESENTER_SECTION = FILE_PRESENTER_SECTION + "." + "text"; - /** - * Whether or not to wrap long lines. - */ - public static final String TEXT_FILE_PRESENTER_LINE_WRAP = TEXT_FILE_PRESENTER_SECTION + "." + "line_wrap"; - /** - * Default wrap value. - */ - public static final boolean DEFAULT_LINE_WRAP = false; - /** - * Whether or not to show line numbers. - */ - public static final String TEXT_FILE_PRESENTER_LINE_NUMBERS = TEXT_FILE_PRESENTER_SECTION + "." + "line_numbers"; - /** - * Default line numbers value. - */ - public static final boolean DEFAULT_LINE_NUMBERS = true; - /** - * Last known file presenter full screen mode. - */ - public static final String TEXT_FILE_PRESENTER_FULL_SCREEN = TEXT_FILE_PRESENTER_SECTION + "." + "full_screen"; - - @Override - public void read(Configuration configuration) { - } + public static final String TEXT_FILE_PRESENTER_SECTION = FILE_PRESENTER_SECTION + "." + "text"; - @Override - public void write(Configuration configuration) { - configuration.setVariable(TEXT_FILE_PRESENTER_FULL_SCREEN, TextViewer.isFullScreen()); - configuration.setVariable(TEXT_FILE_PRESENTER_LINE_WRAP, TextViewer.isLineWrap()); - configuration.setVariable(TEXT_FILE_PRESENTER_LINE_NUMBERS, TextViewer.isLineNumbers()); + TextViewerSnapshot() { + super(TextViewerPreferences::values, + pref -> Boolean.toString(pref.getValue()), + (pref, value) -> pref.setValue(Boolean.parseBoolean(value)), + pref -> pref.getPrefKey() != null ? TEXT_FILE_PRESENTER_SECTION + "." + pref.getPrefKey() : null); } -} +} \ No newline at end of file diff --git a/package/license.txt b/package/license.txt index f3ac4097a9..1ee30bea2a 100644 --- a/package/license.txt +++ b/package/license.txt @@ -19,9 +19,11 @@ Additionally, muCommander uses the following third party works: - the J7Zip library under the terms of the GNU Lesser General Public License - the jCIFS library under the terms of the GNU Lesser General Public License - the JetS3t library under the terms of the Apache License +- the JediTerm library under the terms of dual GNU Lesser General Public License and Apache License - the JmDNS library under the terms of the GNU Lesser General Public License - the JNA library under the terms of the GNU Lesser General Public License - the JUnRar library under the terms of the GNU Lesser General Public License +- the RSyntaxTextArea library under the terms of BSD 3-Clause "New" or "Revised" License - the Yanfs library under the terms of the Berkeley Software Distribution License - the JCommander library under the terms of the Apache License - the ICEpdf library under the terms of the Apache License diff --git a/package/readme.txt b/package/readme.txt index 1020a2879d..049f208cde 100644 --- a/package/readme.txt +++ b/package/readme.txt @@ -6,7 +6,7 @@ ------------------ -muCommander v1.1.0 +muCommander v1.2.0 ------------------ muCommander is a lightweight, cross-platform file manager with a dual-pane interface. @@ -28,35 +28,35 @@ If you're having problems launching muCommander, make sure the JAVA_HOME environ where your Java runtime is installed. -What's new since v1.0.1 ? +What's new since v1.1.0 ? ----------------------- New features: -- Support SMBv2. -- Support RAR 5+. -- New archive formats: RPM, cpio. -- New 'Toggle terminal' action (defaults to F12) that shows/hides a new terminal view. +- Syntax highlighting and other visual enhancements in text viewer/editor +- New operations in text editor: Undo, Redo, Replace spaces with tabs, Replace tabs with spaces +- Renaming files in Google Drive. +- Password-protected 7z and RAR archives can be browsed and unpacked. +- Custom color configurations for read-only files/folders. Improvements: -- Symbolic links are extracted properly from zip archives to the local file system. -- Local symbolic links are packed properly into zip and tar archives. -- Unpacking of 7z archives is now faster and more reliable using a newer native library. -- The filename cell is rendered differently when renaming a file to reflect that the filename is editable when no text is selected. -- Keyboard shortcuts on macOS better align with the default keyboard shortcuts in Safari. -- The 'About' dialog indicates when the portable version is used. -- Commands that are executed from the 'Run command' dialog are now typed within a terminal that recognizes shell aliases. -- When referencing an SMB server (smb:///), its accessible shares are listed. -- Bonjour services are initialized asynchronously in order to accelerate startup time. -- Quick search accepts diacritics that are typed using ALT+letter (like in Polish Programmer keyboard layout). +- 'Show in enclosing folder' action no longer opens a new tab but changes the current tab instead. +- The free space indicator within the status bar is updated quicker for 'ext4' and 'btrfs' UNIX file systems. +- The trash icon and free space indicator remain visible in the status bar when a file with a long name is selected. +- The 'commons-net' library that is used for connecting to FTP servers has been upgraded to version 3.8.0 +- The timeout for showing 'quick search' results is configurable via the 'Preferences' dialog. +- Set alternative keyboard shortcuts that don't require numeric keypad for Mark/Unmark actions. +- The configuration of the last file search is restored (from 'snapshot.xml') on startup. +- The 'Contents' field in the 'Properties' dialog includes hidden files only when the filter 'Show hidden files' is set. Localization: -- +- Korean translation updated Bug fixes: -- 'Move' action does not get stuck when an external file is dragged and dropped to the application. -- Symbolic links are extracted from archive files to the right location rather than to the destination base folder. -- Fix detection of the 'skopeo' binary that is used to connect to container registries. -- When extracting an item from an archive file to the archive file's parent folder, the archive file remains presented. +- The modification timestamp of folders is preserved when they are moved to a different file system. +- 'Open command prompt' action now works on Xfce. +- Filter out trashed files in Google Drive. +- It is now possible to upload files that are bigger than 2GB to NFS share. +- It is now possible to extract files that are bigger than 2GB from RAR 4 and lower archives. Known issues: - Some translations may not be up-to-date. @@ -107,6 +107,9 @@ muCommander uses the following great third party works : - the jCIFS library released under the GNU LGPL. jCIFS can be found at http://jcifs.samba.org . +- JediTerm library released under dual GNU LGPL and Apache License. + JediTerm can be found at https://github.com/JetBrains/jediterm . + - the JetS3t library released under the Apache License. JetS3t can be found at http://jets3t.s3.amazonaws.com/index.html . @@ -119,6 +122,9 @@ muCommander uses the following great third party works : - the JUnRar library released as Freeware. JUnRar can be found at http://sourceforge.net/projects/java-unrar . +- the RSyntaxTextArea library under the terms of BSD 3-Clause "New" or "Revised" License + RSyntaxTextArea can be found at https://bobbylight.github.io/RSyntaxTextArea . + - the Yanfs library released under the BSD license. Yanfs can be found at http://yanfs.dev.java.net . @@ -126,7 +132,7 @@ muCommander uses the following great third party works : JCommander can be found at http://jcommander.org . - the ICEpdf library released under the Apache License. - ICEpdf can be found at http://www.icesoft.com/icepdf . + ICEpdf can be found at https://github.com/pcorless/icepdf . - the Unix4j library released under the MIT License. Unix4j can be found at http://unix4j.org/. @@ -156,6 +162,7 @@ Contributors: - LeO - Xavier Martin - Alejandro Scandroli +- Piotr Skowronek - Alexander Yerenkow - Johann Schmitz - Thomas Uebel diff --git a/package/unix/mucommander.sh b/package/unix/mucommander.sh index e67efd6cd6..e8cceb43d4 100755 --- a/package/unix/mucommander.sh +++ b/package/unix/mucommander.sh @@ -35,4 +35,4 @@ fi cd `dirname "$BASE_FOLDER"` # Starts mucommander. -$JAVA -DGNOME_DESKTOP_SESSION_ID=$GNOME_DESKTOP_SESSION_ID -DKDE_FULL_SESSION=$KDE_FULL_SESSION -DKDE_SESSION_VERSION=$KDE_SESSION_VERSION --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-exports java.desktop/com.apple.eawt=ALL-UNNAMED --add-exports java.desktop/com.apple.laf=ALL-UNNAMED --add-exports java.desktop/com.apple.eio=ALL-UNNAMED -Djava.library.path=/usr/local/lib -cp mucommander-@MU_VERSION@.jar com.mucommander.main.muCommander $@ +$JAVA --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-exports java.desktop/com.apple.eawt=ALL-UNNAMED --add-exports java.desktop/com.apple.laf=ALL-UNNAMED --add-exports java.desktop/com.apple.eio=ALL-UNNAMED -Djava.library.path=/usr/local/lib -cp mucommander-@MU_VERSION@.jar com.mucommander.main.muCommander $@ diff --git a/settings.gradle b/settings.gradle index 086d5ec0ab..b222c260b4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -53,5 +53,6 @@ include 'mucommander-viewer-binary' include 'apache-bzip2' include 'jetbrains-jediterm' include 'sevenzipjbindings' +include 'sun-net-www' rootProject.name = 'mucommander' diff --git a/sevenzipjbindings/build.gradle b/sevenzipjbindings/build.gradle index 663893b5c4..2a297c53a2 100644 --- a/sevenzipjbindings/build.gradle +++ b/sevenzipjbindings/build.gradle @@ -26,6 +26,6 @@ jar { 'Implementation-Vendor': "Arik Hadas", 'Implementation-Version': revision.substring(0, 7), 'Build-Date': new Date().format('yyyyMMdd'), - 'Build-Url': "https://www.mucommander.com/version/nightly.xml") + 'Build-Url': "https://www.mucommander.com/version/version.xml") } diff --git a/sevenzipjbindings/src/main/java/com/mucommander/sevenzipjbindings/ExtractCallback.java b/sevenzipjbindings/src/main/java/com/mucommander/sevenzipjbindings/ExtractCallback.java deleted file mode 100644 index 1de3198697..0000000000 --- a/sevenzipjbindings/src/main/java/com/mucommander/sevenzipjbindings/ExtractCallback.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * This file is part of muCommander, http://www.mucommander.com - * - * muCommander is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * muCommander 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -package com.mucommander.sevenzipjbindings; - -import java.io.IOException; -import java.io.OutputStream; - -import net.sf.sevenzipjbinding.ExtractAskMode; -import net.sf.sevenzipjbinding.ExtractOperationResult; -import net.sf.sevenzipjbinding.IArchiveExtractCallback; -import net.sf.sevenzipjbinding.IInArchive; -import net.sf.sevenzipjbinding.ISequentialOutStream; -import net.sf.sevenzipjbinding.PropID; -import net.sf.sevenzipjbinding.SevenZipException; - -/** - * @author Oleg Trifonov - */ -public class ExtractCallback implements IArchiveExtractCallback { - private boolean skipExtraction; - private IInArchive inArchive; - private OutputStream os; - - public ExtractCallback(IInArchive inArchive, OutputStream os) { - this.inArchive = inArchive; - this.os = os; - } - - public ISequentialOutStream getStream(int index, ExtractAskMode extractAskMode) throws SevenZipException { - skipExtraction = (Boolean) inArchive.getProperty(index, PropID.IS_FOLDER); - if (skipExtraction || extractAskMode != ExtractAskMode.EXTRACT) { - return null; - } - return data -> { - try { - os.write(data); - } catch (IOException e) { - throw new SevenZipException(e); - } - return data.length; // Return amount of proceed data - }; - } - - public void prepareOperation(ExtractAskMode extractAskMode) { -//System.out.println("prepare " + index); - } - - public void setOperationResult(ExtractOperationResult extractOperationResult) { - if (skipExtraction) { - return; - } - if (extractOperationResult != ExtractOperationResult.OK) { - System.err.println("Extraction error = " + extractOperationResult); - } else { -//System.out.println(String.format("%9X | %10s | %s", hash, size, inArchive.getProperty(index, PropID.PATH))); - } - } - - public void setCompleted(long completeValue) { -//System.out.println("completed " + completeValue); - } - - public void setTotal(long total) { -//System.out.println("total " + index + " " + total); - } -} \ No newline at end of file diff --git a/sevenzipjbindings/src/main/java/com/mucommander/sevenzipjbindings/SevenZipJBindingROArchiveFile.java b/sevenzipjbindings/src/main/java/com/mucommander/sevenzipjbindings/SevenZipJBindingROArchiveFile.java index fb9c8f7771..8ef70894c4 100644 --- a/sevenzipjbindings/src/main/java/com/mucommander/sevenzipjbindings/SevenZipJBindingROArchiveFile.java +++ b/sevenzipjbindings/src/main/java/com/mucommander/sevenzipjbindings/SevenZipJBindingROArchiveFile.java @@ -37,6 +37,7 @@ import net.sf.sevenzipjbinding.ArchiveFormat; import net.sf.sevenzipjbinding.IInArchive; +import net.sf.sevenzipjbinding.ISequentialOutStream; import net.sf.sevenzipjbinding.PropID; import net.sf.sevenzipjbinding.SevenZip; import net.sf.sevenzipjbinding.SevenZipException; @@ -79,7 +80,7 @@ public SevenZipJBindingROArchiveFile check() throws IOException { private IInArchive openInArchive() throws IOException { if (inArchive == null) { SignatureCheckedRandomAccessFile in = new SignatureCheckedRandomAccessFile(file, formatSignature); - inArchive = SevenZip.openInArchive(sevenZipJBindingFormat, in); + inArchive = SevenZip.openInArchive(sevenZipJBindingFormat, in, password); } return inArchive; } @@ -87,53 +88,48 @@ private IInArchive openInArchive() throws IOException { @Override public ArchiveEntryIterator getEntryIterator() throws IOException { try { - final IInArchive sevenZipFile = openInArchive(); - int nbEntries = sevenZipFile.getNumberOfItems(); - List entries = new ArrayList<>(); - for (int i = 0; i < nbEntries; i++) { - entries.add(createArchiveEntry(i)); + try (IInArchive sevenZipFile = openInArchive()) { + int nbEntries = sevenZipFile.getNumberOfItems(); + List entries = new ArrayList<>(); + for (int i = 0; i < nbEntries; i++) { + entries.add(createArchiveEntry(i, sevenZipFile)); + } + return new WrapperArchiveEntryIterator(entries.iterator()); } - return new WrapperArchiveEntryIterator(entries.iterator()); } catch (SevenZipException e) { - LOGGER.warn("failed to list archive: %s", e.getMessage()); + LOGGER.warn("failed to list archive: " + e.getMessage()); LOGGER.debug("failed to list archive", e); throw new IOException(e); } finally { - try { - if (inArchive != null) { - inArchive.close(); - } - } catch (SevenZipException e) { - System.err.println("Error closing archive: " + e); - } inArchive = null; } } @Override public InputStream getEntryInputStream(ArchiveEntry entry, ArchiveEntryIterator entryIterator) { - final int[] in = new int[1]; - in[0] = (Integer)entry.getEntryObject(); final CircularByteBuffer cbb = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE); new Thread(() -> { synchronized (SevenZipJBindingROArchiveFile.this) { try { - final IInArchive sevenZipFile = openInArchive(); - sevenZipFile.extract(in, false, new ExtractCallback(inArchive, cbb.getOutputStream())); + try (IInArchive sevenZipFile = openInArchive()) { + ISequentialOutStream outStream = data -> { + try { + cbb.getOutputStream().write(data); + } catch (IOException e) { + throw new SevenZipException(e); + } + return data.length; // Return amount of proceed data + }; + sevenZipFile.extractSlow((Integer) entry.getEntryObject(), outStream, password); + } } catch (IOException e) { - e.printStackTrace(); + LOGGER.warn("failed to extract entry from archive: " + e.getMessage()); + LOGGER.debug("failed to extract entry from archive", e); } finally { - if (inArchive != null) { - try { - inArchive.close(); - } catch (SevenZipException e) { - e.printStackTrace(); - } - } try { cbb.getOutputStream().close(); } catch (IOException e) { - e.printStackTrace(); + LOGGER.info("Error in closing outputstream: " + e.getMessage()); } inArchive = null; } @@ -147,10 +143,10 @@ public InputStream getEntryInputStream(ArchiveEntry entry, ArchiveEntryIterator * Creates and return an {@link ArchiveEntry()} whose attributes are fetched from the given {@link com.mucommander.commons.file.impl.sevenzip.provider.SevenZip.Archive.SevenZipEntry} * * @param i the index of entry + * @param sevenZipFile the archive file * @return an ArchiveEntry whose attributes are fetched from the given SevenZipEntry */ - private ArchiveEntry createArchiveEntry(int i) throws IOException { - final IInArchive sevenZipFile = openInArchive(); + private ArchiveEntry createArchiveEntry(int i, IInArchive sevenZipFile) throws IOException { String path = sevenZipFile.getStringProperty(i, PropID.PATH); boolean isDirectory = (Boolean)sevenZipFile.getProperty(i, PropID.IS_FOLDER); Date time = (Date) sevenZipFile.getProperty(i, PropID.LAST_MODIFICATION_TIME); diff --git a/src/main/java/com/mucommander/main/muCommander.java b/src/main/java/com/mucommander/main/muCommander.java index fb149f912b..55cff484c2 100644 --- a/src/main/java/com/mucommander/main/muCommander.java +++ b/src/main/java/com/mucommander/main/muCommander.java @@ -287,7 +287,7 @@ public static void main(String[] args) throws Exception configProps.computeIfAbsent("mucommander.app.dir", key -> new File(codeParentFolder, "app").getAbsolutePath()); final String appDir = configProps.get("mucommander.app.dir"); - configProps.computeIfAbsent("felix.auto.start.2", key -> "file:" + new File(appDir, "mucommander-core-1.1.0.jar").getAbsolutePath()); + configProps.computeIfAbsent("felix.auto.start.2", key -> "file:" + new File(appDir, "mucommander-core-1.2.0.jar").getAbsolutePath()); Path cacheDir = Paths.get(System.getProperty("java.io.tmpdir"), "mucommander-felix-cache-"+System.getProperty("user.name")); configProps.put(Constants.FRAMEWORK_STORAGE, cacheDir.toFile().getAbsolutePath()); diff --git a/sun-net-www/build.gradle b/sun-net-www/build.gradle new file mode 100644 index 0000000000..dccb03b0fc --- /dev/null +++ b/sun-net-www/build.gradle @@ -0,0 +1 @@ +repositories.mavenCentral() diff --git a/sun-net-www/src/main/java/sun/net/www/MessageHeader.java b/sun-net-www/src/main/java/sun/net/www/MessageHeader.java new file mode 100644 index 0000000000..22b16407dd --- /dev/null +++ b/sun-net-www/src/main/java/sun/net/www/MessageHeader.java @@ -0,0 +1,563 @@ +/* + * Copyright (c) 1995, 2020, 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. + */ + +/*- + * news stream opener + */ + +package sun.net.www; + +import java.io.*; +import java.util.Collections; +import java.util.*; + +/** An RFC 844 or MIME message header. Includes methods + for parsing headers from incoming streams, fetching + values, setting values, and printing headers. + Key values of null are legal: they indicate lines in + the header that don't have a valid key, but do have + a value (this isn't legal according to the standard, + but lines like this are everywhere). */ +public +class MessageHeader { + private String keys[]; + private String values[]; + private int nkeys; + + public MessageHeader () { + grow(); + } + + public MessageHeader (InputStream is) throws java.io.IOException { + parseHeader(is); + } + + /** + * Returns list of header names in a comma separated list + */ + public synchronized String getHeaderNamesInList() { + StringJoiner joiner = new StringJoiner(","); + for (int i=0; i= 0;) + if (keys[i] == null) + return values[i]; + } else + for (int i = nkeys; --i >= 0;) { + if (k.equalsIgnoreCase(keys[i])) + return values[i]; + } + return null; + } + + // return the location of the key + public synchronized int getKey(String k) { + for (int i = nkeys; --i >= 0;) + if ((keys[i] == k) || + (k != null && k.equalsIgnoreCase(keys[i]))) + return i; + return -1; + } + + public synchronized String getKey(int n) { + if (n < 0 || n >= nkeys) return null; + return keys[n]; + } + + public synchronized String getValue(int n) { + if (n < 0 || n >= nkeys) return null; + return values[n]; + } + + /** Deprecated: Use multiValueIterator() instead. + * + * Find the next value that corresponds to this key. + * It finds the first value that follows v. To iterate + * over all the values of a key use: + *
      +     *          for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
      +     *              ...
      +     *          }
      +     *  
      + */ + public synchronized String findNextValue(String k, String v) { + boolean foundV = false; + if (k == null) { + for (int i = nkeys; --i >= 0;) + if (keys[i] == null) + if (foundV) + return values[i]; + else if (values[i] == v) + foundV = true; + } else + for (int i = nkeys; --i >= 0;) + if (k.equalsIgnoreCase(keys[i])) + if (foundV) + return values[i]; + else if (values[i] == v) + foundV = true; + return null; + } + + /** + * Removes bare Negotiate and Kerberos headers when an "NTLM ..." + * appears. All Performed on headers with key being k. + * @return true if there is a change + */ + public boolean filterNTLMResponses(String k) { + boolean found = false; + for (int i=0; i 5 + && values[i].substring(0, 5).equalsIgnoreCase("NTLM ")) { + found = true; + break; + } + } + if (found) { + int j = 0; + for (int i=0; i { + int index = 0; + int next = -1; + String key; + boolean haveNext = false; + Object lock; + + public HeaderIterator (String k, Object lock) { + key = k; + this.lock = lock; + } + public boolean hasNext () { + synchronized (lock) { + if (haveNext) { + return true; + } + while (index < nkeys) { + if (key.equalsIgnoreCase (keys[index])) { + haveNext = true; + next = index++; + return true; + } + index ++; + } + return false; + } + } + public String next() { + synchronized (lock) { + if (haveNext) { + haveNext = false; + return values [next]; + } + if (hasNext()) { + return next(); + } else { + throw new NoSuchElementException ("No more elements"); + } + } + } + public void remove () { + throw new UnsupportedOperationException ("remove not allowed"); + } + } + + /** + * return an Iterator that returns all values of a particular + * key in sequence + */ + public Iterator multiValueIterator (String k) { + return new HeaderIterator (k, this); + } + + public synchronized Map> getHeaders() { + return getHeaders(null); + } + + public synchronized Map> getHeaders(String[] excludeList) { + return filterAndAddHeaders(excludeList, null); + } + + public synchronized Map> filterAndAddHeaders( + String[] excludeList, Map> include) { + boolean skipIt = false; + Map> m = new HashMap<>(); + for (int i = nkeys; --i >= 0;) { + if (excludeList != null) { + // check if the key is in the excludeList. + // if so, don't include it in the Map. + for (int j = 0; j < excludeList.length; j++) { + if ((excludeList[j] != null) && + (excludeList[j].equalsIgnoreCase(keys[i]))) { + skipIt = true; + break; + } + } + } + if (!skipIt) { + List l = m.get(keys[i]); + if (l == null) { + l = new ArrayList<>(); + m.put(keys[i], l); + } + l.add(values[i]); + } else { + // reset the flag + skipIt = false; + } + } + + if (include != null) { + for (Map.Entry> entry: include.entrySet()) { + List l = m.get(entry.getKey()); + if (l == null) { + l = new ArrayList<>(); + m.put(entry.getKey(), l); + } + l.addAll(entry.getValue()); + } + } + + for (String key : m.keySet()) { + m.put(key, Collections.unmodifiableList(m.get(key))); + } + + return Collections.unmodifiableMap(m); + } + + /** Check if a line of message header looks like a request line. + * This method does not perform a full validation but simply + * returns false if the line does not end with 'HTTP/[1-9].[0-9]' + * @param line the line to check. + * @return true if the line might be a request line. + */ + private static boolean isRequestline(String line) { + String k = line.trim(); + int i = k.lastIndexOf(' '); + if (i <= 0) return false; + int len = k.length(); + if (len - i < 9) return false; + + char c1 = k.charAt(len-3); + char c2 = k.charAt(len-2); + char c3 = k.charAt(len-1); + if (c1 < '1' || c1 > '9') return false; + if (c2 != '.') return false; + if (c3 < '0' || c3 > '9') return false; + + return (k.substring(i+1, len-3).equalsIgnoreCase("HTTP/")); + } + + /** Prints the key-value pairs represented by this + header. Also prints the RFC required blank line + at the end. Omits pairs with a null key. Omits + colon if key-value pair is the requestline. */ + public void print(PrintStream p) { + // no synchronization: use cloned arrays instead. + String[] k; String[] v; int n; + synchronized (this) { n = nkeys; k = keys.clone(); v = values.clone(); } + print(n, k, v, p); + } + + + /** Prints the key-value pairs represented by this + header. Also prints the RFC required blank line + at the end. Omits pairs with a null key. Omits + colon if key-value pair is the requestline. */ + private static void print(int nkeys, String[] keys, String[] values, PrintStream p) { + for (int i = 0; i < nkeys; i++) + if (keys[i] != null) { + StringBuilder sb = new StringBuilder(keys[i]); + if (values[i] != null) { + sb.append(": " + values[i]); + } else if (i != 0 || !isRequestline(keys[i])) { + sb.append(":"); + } + p.print(sb.append("\r\n")); + } + p.print("\r\n"); + p.flush(); + } + + /** Adds a key value pair to the end of the + header. Duplicates are allowed */ + public synchronized void add(String k, String v) { + grow(); + keys[nkeys] = k; + values[nkeys] = v; + nkeys++; + } + + /** Prepends a key value pair to the beginning of the + header. Duplicates are allowed */ + public synchronized void prepend(String k, String v) { + grow(); + for (int i = nkeys; i > 0; i--) { + keys[i] = keys[i-1]; + values[i] = values[i-1]; + } + keys[0] = k; + values[0] = v; + nkeys++; + } + + /** Overwrite the previous key/val pair at location 'i' + * with the new k/v. If the index didn't exist before + * the key/val is simply tacked onto the end. + */ + + public synchronized void set(int i, String k, String v) { + grow(); + if (i < 0) { + return; + } else if (i >= nkeys) { + add(k, v); + } else { + keys[i] = k; + values[i] = v; + } + } + + + /** grow the key/value arrays as needed */ + + private void grow() { + if (keys == null || nkeys >= keys.length) { + String[] nk = new String[nkeys + 4]; + String[] nv = new String[nkeys + 4]; + if (keys != null) + System.arraycopy(keys, 0, nk, 0, nkeys); + if (values != null) + System.arraycopy(values, 0, nv, 0, nkeys); + keys = nk; + values = nv; + } + } + + /** + * Remove the key from the header. If there are multiple values under + * the same key, they are all removed. + * Nothing is done if the key doesn't exist. + * After a remove, the other pairs' order are not changed. + * @param k the key to remove + */ + public synchronized void remove(String k) { + if(k == null) { + for (int i = 0; i < nkeys; i++) { + while (keys[i] == null && i < nkeys) { + for(int j=i; j= 0;) + if (k.equalsIgnoreCase(keys[i])) { + values[i] = v; + return; + } + add(k, v); + } + + /** Set's the value of a key only if there is no + * key with that value already. + */ + + public synchronized void setIfNotSet(String k, String v) { + if (findValue(k) == null) { + add(k, v); + } + } + + /** Convert a message-id string to canonical form (strips off + leading and trailing {@literal <>s}) */ + public static String canonicalID(String id) { + if (id == null) + return ""; + int st = 0; + int len = id.length(); + boolean substr = false; + int c; + while (st < len && ((c = id.charAt(st)) == '<' || + c <= ' ')) { + st++; + substr = true; + } + while (st < len && ((c = id.charAt(len - 1)) == '>' || + c <= ' ')) { + len--; + substr = true; + } + return substr ? id.substring(st, len) : id; + } + + /** Parse a MIME header from an input stream. */ + public void parseHeader(InputStream is) throws java.io.IOException { + synchronized (this) { + nkeys = 0; + } + mergeHeader(is); + } + + /** Parse and merge a MIME header from an input stream. */ + @SuppressWarnings("fallthrough") + public void mergeHeader(InputStream is) throws java.io.IOException { + if (is == null) + return; + char s[] = new char[10]; + int firstc = is.read(); + while (firstc != '\n' && firstc != '\r' && firstc >= 0) { + int len = 0; + int keyend = -1; + int c; + boolean inKey = firstc > ' '; + s[len++] = (char) firstc; + parseloop:{ + while ((c = is.read()) >= 0) { + switch (c) { + case ':': + if (inKey && len > 0) + keyend = len; + inKey = false; + break; + case '\t': + c = ' '; + /*fall through*/ + case ' ': + inKey = false; + break; + case '\r': + case '\n': + firstc = is.read(); + if (c == '\r' && firstc == '\n') { + firstc = is.read(); + if (firstc == '\r') + firstc = is.read(); + } + if (firstc == '\n' || firstc == '\r' || firstc > ' ') + break parseloop; + /* continuation */ + c = ' '; + break; + } + if (len >= s.length) { + char ns[] = new char[s.length * 2]; + System.arraycopy(s, 0, ns, 0, len); + s = ns; + } + s[len++] = (char) c; + } + firstc = -1; + } + while (len > 0 && s[len - 1] <= ' ') + len--; + String k; + if (keyend <= 0) { + k = null; + keyend = 0; + } else { + k = String.copyValueOf(s, 0, keyend); + if (keyend < len && s[keyend] == ':') + keyend++; + while (keyend < len && s[keyend] <= ' ') + keyend++; + } + String v; + if (keyend >= len) + v = new String(); + else + v = String.copyValueOf(s, keyend, len - keyend); + add(k, v); + } + } + + public synchronized String toString() { + String result = super.toString() + nkeys + " pairs: "; + for (int i = 0; i < keys.length && i < nkeys; i++) { + result += "{"+keys[i]+": "+values[i]+"}"; + } + return result; + } +} diff --git a/sun-net-www/src/main/java/sun/net/www/MimeEntry.java b/sun-net-www/src/main/java/sun/net/www/MimeEntry.java new file mode 100644 index 0000000000..48b847cf55 --- /dev/null +++ b/sun-net-www/src/main/java/sun/net/www/MimeEntry.java @@ -0,0 +1,268 @@ +/* + * Copyright (c) 1994, 2021, 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.net.www; +import java.net.URL; +import java.io.*; +import java.util.StringJoiner; +import java.util.StringTokenizer; + +public class MimeEntry implements Cloneable { + private String typeName; // of the form: "type/subtype" + private String tempFileNameTemplate; + + private int action; + private String command; + private String description; + private String imageFileName; + private String fileExtensions[]; + + boolean starred; + + // Actions + public static final int UNKNOWN = 0; + public static final int LOAD_INTO_BROWSER = 1; + public static final int SAVE_TO_FILE = 2; + public static final int LAUNCH_APPLICATION = 3; + + static final String[] actionKeywords = { + "unknown", + "browser", + "save", + "application", + }; + + /** + * Construct an empty entry of the given type and subtype. + */ + public MimeEntry(String type) { + // Default action is UNKNOWN so clients can decide what the default + // should be, typically save to file or ask user. + this(type, UNKNOWN, null, null, null); + } + + // + // The next two constructors are used only by the deprecated + // PlatformMimeTable classes or, in last case, is called by the public + // constructor. They are kept here anticipating putting support for + // mailcap formatted config files back in (so BOTH the properties format + // and the mailcap formats are supported). + // + MimeEntry(String type, String imageFileName, String extensionString) { + typeName = type.toLowerCase(); + action = UNKNOWN; + command = null; + this.imageFileName = imageFileName; + setExtensions(extensionString); + starred = isStarred(typeName); + } + + // For use with MimeTable::parseMailCap + MimeEntry(String typeName, int action, String command, + String tempFileNameTemplate) { + this.typeName = typeName.toLowerCase(); + this.action = action; + this.command = command; + this.imageFileName = null; + this.fileExtensions = null; + + this.tempFileNameTemplate = tempFileNameTemplate; + } + + // This is the one called by the public constructor. + MimeEntry(String typeName, int action, String command, + String imageFileName, String fileExtensions[]) { + + this.typeName = typeName.toLowerCase(); + this.action = action; + this.command = command; + this.imageFileName = imageFileName; + this.fileExtensions = fileExtensions; + + starred = isStarred(typeName); + + } + + public synchronized String getType() { + return typeName; + } + + public synchronized void setType(String type) { + typeName = type.toLowerCase(); + } + + public synchronized int getAction() { + return action; + } + + public synchronized void setAction(int action, String command) { + this.action = action; + this.command = command; + } + + public synchronized void setAction(int action) { + this.action = action; + } + + public synchronized String getLaunchString() { + return command; + } + + public synchronized void setCommand(String command) { + this.command = command; + } + + public synchronized String getDescription() { + return (description != null ? description : typeName); + } + + public synchronized void setDescription(String description) { + this.description = description; + } + + // ??? what to return for the image -- the file name or should this return + // something more advanced like an image source or something? + // returning the name has the least policy associated with it. + // pro tempore, we'll use the name + public String getImageFileName() { + return imageFileName; + } + + public synchronized void setImageFileName(String filename) { + File file = new File(filename); + if (file.getParent() == null) { + imageFileName = System.getProperty( + "java.net.ftp.imagepath."+filename); + } + else { + imageFileName = filename; + } + + if (filename.lastIndexOf('.') < 0) { + imageFileName = imageFileName + ".gif"; + } + } + + public String getTempFileTemplate() { + return tempFileNameTemplate; + } + + public synchronized String[] getExtensions() { + return fileExtensions; + } + + public synchronized String getExtensionsAsList() { + String extensionsAsString = ""; + if (fileExtensions != null) { + for (int i = 0; i < fileExtensions.length; i++) { + extensionsAsString += fileExtensions[i]; + if (i < (fileExtensions.length - 1)) { + extensionsAsString += ","; + } + } + } + + return extensionsAsString; + } + + public synchronized void setExtensions(String extensionString) { + StringTokenizer extTokens = new StringTokenizer(extensionString, ","); + int numExts = extTokens.countTokens(); + String extensionStrings[] = new String[numExts]; + + for (int i = 0; i < numExts; i++) { + String ext = (String)extTokens.nextElement(); + extensionStrings[i] = ext.trim(); + } + + fileExtensions = extensionStrings; + } + + private boolean isStarred(String typeName) { + return typeName != null && typeName.endsWith("/*"); + } + + public boolean matches(String type) { + if (starred) { + // REMIND: is this the right thing or not? + return type.startsWith(typeName); + } else { + return type.equals(typeName); + } + } + + public Object clone() { + // return a shallow copy of this. + MimeEntry theClone = new MimeEntry(typeName); + theClone.action = action; + theClone.command = command; + theClone.description = description; + theClone.imageFileName = imageFileName; + theClone.tempFileNameTemplate = tempFileNameTemplate; + theClone.fileExtensions = fileExtensions; + + return theClone; + } + + public synchronized String toProperty() { + StringJoiner sj = new StringJoiner("; "); + + int action = getAction(); + if (action != MimeEntry.UNKNOWN) { + sj.add("action=" + actionKeywords[action]); + } + + String command = getLaunchString(); + if (command != null && command.length() > 0) { + sj.add("application=" + command); + } + + String image = getImageFileName(); + if (image != null) { + sj.add("icon=" + image); + } + + String extensions = getExtensionsAsList(); + if (!extensions.isEmpty()) { + sj.add("file_extensions=" + extensions); + } + + String description = getDescription(); + if (description != null && !description.equals(getType())) { + sj.add("description=" + description); + } + + return sj.toString(); + } + + public String toString() { + return "MimeEntry[contentType=" + typeName + + ", image=" + imageFileName + + ", action=" + action + + ", command=" + command + + ", extensions=" + getExtensionsAsList() + + "]"; + } +} diff --git a/sun-net-www/src/main/java/sun/net/www/MimeTable.java b/sun-net-www/src/main/java/sun/net/www/MimeTable.java new file mode 100644 index 0000000000..ee7715678b --- /dev/null +++ b/sun-net-www/src/main/java/sun/net/www/MimeTable.java @@ -0,0 +1,440 @@ +/* + * Copyright (c) 1994, 2021, 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.net.www; + +import java.io.*; +import java.net.FileNameMap; +import java.util.Hashtable; +import java.util.Enumeration; +import java.util.Properties; +import java.util.StringTokenizer; + +@SuppressWarnings("removal") +public class MimeTable implements FileNameMap { + /** Keyed by content type, returns MimeEntries */ + private Hashtable entries + = new Hashtable(); + + /** Keyed by file extension (with the .), returns MimeEntries */ + private Hashtable extensionMap + = new Hashtable(); + + // Will be reset if in the platform-specific data file + private static String tempFileTemplate; + + static { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + tempFileTemplate = + System.getProperty("content.types.temp.file.template", + "/tmp/%s"); + + mailcapLocations = new String[] { + System.getProperty("user.mailcap"), +// StaticProperty.userHome() + "/.mailcap", + "/etc/mailcap", + "/usr/etc/mailcap", + "/usr/local/etc/mailcap", + }; + return null; + } + }); + } + + + private static final String filePreamble = "sun.net.www MIME content-types table"; + private static final String fileMagic = "#" + filePreamble; + + MimeTable() { + load(); + } + + private static class DefaultInstanceHolder { + static final MimeTable defaultInstance = getDefaultInstance(); + + static MimeTable getDefaultInstance() { + return java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public MimeTable run() { + MimeTable instance = new MimeTable(); + URLConnection.setFileNameMap(instance); + return instance; + } + }); + } + } + + /** + * Get the single instance of this class. First use will load the + * table from a data file. + */ + public static MimeTable getDefaultTable() { + return DefaultInstanceHolder.defaultInstance; + } + + /** + * + */ + public static FileNameMap loadTable() { + MimeTable mt = getDefaultTable(); + return (FileNameMap)mt; + } + + public synchronized int getSize() { + return entries.size(); + } + + public synchronized String getContentTypeFor(String fileName) { + MimeEntry entry = findByFileName(fileName); + if (entry != null) { + return entry.getType(); + } else { + return null; + } + } + + public synchronized void add(MimeEntry m) { + entries.put(m.getType(), m); + + String exts[] = m.getExtensions(); + if (exts == null) { + return; + } + + for (int i = 0; i < exts.length; i++) { + extensionMap.put(exts[i], m); + } + } + + public synchronized MimeEntry remove(String type) { + MimeEntry entry = entries.get(type); + return remove(entry); + } + + public synchronized MimeEntry remove(MimeEntry entry) { + String[] extensionKeys = entry.getExtensions(); + if (extensionKeys != null) { + for (int i = 0; i < extensionKeys.length; i++) { + extensionMap.remove(extensionKeys[i]); + } + } + + return entries.remove(entry.getType()); + } + + public synchronized MimeEntry find(String type) { + MimeEntry entry = entries.get(type); + if (entry == null) { + // try a wildcard lookup + Enumeration e = entries.elements(); + while (e.hasMoreElements()) { + MimeEntry wild = e.nextElement(); + if (wild.matches(type)) { + return wild; + } + } + } + + return entry; + } + + /** + * Locate a MimeEntry by the file extension that has been associated + * with it. Parses general file names, and URLs. + */ + public MimeEntry findByFileName(String fname) { + String ext = ""; + + int i = fname.lastIndexOf('#'); + + if (i > 0) { + fname = fname.substring(0, i - 1); + } + + i = fname.lastIndexOf('.'); + // REMIND: OS specific delimters appear here + i = Math.max(i, fname.lastIndexOf('/')); + i = Math.max(i, fname.lastIndexOf('?')); + + if (i != -1 && fname.charAt(i) == '.') { + ext = fname.substring(i).toLowerCase(); + } + + return findByExt(ext); + } + + /** + * Locate a MimeEntry by the file extension that has been associated + * with it. + */ + public synchronized MimeEntry findByExt(String fileExtension) { + return extensionMap.get(fileExtension); + } + + public synchronized MimeEntry findByDescription(String description) { + Enumeration e = elements(); + while (e.hasMoreElements()) { + MimeEntry entry = e.nextElement(); + if (description.equals(entry.getDescription())) { + return entry; + } + } + + // We failed, now try treating description as type + return find(description); + } + + String getTempFileTemplate() { + return tempFileTemplate; + } + + public synchronized Enumeration elements() { + return entries.elements(); + } + + // For backward compatibility -- mailcap format files + // This is not currently used, but may in the future when we add ability + // to read BOTH the properties format and the mailcap format. + protected static String[] mailcapLocations; + + public synchronized void load() { + Properties entries = new Properties(); + File file = null; + InputStream in; + + // First try to load the user-specific table, if it exists + String userTablePath = System.getProperty("content.types.user.table"); + if (userTablePath != null && (file = new File(userTablePath)).exists()) { + try { + in = new FileInputStream(file); + } catch (FileNotFoundException e) { + System.err.println("Warning: " + file.getPath() + + " mime table not found."); + return; + } + } else { + in = MimeTable.class.getResourceAsStream("content-types.properties"); + if (in == null) + throw new InternalError("default mime table not found"); + } + + try (BufferedInputStream bin = new BufferedInputStream(in)) { + entries.load(bin); + } catch (IOException e) { + System.err.println("Warning: " + e.getMessage()); + } + parse(entries); + } + + void parse(Properties entries) { + // first, strip out the platform-specific temp file template + String tempFileTemplate = (String)entries.get("temp.file.template"); + if (tempFileTemplate != null) { + entries.remove("temp.file.template"); + MimeTable.tempFileTemplate = tempFileTemplate; + } + + // now, parse the mime-type spec's + Enumeration types = entries.propertyNames(); + while (types.hasMoreElements()) { + String type = (String)types.nextElement(); + String attrs = entries.getProperty(type); + parse(type, attrs); + } + } + + // + // Table format: + // + // ::= | + // + // ::= | + // + // ::= '=' + // + // ::= '/' + // + // ::= [ ';' ]* + // | [ ]+ + // + // ::= '=' + // + // ::= 'description' | 'action' | 'application' + // | 'file_extensions' | 'icon' + // + // ::= * + // + // Embedded ';' in an are quoted with leading '\' . + // + // Interpretation of depends on the it is + // associated with. + // + + void parse(String type, String attrs) { + MimeEntry newEntry = new MimeEntry(type); + + // REMIND handle embedded ';' and '|' and literal '"' + StringTokenizer tokenizer = new StringTokenizer(attrs, ";"); + while (tokenizer.hasMoreTokens()) { + String pair = tokenizer.nextToken(); + parse(pair, newEntry); + } + + add(newEntry); + } + + void parse(String pair, MimeEntry entry) { + // REMIND add exception handling... + String name = null; + String value = null; + + boolean gotName = false; + StringTokenizer tokenizer = new StringTokenizer(pair, "="); + while (tokenizer.hasMoreTokens()) { + if (gotName) { + value = tokenizer.nextToken().trim(); + } + else { + name = tokenizer.nextToken().trim(); + gotName = true; + } + } + + fill(entry, name, value); + } + + void fill(MimeEntry entry, String name, String value) { + if ("description".equalsIgnoreCase(name)) { + entry.setDescription(value); + } + else if ("action".equalsIgnoreCase(name)) { + entry.setAction(getActionCode(value)); + } + else if ("application".equalsIgnoreCase(name)) { + entry.setCommand(value); + } + else if ("icon".equalsIgnoreCase(name)) { + entry.setImageFileName(value); + } + else if ("file_extensions".equalsIgnoreCase(name)) { + entry.setExtensions(value); + } + + // else illegal name exception + } + + String[] getExtensions(String list) { + StringTokenizer tokenizer = new StringTokenizer(list, ","); + int n = tokenizer.countTokens(); + String[] extensions = new String[n]; + for (int i = 0; i < n; i++) { + extensions[i] = tokenizer.nextToken(); + } + + return extensions; + } + + int getActionCode(String action) { + for (int i = 0; i < MimeEntry.actionKeywords.length; i++) { + if (action.equalsIgnoreCase(MimeEntry.actionKeywords[i])) { + return i; + } + } + + return MimeEntry.UNKNOWN; + } + + public Properties getAsProperties() { + Properties properties = new Properties(); + Enumeration e = elements(); + while (e.hasMoreElements()) { + MimeEntry entry = e.nextElement(); + properties.put(entry.getType(), entry.toProperty()); + } + + return properties; + } + + protected boolean saveAsProperties(File file) { + FileOutputStream os = null; + try { + os = new FileOutputStream(file); + Properties properties = getAsProperties(); + properties.put("temp.file.template", tempFileTemplate); + String tag; + // Perform the property security check for user.name + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPropertyAccess("user.name"); + } + String user = "";//StaticProperty.userName(); + if (user != null) { + tag = "; customized for " + user; + properties.store(os, filePreamble + tag); + } + else { + properties.store(os, filePreamble); + } + } + catch (IOException e) { + e.printStackTrace(); + return false; + } + finally { + if (os != null) { + try { os.close(); } catch (IOException e) {} + } + } + + return true; + } + /* + * Debugging utilities + * + public void list(PrintStream out) { + Enumeration keys = entries.keys(); + while (keys.hasMoreElements()) { + String key = (String)keys.nextElement(); + MimeEntry entry = (MimeEntry)entries.get(key); + out.println(key + ": " + entry); + } + } + + public static void main(String[] args) { + MimeTable testTable = MimeTable.getDefaultTable(); + + Enumeration e = testTable.elements(); + while (e.hasMoreElements()) { + MimeEntry entry = (MimeEntry)e.nextElement(); + System.out.println(entry); + } + + testTable.save(File.separator + "tmp" + + File.separator + "mime_table.save"); + } + */ +} diff --git a/sun-net-www/src/main/java/sun/net/www/URLConnection.java b/sun-net-www/src/main/java/sun/net/www/URLConnection.java new file mode 100644 index 0000000000..b3af24c594 --- /dev/null +++ b/sun-net-www/src/main/java/sun/net/www/URLConnection.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 1995, 2020, 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.net.www; + +import java.io.IOException; +import java.net.URL; +import java.util.*; + +/** + * A class to represent an active connection to an object + * represented by a URL. + * @author James Gosling + */ + +public abstract class URLConnection extends java.net.URLConnection { + + /** The URL that it is connected to */ + + private String contentType; + private int contentLength = -1; + + protected MessageHeader properties; + + /** + * Create a URLConnection object. These should not be created directly: + * instead they should be created by protocol handlers in response to + * URL.openConnection. + * @param u The URL that this connects to. + */ + public URLConnection (URL u) { + super(u); + properties = new MessageHeader(); + } + + /** + * Call this routine to get the property list for this object. + * Properties (like content-type) that have explicit getXX() methods + * associated with them should be accessed using those methods. + */ + public MessageHeader getProperties() { + return properties; + } + + /** Call this routine to set the property list for this object. */ + public void setProperties(MessageHeader properties) { + this.properties = properties; + } + + public void setRequestProperty(String key, String value) { + if(connected) + throw new IllegalStateException("Already connected"); + if (key == null) + throw new NullPointerException ("key cannot be null"); + properties.set(key, value); + } + + /** + * The following three methods addRequestProperty, getRequestProperty, + * and getRequestProperties were copied from the superclass implementation + * before it was changed by CR:6230836, to maintain backward compatibility. + */ + public void addRequestProperty(String key, String value) { + if (connected) + throw new IllegalStateException("Already connected"); + if (key == null) + throw new NullPointerException ("key is null"); + } + + public String getRequestProperty(String key) { + if (connected) + throw new IllegalStateException("Already connected"); + return null; + } + + public Map> getRequestProperties() { + if (connected) + throw new IllegalStateException("Already connected"); + return Collections.emptyMap(); + } + + public String getHeaderField(String name) { + try { + getInputStream(); + } catch (Exception e) { + return null; + } + return properties == null ? null : properties.findValue(name); + } + + + Map> headerFields; + + @Override + public Map> getHeaderFields() { + if (headerFields == null) { + try { + getInputStream(); + if (properties == null) { + headerFields = super.getHeaderFields(); + } else { + headerFields = properties.getHeaders(); + } + } catch (IOException e) { + return super.getHeaderFields(); + } + } + return headerFields; + } + + /** + * Return the key for the nth header field. Returns null if + * there are fewer than n fields. This can be used to iterate + * through all the headers in the message. + */ + public String getHeaderFieldKey(int n) { + try { + getInputStream(); + } catch (Exception e) { + return null; + } + MessageHeader props = properties; + return props == null ? null : props.getKey(n); + } + + /** + * Return the value for the nth header field. Returns null if + * there are fewer than n fields. This can be used in conjunction + * with getHeaderFieldKey to iterate through all the headers in the message. + */ + public String getHeaderField(int n) { + try { + getInputStream(); + } catch (Exception e) { + return null; + } + MessageHeader props = properties; + return props == null ? null : props.getValue(n); + } + + /** + * Call this routine to get the content-type associated with this + * object. + */ + public String getContentType() { + if (contentType == null) + contentType = getHeaderField("content-type"); + if (contentType == null) { + String ct = null; + try { + ct = guessContentTypeFromStream(getInputStream()); + } catch(java.io.IOException e) { + } + String ce = properties.findValue("content-encoding"); + if (ct == null) { + ct = properties.findValue("content-type"); + + if (ct == null) + if (url.getFile().endsWith("/")) + ct = "text/html"; + else + ct = guessContentTypeFromName(url.getFile()); + } + + /* + * If the Mime header had a Content-encoding field and its value + * was not one of the values that essentially indicate no + * encoding, we force the content type to be unknown. This will + * cause a save dialog to be presented to the user. It is not + * ideal but is better than what we were previously doing, namely + * bringing up an image tool for compressed tar files. + */ + + if (ct == null || ce != null && + !(ce.equalsIgnoreCase("7bit") + || ce.equalsIgnoreCase("8bit") + || ce.equalsIgnoreCase("binary"))) + ct = "content/unknown"; + setContentType(ct); + } + return contentType; + } + + /** + * Set the content type of this URL to a specific value. + * @param type The content type to use. One of the + * content_* static variables in this + * class should be used. + * e.g. setType(URL.content_html); + */ + public void setContentType(String type) { + contentType = type; + properties.set("content-type", type); + } + + /** + * Call this routine to get the content-length associated with this + * object. + */ + public int getContentLength() { + try { + getInputStream(); + } catch (Exception e) { + return -1; + } + int l = contentLength; + if (l < 0) { + try { + l = Integer.parseInt(properties.findValue("content-length")); + setContentLength(l); + } catch(Exception e) { + } + } + return l; + } + + /** + * Call this routine to set the content-length associated with this + * object. + */ + protected void setContentLength(int length) { + contentLength = length; + properties.set("content-length", String.valueOf(length)); + } + + /** + * Returns true if the data associated with this URL can be cached. + */ + public boolean canCache() { + return url.getFile().indexOf('?') < 0 /* && url.postData == null + REMIND */ ; + } + + /** + * Call this to close the connection and flush any remaining data. + * Overriders must remember to call super.close() + */ + public void close() { + url = null; + } + + private static HashMap proxiedHosts = new HashMap<>(); + + public static synchronized void setProxiedHost(String host) { + proxiedHosts.put(host.toLowerCase(), null); + } + + public static synchronized boolean isProxiedHost(String host) { + return proxiedHosts.containsKey(host.toLowerCase()); + } +}