Class: Zip::CentralDirectory

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/zip/central_directory.rb

Direct Known Subclasses

File

Constant Summary collapse

END_OF_CDS =
0x06054b50
ZIP64_END_OF_CDS =
0x06064b50
ZIP64_EOCD_LOCATOR =
0x07064b50
MAX_END_OF_CDS_SIZE =
65536 + 18
STATIC_EOCD_SIZE =
22

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(entries = EntrySet.new, comment = '') ⇒ CentralDirectory

:nodoc:



18
19
20
21
22
# File 'lib/zip/central_directory.rb', line 18

def initialize(entries = EntrySet.new, comment = '') #:nodoc:
  super()
  @entry_set = entries.kind_of?(EntrySet) ? entries : EntrySet.new(entries)
  @comment   = comment
end

Instance Attribute Details

#commentObject (readonly)

Returns the value of attribute comment.



11
12
13
# File 'lib/zip/central_directory.rb', line 11

def comment
  @comment
end

Class Method Details

.read_from_stream(io) ⇒ Object

:nodoc:



188
189
190
191
192
193
194
# File 'lib/zip/central_directory.rb', line 188

def self.read_from_stream(io) #:nodoc:
  cdir = new
  cdir.read_from_stream(io)
  return cdir
rescue ZipError
  return nil
end

Instance Method Details

#==(other) ⇒ Object

:nodoc:



196
197
198
199
# File 'lib/zip/central_directory.rb', line 196

def ==(other) #:nodoc:
  return false unless other.kind_of?(CentralDirectory)
  @entry_set.entries.sort == other.entries.sort && comment == other.comment
end

#each(&proc) ⇒ Object

For iterating over the entries.



178
179
180
# File 'lib/zip/central_directory.rb', line 178

def each(&proc)
  @entry_set.each(&proc)
end

#entriesObject

Returns an Enumerable containing the entries.



14
15
16
# File 'lib/zip/central_directory.rb', line 14

def entries
  @entry_set.entries
end

#get_64_e_o_c_d(buf) ⇒ Object

:nodoc:

Raises:



163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/zip/central_directory.rb', line 163

def get_64_e_o_c_d(buf) #:nodoc:
  zip_64_start = buf.rindex([ZIP64_END_OF_CDS].pack('V'))
  raise ZipError, "Zip64 end of central directory signature not found" unless zip_64_start
  zip_64_locator = buf.rindex([ZIP64_EOCD_LOCATOR].pack('V'))
  raise ZipError, "Zip64 end of central directory signature locator not found" unless zip_64_locator
  buf = buf.slice!((zip_64_start + 4)..zip_64_locator)

  def buf.read(count)
    slice!(0, count)
  end

  buf
end

#get_e_o_c_d(buf) ⇒ Object

:nodoc:

Raises:



138
139
140
141
142
143
144
145
146
147
148
# File 'lib/zip/central_directory.rb', line 138

def get_e_o_c_d(buf) #:nodoc:
  sig_index = buf.rindex([END_OF_CDS].pack('V'))
  raise ZipError, "Zip end of central directory signature not found" unless sig_index
  buf = buf.slice!((sig_index + 4)..(buf.bytesize))

  def buf.read(count)
    slice!(0, count)
  end

  buf
end

#read_64_e_o_c_d(buf) ⇒ Object

:nodoc:

Raises:



84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/zip/central_directory.rb', line 84

def read_64_e_o_c_d(buf) #:nodoc:
  buf                                           = get_64_e_o_c_d(buf)
  @size_of_zip64_e_o_c_d                        = Entry.read_zip_64_long(buf)
  @version_made_by                              = Entry.read_zip_short(buf)
  @version_needed_for_extract                   = Entry.read_zip_short(buf)
  @number_of_this_disk                          = Entry.read_zip_long(buf)
  @number_of_disk_with_start_of_cdir            = Entry.read_zip_long(buf)
  @total_number_of_entries_in_cdir_on_this_disk = Entry.read_zip_64_long(buf)
  @size                                         = Entry.read_zip_64_long(buf)
  @size_in_bytes                                = Entry.read_zip_64_long(buf)
  @cdir_offset                                  = Entry.read_zip_64_long(buf)
  @zip_64_extensible                            = buf.slice!(0, buf.bytesize)
  raise ZipError, "Zip consistency problem while reading eocd structure" unless buf.size == 0
