1# -*- coding: utf-8 -*-
2#++
3# Copyright (C) 2004 Mauricio Julio Fernández Pradier
4# See LICENSE.txt for additional licensing information.
5#--
6
7##
8# Class for reading entries out of a tar file
9
10class Gem::Package::TarReader::Entry
11
12  ##
13  # Header for this tar entry
14
15  attr_reader :header
16
17  ##
18  # Creates a new tar entry for +header+ that will be read from +io+
19
20  def initialize(header, io)
21    @closed = false
22    @header = header
23    @io = io
24    @orig_pos = @io.pos
25    @read = 0
26  end
27
28  def check_closed # :nodoc:
29    raise IOError, "closed #{self.class}" if closed?
30  end
31
32  ##
33  # Number of bytes read out of the tar entry
34
35  def bytes_read
36    @read
37  end
38
39  ##
40  # Closes the tar entry
41
42  def close
43    @closed = true
44  end
45
46  ##
47  # Is the tar entry closed?
48
49  def closed?
50    @closed
51  end
52
53  ##
54  # Are we at the end of the tar entry?
55
56  def eof?
57    check_closed
58
59    @read >= @header.size
60  end
61
62  ##
63  # Full name of the tar entry
64
65  def full_name
66    if @header.prefix != "" then
67      File.join @header.prefix, @header.name
68    else
69      @header.name
70    end
71  rescue ArgumentError => e
72    raise unless e.message == 'string contains null byte'
73    raise Gem::Package::TarInvalidError,
74          'tar is corrupt, name contains null byte'
75  end
76
77  ##
78  # Read one byte from the tar entry
79
80  def getc
81    check_closed
82
83    return nil if @read >= @header.size
84
85    ret = @io.getc
86    @read += 1 if ret
87
88    ret
89  end
90
91  ##
92  # Is this tar entry a directory?
93
94  def directory?
95    @header.typeflag == "5"
96  end
97
98  ##
99  # Is this tar entry a file?
100
101  def file?
102    @header.typeflag == "0"
103  end
104
105  ##
106  # The position in the tar entry
107
108  def pos
109    check_closed
110
111    bytes_read
112  end
113
114  ##
115  # Reads +len+ bytes from the tar file entry, or the rest of the entry if
116  # nil
117
118  def read(len = nil)
119    check_closed
120
121    return nil if @read >= @header.size
122
123    len ||= @header.size - @read
124    max_read = [len, @header.size - @read].min
125
126    ret = @io.read max_read
127    @read += ret.size
128
129    ret
130  end
131
132  ##
133  # Rewinds to the beginning of the tar file entry
134
135  def rewind
136    check_closed
137
138    raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
139
140    @io.pos = @orig_pos
141    @read = 0
142  end
143
144end
145
146