File: data.rb

package info (click to toggle)
ruby-gpgme 2.0.23-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,920 kB
  • sloc: ruby: 3,129; ansic: 2,559; sh: 7; makefile: 5
file content (216 lines) | stat: -rw-r--r-- 6,171 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
module GPGME

  ##
  # A class whose purpose is to unify the way we work with the data (both input
  # and output). Most of the calls expect instances of this class, or will try
  # to create one from your parameters.
  #
  # Read the {#read}, {#write} and {#seek} methods for the most commonly used
  # methods.
  class Data

    BLOCK_SIZE = 4096

    class << self

      ##
      # We implement +self.new+ instead of initialize because objects are actually
      # instantiated through the C API with stuff like +gpgme_data_new+.
      #
      # We try to create a {GPGME::Data} smartly depending on the object passed, and if
      # another {GPGME::Data} object is passed, it just returns it, so when in
      # doubt, you can always pass a {GPGME::Data} object.
      #
      # @example empty
      #   data = GPGME::Data.new
      #   data.write("stuff")
      #
      # @example from a string
      #   data = GPGME::Data.new("From a string")
      #
      # @example from a file
      #   data = GPGME::Data.new(File.open("secure.pass"))
      #
      # @example from a file descriptor
      #   data = GPGME::Data.new(0) # Standard input
      #   data = GPGME::Data.new(1) # Standard output
      #
      #   file = File.open("secure.pass")
      #   data = GPGME::Data.new(file.fileno) # file descriptor
      #
      def new(object = nil)
        if object.nil?
          empty!
        elsif object.is_a?(Data)
          object
        elsif object.is_a?(Integer)
          from_fd(object)
        elsif object.respond_to? :to_str
          from_str(object.to_str)
        elsif object.respond_to? :to_io
          from_io(object.to_io)
        elsif object.respond_to? :open
          from_io(object.open)
        elsif defined?(StringIO) and object.is_a?(StringIO)
          from_io(object)
        end
      end

      # Create a new instance with an empty buffer.
      def empty!
        rdh = []
        err = GPGME::gpgme_data_new(rdh)
        exc = GPGME::error_to_exception(err)
        raise exc if exc
        rdh.first
      end

      # Create a new instance with internal buffer.
      def from_str(string)
        rdh = []
        err = GPGME::gpgme_data_new_from_mem(rdh, string, string.bytesize)
        exc = GPGME::error_to_exception(err)
        raise exc if exc
        rdh.first
      end

      # Create a new instance associated with a given IO.
      def from_io(io)
        from_callbacks(IOCallbacks.new(io))
      end

      # Create a new instance from the specified file descriptor.
      def from_fd(fd)
        rdh = []
        err = GPGME::gpgme_data_new_from_fd(rdh, fd)
        exc = GPGME::error_to_exception(err)
        raise exc if exc
        rdh.first
      end

      # Create a new instance from the specified callbacks.
      def from_callbacks(callbacks, hook_value = nil)
        rdh = []
        err = GPGME::gpgme_data_new_from_cbs(rdh, callbacks, hook_value)
        exc = GPGME::error_to_exception(err)
        raise exc if exc
        rdh.first
      end
    end # class << self

    # Read at most +length+ bytes from the data object, or to the end
    # of file if +length+ is omitted or is +nil+.
    #
    # @example
    #   data = GPGME::Data.new("From a string")
    #   data.read # => "From a string"
    #
    # @example
    #   data = GPGME::Data.new("From a string")
    #   data.read(4) # => "From"
    #
    def read(length = nil)
      if length
        GPGME::gpgme_data_read(self, length)
      else
        buf = String.new
        loop do
          s = GPGME::gpgme_data_read(self, BLOCK_SIZE)
          break unless s
          buf << s
        end
        buf
      end
    end

    ##
    # Seek to a given +offset+ in the data object according to the
    # value of +whence+.
    #
    # @example going to the beginning of the buffer after writing something
    #  data = GPGME::Data.new("Some data")
    #  data.read # => "Some data"
    #  data.read # => ""
    #  data.seek 0
    #  data.read # => "Some data"
    #
    def seek(offset, whence = IO::SEEK_SET)
      GPGME::gpgme_data_seek(self, offset, IO::SEEK_SET)
    end

    ##
    # Writes +length+ bytes from +buffer+ into the data object.
    # Writes the full buffer if no length passed.
    #
    # @example
    #   data = GPGME::Data.new
    #   data.write "hola"
    #   data.seek 0
    #   data.read # => "hola"
    #
    # @example
    #   data = GPGME::Data.new
    #   data.write "hola", 2
    #   data.seek 0
    #   data.read # => "ho"
    #
    def write(buffer, length = buffer.length)
      GPGME::gpgme_data_write(self, buffer, length)
    end

    ##
    # Return the encoding of the underlying data.
    def encoding
      GPGME::gpgme_data_get_encoding(self)
    end

    ##
    # Sets the encoding for this buffer. Accepts only integer values 0 to 7:
    #
    # 0 = GPGME_DATA_ENCODING_NONE   (Not specified)
    # 1 = GPGME_DATA_ENCODING_BINARY
    # 2 = GPGME_DATA_ENCODING_BASE64
    # 3 = GPGME_DATA_ENCODING_ARMOR  (Either PEM or OpenPGP Armor)
    # 4 = GPGME_DATA_ENCODING_URL    (LF delimited URL list)
    # 5 = GPGME_DATA_ENCODING_URLESC (Ditto, but percent escaped)
    # 6 = GPGME_DATA_ENCODING_URL0   (Nul delimited URL list)
    # 7 = GPGME_DATA_ENCODING_MIME   (Data is a MIME part)
    #
    # @raise [GPGME::Error::InvalidValue] if the value isn't accepted.
    def encoding=(encoding)
      err = GPGME::gpgme_data_set_encoding(self, encoding)
      exc = GPGME::error_to_exception(err)
      raise exc if exc
      encoding
    end

    ##
    # Return the file name of the underlying data.
    def file_name
      GPGME::gpgme_data_get_file_name(self)
    end

    ##
    # Sets the file name for this buffer.
    #
    # @raise [GPGME::Error::InvalidValue] if the value isn't accepted.
    def file_name=(file_name)
      err = GPGME::gpgme_data_set_file_name(self, file_name)
      exc = GPGME::error_to_exception(err)
      raise exc if exc
      file_name
    end

    ##
    # Return the entire content of the data object as string.
    def to_s
      pos = seek(0, IO::SEEK_CUR)
      begin
        seek(0)
        read
      ensure
        seek(pos)
      end
    end
  end
end