end

#read_central_directory_entries(io) ⇒ Object

:nodoc:



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/zip/central_directory.rb', line 116

def read_central_directory_entries(io) #:nodoc:
  begin
    io.seek(@cdir_offset, IO::SEEK_SET)
  rescue Errno::EINVAL
    raise ZipError, "Zip consistency problem while reading central directory entry"
  end
  @entry_set = EntrySet.new
  @size.times do
    @entry_set << Entry.read_c_dir_entry(io)
  end
end

#read_e_o_c_d(buf) ⇒ Object

:nodoc:

Raises:



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/zip/central_directory.rb', line 99

def read_e_o_c_d(buf) #:nodoc:
  buf                                           = get_e_o_c_d(buf)
  @number_of_this_disk                          = Entry.read_zip_short(buf)
  @number_of_disk_with_start_of_cdir            = Entry.read_zip_short(buf)
  @total_number_of_entries_in_cdir_on_this_disk = Entry.read_zip_short(buf)
  @size                                         = Entry.read_zip_short(buf)
  @size_in_bytes                                = Entry.read_zip_long(buf)
  @cdir_offset                                  = Entry.read_zip_long(buf)
  comment_length                                = Entry.read_zip_short(buf)
  @comment                                      = if comment_length <= 0
                                                    buf.slice!(0, buf.size)
                                                  else
                                                    buf.read(comment_length)
                                                  end
  raise ZipError, "Zip consistency problem while reading eocd structure" unless buf.size == 0
end

#read_from_stream(io) ⇒ Object

:nodoc:



128
129
130
131
132
133
134
135
136
# File 'lib/zip/central_directory.rb', line 128

def read_from_stream(io) #:nodoc:
  buf = start_buf(io)
  if self.zip64_file?(buf)
    read_64_e_o_c_d(buf)
  else
    read_e_o_c_d(buf)
  end
  read_central_directory_entries(io)
end

#sizeObject

Returns the number of entries in the central directory (and consequently in the zip archive).



184
185
186
# File 'lib/zip/central_directory.rb', line 184

def size
  @entry_set.size
end

#start_buf(io) ⇒ Object



154
155
156
157
158
159
160
161
# File 'lib/zip/central_directory.rb', line 154

def start_buf(io)
  begin
    io.seek(-MAX_END_OF_CDS_SIZE, IO::SEEK_END)
  rescue Errno::EINVAL
    io.seek(0, IO::SEEK_SET)
  end
  io.read
end

#write_to_stream(io) ⇒ Object

:nodoc:



24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/zip/central_directory.rb', line 24

def write_to_stream(io) #:nodoc:
  cdir_offset = io.tell
  @entry_set.each { |entry| entry.write_c_dir_entry(io) }
  eocd_offset = io.tell
  cdir_size = eocd_offset - cdir_offset
  has_zip64_entry = @entry_set.any? { |entry| entry.extra['Zip64'] }
  if has_zip64_entry || cdir_offset > 0xFFFFFFFF || cdir_size > 0xFFFFFFFF || @entry_set.size > 0xFFFF
    write_64_e_o_c_d(io, cdir_offset, cdir_size)
    write_64_eocd_locator(io, eocd_offset)
  end
  write_e_o_c_d(io, cdir_offset, cdir_size)
end

#zip64_file?(buf) ⇒ Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/zip/central_directory.rb', line 150

def zip64_file?(buf)
  buf.rindex([ZIP64_END_OF_CDS].pack('V')) && buf.rindex([ZIP64_EOCD_LOCATOR].pack('V'))
end