=begin

= File
	parsers/pdf.rb

= Info
	This file is part of Origami, PDF manipulation framework for Ruby
	Copyright (C) 2010	Guillaume Delugré <guillaume AT security-labs DOT org>
	All right reserved.
	
  Origami 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.

  Origami 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 Origami.  If not, see <http://www.gnu.org/licenses/>.

=end

require 'origami/parser'

module Origami
  
  class PDF
    class Parser < Origami::Parser
      def initialize(params = {})
        options =
        {
          :password => '',            # Default password being tried when opening a protected document.
          :prompt_password => Proc.new { 
            print "Password: "
            gets.chomp 
          },                          # Callback procedure to prompt password when document is encrypted.
          :force => false             # Force PDF header detection
        }.update(params)

        super(options)
      end

      private

      def parse_initialize #:nodoc:
        if @options[:force] == true
          @data.skip_until(/%PDF-/).nil?
          @data.pos = @data.pos - 5
        end

        pdf = PDF.new(self)

        info "...Reading header..."
        begin
          pdf.header = PDF::Header.parse(@data)
          @options[:callback].call(pdf.header)
        rescue InvalidHeaderError => e
          if @options[:ignore_errors] == true
            warn "PDF header is invalid, ignoring..."
          else
            raise e
          end
        end

        pdf
      end

      def parse_finalize(pdf) #:nodoc:
        warn "This file has been linearized." if pdf.is_linearized?

        if Origami::OPTIONS[:enable_type_propagation]
          info "...Propagating types..."
          @deferred_casts.each_pair do |ref, type|
            type = [ type ] unless type.is_a?(::Array)
            type.each do |hint|
              pdf.cast_object(ref, hint)
            end
          end
        end

        #
        # Decrypt encrypted file contents
        #
        if pdf.is_encrypted?
          warn "This document contains encrypted data!"
        
          passwd = @options[:password]
          begin
            pdf.decrypt(passwd)
          rescue EncryptionInvalidPasswordError
            if passwd.empty?
              passwd = @options[:prompt_password].call
              retry unless passwd.empty?
            end

            raise EncryptionInvalidPasswordError
          end
        end

        if pdf.is_signed?
          warn "This document has been signed!"
        end

        pdf
      end
    end
  end

end

require 'origami/parsers/pdf/linear'

