# AccessPermission.java

    /*
     * Licensed to the Apache Software Foundation (ASF) under one or more
     * contributor license agreements.  See the NOTICE file distributed with
     * this work for additional information regarding copyright ownership.
     * The ASF licenses this file to You under the Apache License, Version 2.0
     * (the "License"); you may not use this file except in compliance with
     * the License.  You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */

    package org.apache.pdfbox.pdmodel.encryption;

    /**
     * This class represents the access permissions to a document.
     * These permissions are specified in the PDF format specifications, they include:
     * <ul>
     * <li>print the document</li>
     * <li>modify the content of the document</li>
     * <li>copy or extract content of the document</li>
     * <li>add or modify annotations</li>
     * <li>fill in interactive form fields</li>
     * <li>extract text and graphics for accessibility to visually impaired people</li>
     * <li>assemble the document</li>
     * <li>print in degraded quality</li>
     * </ul>
     *
     * This class can be used to protect a document by assigning access permissions to recipients.
     * In this case, it must be used with a specific ProtectionPolicy.
     *
     *
     * When a document is decrypted, it has a currentAccessPermission property which is the access permissions
     * granted to the user who decrypted the document.
     *
     * @see ProtectionPolicy
     * @see org.apache.pdfbox.pdmodel.PDDocument#getCurrentAccessPermission()
     *
     * @author Ben Litchfield
     * @author Benoit Guillon
     *
     */

    public class AccessPermission
    {

        private static final int DEFAULT_PERMISSIONS = ~3; //bits 0 & 1 need to be zero
        private static final int PRINT_BIT = 3;
        private static final int MODIFICATION_BIT = 4;
        private static final int EXTRACT_BIT = 5;
        private static final int MODIFY_ANNOTATIONS_BIT = 6;
        private static final int FILL_IN_FORM_BIT = 9;
        private static final int EXTRACT_FOR_ACCESSIBILITY_BIT = 10;
        private static final int ASSEMBLE_DOCUMENT_BIT = 11;
        private static final int FAITHFUL_PRINT_BIT = 12;

        private int bytes;

        private boolean readOnly = false;

        /**
         * Create a new access permission object.
         * By default, all permissions are granted.
         */
        public AccessPermission()
        {
            bytes = DEFAULT_PERMISSIONS;
        }

        /**
         * Create a new access permission object from a byte array.
         * Bytes are ordered most significant byte first.
         *
         * @param b the bytes as defined in PDF specs
         */

        public AccessPermission(byte[] b)
        {
            bytes = 0;
            bytes |= b[0] & 0xFF;
            bytes <<= 8;
            bytes |= b[1] & 0xFF;
            bytes <<= 8;
            bytes |= b[2] & 0xFF;
            bytes <<= 8;
            bytes |= b[3] & 0xFF;
        }

        /**
         * Creates a new access permission object from a single integer.
         *
         * @param permissions The permission bits.
         */
        public AccessPermission( int permissions )
        {
            bytes = permissions;
        }

        private boolean isPermissionBitOn( int bit )
        {
            return (bytes & (1 << (bit-1))) != 0;
        }

        private boolean setPermissionBit( int bit, boolean value )
        {
            int permissions = bytes;
            if( value )
            {
                permissions = permissions | (1 << (bit-1));
            }
            else
            {
                permissions = permissions & (~(1 << (bit - 1)));
            }
            bytes = permissions;

            return (bytes & (1 << (bit-1))) != 0;
        }

        /**
         * This will tell if the access permission corresponds to owner
         * access permission (no restriction).
         *
         * @return true if the access permission does not restrict the use of the document
         */
        public boolean isOwnerPermission()
        {
            return (this.canAssembleDocument()
                    && this.canExtractContent()
                    && this.canExtractForAccessibility()
                    && this.canFillInForm()
                    && this.canModify()
                    && this.canModifyAnnotations()
                    && this.canPrint()
                    && this.canPrintFaithful()
                    );
        }

        /**
         * returns an access permission object for a document owner.
         *
         * @return A standard owner access permission set.
         */

        public static AccessPermission getOwnerAccessPermission()
        {
            AccessPermission ret = new AccessPermission();
            ret.setCanAssembleDocument(true);
            ret.setCanExtractContent(true);
            ret.setCanExtractForAccessibility(true);
            ret.setCanFillInForm(true);
            ret.setCanModify(true);
            ret.setCanModifyAnnotations(true);
            ret.setCanPrint(true);
            ret.setCanPrintFaithful(true);
            return ret;
        }

        /**
         * This returns an integer representing the access permissions.
         * This integer can be used for public key encryption. This format
         * is not documented in the PDF specifications but is necessary for compatibility
         * with Adobe Acrobat and Adobe Reader.
         *
         * @return the integer representing access permissions
         */

        public int getPermissionBytesForPublicKey()
        {
            setPermissionBit(1, true);
            setPermissionBit(7, false);
            setPermissionBit(8, false);
            for(int i=13; i<=32; i++)
            {
                setPermissionBit(i, false);
            }
            return bytes;
        }

        /**
         * The returns an integer representing the access permissions.
         * This integer can be used for standard PDF encryption as specified
         * in the PDF specifications.
         *
         * @return the integer representing the access permissions
         */
        public int getPermissionBytes()
        {
            return bytes;
        }

        /**
         * This will tell if the user can print.
         *
         * @return true If supplied with the user password they are allowed to print.
         */
        public boolean canPrint()
        {
            return isPermissionBitOn( PRINT_BIT );
        }

        /**
         * Set if the user can print.
         * <p>
         * This method will have no effect if the object is in read only mode.
         *
         * @param allowPrinting A boolean determining if the user can print.
         */
        public void setCanPrint( boolean allowPrinting )
        {
            if(!readOnly)
            {
                setPermissionBit( PRINT_BIT, allowPrinting );
            }
        }

        /**
         * This will tell if the user can modify contents of the document.
         *
         * @return true If supplied with the user password they are allowed to modify the document
         */
        public boolean canModify()
        {
            return isPermissionBitOn( MODIFICATION_BIT );
        }

        /**
         * Set if the user can modify the document.
         * <p>
         * This method will have no effect if the object is in read only mode.
         *
         * @param allowModifications A boolean determining if the user can modify the document.
         */
        public void setCanModify( boolean allowModifications )
        {
            if(!readOnly)
            {
                setPermissionBit( MODIFICATION_BIT, allowModifications );
            }
        }

        /**
         * This will tell if the user can extract text and images from the PDF document.
         *
         * @return true If supplied with the user password they are allowed to extract content
         *              from the PDF document
         */
        public boolean canExtractContent()
        {
            return isPermissionBitOn( EXTRACT_BIT );
        }

        /**
         * Set if the user can extract content from the document.
         * <p>
         * This method will have no effect if the object is in read only mode.
         *
         * @param allowExtraction A boolean determining if the user can extract content
         *                        from the document.
         */
        public void setCanExtractContent( boolean allowExtraction )
        {
            if(!readOnly)
            {
                setPermissionBit( EXTRACT_BIT, allowExtraction );
            }
        }

        /**
         * This will tell if the user can add or modify text annotations and fill in interactive forms
         * fields and, if {@link #canModify() canModify()} returns true, create or modify interactive
         * form fields (including signature fields). Note that if
         * {@link #canFillInForm() canFillInForm()} returns true, it is still possible to fill in
         * interactive forms (including signature fields) even if this method here returns false.
         *
         * @return true If supplied with the user password they are allowed to modify annotations.
         */
        public boolean canModifyAnnotations()
        {
            return isPermissionBitOn( MODIFY_ANNOTATIONS_BIT );
        }

        /**
         * Set if the user can add or modify text annotations and fill in interactive forms fields and,
         * if {@link #canModify() canModify()} returns true, create or modify interactive form fields
         * (including signature fields). Note that if {@link #canFillInForm() canFillInForm()} returns
         * true, it is still possible to fill in interactive forms (including signature fields) even the
         * parameter here is false.
         * <p>
         * This method will have no effect if the object is in read only mode.
         *
         * @param allowAnnotationModification A boolean determining the new setting.
         */
        public void setCanModifyAnnotations( boolean allowAnnotationModification )
        {
            if(!readOnly)
            {
                setPermissionBit( MODIFY_ANNOTATIONS_BIT, allowAnnotationModification );
            }
        }

        /**
         * This will tell if the user can fill in interactive form fields (including signature fields)
         * even if {@link #canModifyAnnotations() canModifyAnnotations()} returns false.
         *
         * @return true If supplied with the user password they are allowed to fill in form fields.
         */
        public boolean canFillInForm()
        {
            return isPermissionBitOn( FILL_IN_FORM_BIT );
        }

        /**
         * Set if the user can fill in interactive form fields (including signature fields) even if
         * {@link #canModifyAnnotations() canModifyAnnotations()} returns false. Therefore, if you want
         * to prevent a user from filling in interactive form fields, you need to call
         * {@link #setCanModifyAnnotations(boolean) setCanModifyAnnotations(false)} as well.
         *<p>
         * This method will have no effect if the object is in read only mode.
         *
         * @param allowFillingInForm A boolean determining if the user can fill in interactive forms.
         */
        public void setCanFillInForm( boolean allowFillingInForm )
        {
            if(!readOnly)
            {
                setPermissionBit( FILL_IN_FORM_BIT, allowFillingInForm );
            }
        }

        /**
         * This will tell if the user can extract text and images from the PDF document
         * for accessibility purposes.
         *
         * @return true If supplied with the user password they are allowed to extract content
         *              from the PDF document
         */
        public boolean canExtractForAccessibility()
        {
            return isPermissionBitOn( EXTRACT_FOR_ACCESSIBILITY_BIT );
        }

        /**
         * Set if the user can extract content from the document for accessibility purposes.
         * <p>
         * This method will have no effect if the object is in read only mode.
         *
         * @param allowExtraction A boolean determining if the user can extract content
         *                        from the document.
         */
        public void setCanExtractForAccessibility( boolean allowExtraction )
        {
            if(!readOnly)
            {
                setPermissionBit( EXTRACT_FOR_ACCESSIBILITY_BIT, allowExtraction );
            }
        }

        /**
         * This will tell if the user can insert/rotate/delete pages.
         *
         * @return true If supplied with the user password they are allowed to assemble the document.
         */
        public boolean canAssembleDocument()
        {
            return isPermissionBitOn( ASSEMBLE_DOCUMENT_BIT );
        }

        /**
         * Set if the user can insert/rotate/delete pages.
         * <p>
         * This method will have no effect if the object is in read only mode.
         *
         * @param allowAssembly A boolean determining if the user can assemble the document.
         */
        public void setCanAssembleDocument( boolean allowAssembly )
        {
            if(!readOnly)
            {
                setPermissionBit( ASSEMBLE_DOCUMENT_BIT, allowAssembly );
            }
        }

        /**
         * This will tell if the user can print the document in a faithful format or in a degraded
         * format (if print is enabled).
         *
         * @return true If supplied with the user password they are allowed to print the document in a
         * faithful format.
         */
        public boolean canPrintFaithful()
        {
            return isPermissionBitOn(FAITHFUL_PRINT_BIT);
        }

        /**
         * Set if the user can print the document in a faithful format or in a degraded format (if print
         * is enabled). The PDF version must be 1.5 or higher.
         * <p>
         * This method will have no effect if the object is in read only mode.
         *
         * @param canPrintFaithful A boolean determining if the user can print the document in a
         * faithful format.
         */
        public void setCanPrintFaithful(boolean canPrintFaithful)
        {
            if (!readOnly)
            {
                setPermissionBit(FAITHFUL_PRINT_BIT, canPrintFaithful);
            }
        }

        /**
         * Locks the access permission read only (ie, the setters will have no effects).
         * After that, the object cannot be unlocked.
         * This method is used for the currentAccessPermssion of a document to avoid
         * users to change access permission.
         */
        public void setReadOnly()
        {
            readOnly = true;
        }

        /**
         * This will tell if the object has been set as read only.
         *
         * @return true if the object is in read only mode.
         */

        public boolean isReadOnly()
        {
            return readOnly;
        }

        /**
         * Indicates if any revision 3 access permission is set or not.
         *
         * @return true if any revision 3 access permission is set
         */
        protected boolean hasAnyRevision3PermissionSet()
        {
            if (canFillInForm())
            {
                return true;
            }
            if (canExtractForAccessibility())
            {
                return true;
            }
            if (canAssembleDocument())
            {
                return true;
            }
            return canPrintFaithful();
        }
    }