core.bmx 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  1. ' Copyright (c) 2022 Bruce A Henderson
  2. ' All rights reserved.
  3. '
  4. ' Redistribution and use in source and binary forms, with or without
  5. ' modification, are permitted provided that the following conditions are met:
  6. ' * Redistributions of source code must retain the above copyright
  7. ' notice, this list of conditions and the following disclaimer.
  8. ' * Redistributions in binary form must reproduce the above copyright
  9. ' notice, this list of conditions and the following disclaimer in the
  10. ' documentation and/or other materials provided with the distribution.
  11. '
  12. ' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY
  13. ' EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. ' WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. ' DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
  16. ' DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. ' (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. ' LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. ' ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. ' (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. ' SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. '
  23. SuperStrict
  24. Rem
  25. bbdoc: Streaming Archive Library
  26. End Rem
  27. Module Archive.Core
  28. ModuleInfo "Version: 1.07"
  29. ModuleInfo "License: BSD"
  30. ModuleInfo "Copyright: libarchive - 2003-2018 Tim Kientzle"
  31. ModuleInfo "Copyright: Wrapper - 2013-2022 Bruce A Henderson"
  32. ModuleInfo "History: 1.07"
  33. ModuleInfo "History: Update to libarchive 3.6.2.2d32907."
  34. ModuleInfo "History: Added DataStream() to TWriteArchive, returning a writeable TStream."
  35. ModuleInfo "History: 1.06"
  36. ModuleInfo "History: Update to libarchive 3.5.2.b967588."
  37. ModuleInfo "History: 1.05"
  38. ModuleInfo "History: Update to libarchive 3.3.4.458e493."
  39. ModuleInfo "History: 1.04"
  40. ModuleInfo "History: Update to libarchive 3.3.4.c16ce12."
  41. ModuleInfo "History: 1.03"
  42. ModuleInfo "History: Added zstd support."
  43. ModuleInfo "History: 1.02"
  44. ModuleInfo "History: Update to libarchive 3.3.2.77d26b0."
  45. ModuleInfo "History: 1.01"
  46. ModuleInfo "History: Removed libiconv requirement from Win32."
  47. ModuleInfo "History: 1.00"
  48. ModuleInfo "History: Initial Release. libarchive 3.1.2"
  49. ModuleInfo "CC_OPTS: -DHAVE_CONFIG_H -D_FILE_OFFSET_BITS=64"
  50. ?win32
  51. ModuleInfo "CC_OPTS: -DLIBARCHIVE_STATIC"
  52. ?
  53. Import "common.bmx"
  54. Import BRL.Stream
  55. Import BRL.FileSystem
  56. Rem
  57. bbdoc: Archive base type.
  58. End Rem
  59. Type TArchive
  60. Field archivePtr:Byte Ptr
  61. Rem
  62. bbdoc: Clears any error information left over from a previous call.
  63. about: Not generally used in client code.
  64. End Rem
  65. Method ClearError()
  66. bmx_libarchive_archive_clear_error(archivePtr)
  67. End Method
  68. Rem
  69. bbdoc: Returns a numeric error code indicating the reason for the most recent error return.
  70. about: Note that this can not be reliably used to detect whether an error has occurred.
  71. It should be used only after another libarchive function has returned an error status.
  72. End Rem
  73. Method Errno:Int()
  74. Return bmx_libarchive_archive_errno(archivePtr)
  75. End Method
  76. Rem
  77. bbdoc: Returns a textual error message suitable for display.
  78. about: The error message here is usually more specific than that obtained from passing the result of archive_errno() to strerror(3).
  79. End Rem
  80. Method ErrorString:String()
  81. Return bmx_libarchive_archive_error_string(archivePtr)
  82. End Method
  83. Rem
  84. bbdoc: Returns a count of the number of files processed by this archive object.
  85. about: The count is incremented by calls to WriteHeader or ReadNextHeader.
  86. End Rem
  87. Method FileCount:Int()
  88. Return bmx_libarchive_archive_file_count(archivePtr)
  89. End Method
  90. Rem
  91. bbdoc: Returns a numeric code identifying the indicated filter.
  92. about: See FilterCount() for details of the numbering.
  93. End Rem
  94. Method FilterCode:Int(filter:Int)
  95. Return bmx_libarchive_archive_filter_code(archivePtr, filter)
  96. End Method
  97. Rem
  98. bbdoc: Returns the number of filters in the current pipeline.
  99. about: For read archive handles, these filters are added automatically by the automatic format detection.
  100. For write archive handles, these filters are added by calls to the various AddFilterXXX() methods. Filters in the
  101. resulting pipeline are numbered so that filter 0 is the filter closest to the format handler. As a convenience,
  102. methods that expect a filter number will accept -1 as a synonym for the highest-numbered filter.
  103. <p>
  104. For example, when reading a uuencoded gzipped tar archive, there are three filters: filter 0 is the gunzip filter, filter 1 is the uudecode
  105. filter, and filter 2 is the pseudo-filter that wraps the archive read methods. In this case, requesting Position(-1) would be a synonym
  106. for Position(2) which would return the number of bytes currently read from the archive, while Position(1) would return the number of
  107. bytes after uudecoding, and Position(0) would return the number of bytes after decompression.
  108. </p>
  109. End Rem
  110. Method FilterCount:Int()
  111. Return bmx_libarchive_archive_filter_count(archivePtr)
  112. End Method
  113. Rem
  114. bbdoc: Returns a textual name identifying the indicated filter.
  115. about: See FilterCount() for details of the numbering.
  116. End Rem
  117. Method FilterName:String(filter:Int)
  118. Return bmx_libarchive_archive_filter_name(archivePtr, filter)
  119. End Method
  120. Rem
  121. bbdoc: Returns a numeric code indicating the format of the current archive entry.
  122. about: This value is set by a successful call to ReadNextHeader(). Note that it is common for this value to
  123. change from entry to entry. For example, a tar archive might have several entries that utilize GNU
  124. tar extensions and several entries that do not. These entries will have different format codes.
  125. End Rem
  126. Method Format:Int()
  127. Return bmx_libarchive_archive_format(archivePtr)
  128. End Method
  129. Rem
  130. bbdoc: A textual description of the format of the current entry.
  131. End Rem
  132. Method FormatName:String()
  133. Return bmx_libarchive_archive_format_name(archivePtr)
  134. End Method
  135. Rem
  136. bbdoc: Returns the number of bytes read from or written to the indicated filter.
  137. about: In particular, Position(0) returns the number of bytes read or written by the format handler,
  138. while Position(-1) returns the number of bytes read or written to the archive. See FilterCount() for details of the numbering here.
  139. End Rem
  140. Method Position:Long(filter:Int)
  141. Local v:Long
  142. bmx_libarchive_archive_position(archivePtr, filter, Varptr v)
  143. Return v
  144. End Method
  145. Method Data:Int(data:Byte Ptr, size:Size_T) Abstract
  146. Method Free() Abstract
  147. Method Delete()
  148. Free()
  149. End Method
  150. End Type
  151. Rem
  152. bbdoc: A readable archive.
  153. about: This is used for extracting data from existing archives.
  154. End Rem
  155. Type TReadArchive Extends TArchive
  156. Field callbackData:TArchiveCallbackData
  157. Field passphraseCallback:String(archive:TReadArchive, data:Object, cancel:Int Var)
  158. Field passphraseCallbackData:Object
  159. Field StaticArray pw:Byte[1024]
  160. Function CreateArchive:TReadArchive()
  161. Return New TReadArchive()
  162. End Function
  163. Rem
  164. bbdoc: Creates a new instance of #TReadArchive.
  165. End Rem
  166. Method New()
  167. archivePtr = bmx_libarchive_read_archive_new()
  168. End Method
  169. Rem
  170. bbdoc: Creates a new instance of #TReadArchive with the specified format and filters.
  171. End Rem
  172. Method New(format:EArchiveFormat, filters:EArchiveFilter[])
  173. New()
  174. SetFormat(format)
  175. For Local filter:EArchiveFilter = Eachin filters
  176. AddFilter(filter)
  177. Next
  178. End Method
  179. Rem
  180. bbdoc: Registers a passphrase for the archive.
  181. End Rem
  182. Method AddPassphrase:Int(passphrase:String)
  183. Return bmx_libarchive_archive_read_add_passphrase(archivePtr, passphrase)
  184. End Method
  185. Private
  186. Function _passphraseCallback:Byte Ptr(archive:TReadArchive) { nomangle }
  187. Local cancel:Int
  188. Local pass:String = archive.passphraseCallback(archive, archive.passphraseCallbackData, cancel)
  189. If cancel Then
  190. Return Null
  191. Else
  192. Local length:Size_T = 1024
  193. Return pass.ToUTF8StringBuffer(archive.pw, length)
  194. End If
  195. End Function
  196. Public
  197. Rem
  198. bbdoc: Registers a callback function that will be invoked to get a passphrase for decryption after trying all the passphrases registered by #AddPassphrase.
  199. End Rem
  200. Method SetPassphraseCallback:Int(callback:String(archive:TReadArchive, data:Object, cancel:Int Var), data:Object)
  201. Local cb:Byte Ptr = callback
  202. If Not cb Then
  203. passphraseCallback = Null
  204. passphraseCallbackData = Null
  205. Return bmx_libarchive_archive_read_set_passphrase_callback(archivePtr, Null)
  206. Else
  207. passphraseCallback = callback
  208. passphraseCallbackData = data
  209. Return bmx_libarchive_archive_read_set_passphrase_callback(archivePtr, self)
  210. End If
  211. End Method
  212. Rem
  213. bbdoc: Returns #True if the archive has encrypted entries.
  214. End Rem
  215. Method HasEncryptedEntries:Int()
  216. Return bmx_libarchive_archive_read_has_encrypted_entries(archivePtr)
  217. End Method
  218. Rem
  219. bbdoc: Opens archive for reading from a file of the given @filename, with a block size of @blockSize bytes.
  220. about: The file should be readable.
  221. End Rem
  222. Method Open:Int(filename:String, blockSize:Int = 10240)
  223. Local stream:TStream = ReadStream(filename)
  224. If Not stream Then
  225. Throw New TArchiveException("Unable to create stream for reading")
  226. End If
  227. Return Open(stream, blockSize, True)
  228. End Method
  229. Rem
  230. bbdoc: Opens archive for reading from memory.
  231. about: @size indicates the size of the archive in memory at location @buf.
  232. End Rem
  233. Method Open:Int(buf:Byte Ptr, size:Size_T)
  234. Return bmx_libarchive_archive_read_open_memory(archivePtr, buf, size)
  235. End Method
  236. Rem
  237. bbdoc: Opens archive for reading from a @stream, with a block size of @blockSize bytes.
  238. about: @stream should already be created and readable.
  239. If @closeAfterRead is set, the stream will be closed when the archive is closed.
  240. End Rem
  241. Method Open:Int(stream:TStream, blockSize:Int = 10240, closeAfterRead:Int = False)
  242. If Not stream Then
  243. Throw New TArchiveException("stream cannot be Null")
  244. End If
  245. If Not callbackData Then
  246. callbackData = New TArchiveCallbackData(stream, blockSize)
  247. Else
  248. callbackData.Update(stream, blockSize)
  249. End If
  250. callbackData.shouldClose = closeAfterRead
  251. Return bmx_libarchive_archive_read_open(archivePtr, callbackData)
  252. End Method
  253. Rem
  254. bbdoc: Read the header for the next entry and populate the provided entry
  255. returns: ARCHIVE_OK (the operation succeeded), ARCHIVE_WARN (the operation succeeded but a non-critical error was encountered), ARCHIVE_EOF (end-of-archive was encountered), ARCHIVE_RETRY (the operation failed but can be retried), and ARCHIVE_FATAL (there was a fatal error; the archive should be closed immediately).
  256. End Rem
  257. Method ReadNextHeader:Int(entry:TArchiveEntry)
  258. Return bmx_libarchive_archive_read_next_header(archivePtr, entry.entryPtr)
  259. End Method
  260. Rem
  261. bbdoc: A convenience method that repeatedly skips all of the data for this archive entry.
  262. End Rem
  263. Method DataSkip:Int()
  264. Return bmx_libarchive_archive_read_data_skip(archivePtr)
  265. End Method
  266. Rem
  267. bbdoc: Read data associated with the header just read.
  268. returns: A count of bytes actually read or zero at the end of the entry. On error, a value of #ARCHIVE_FATAL, #ARCHIVE_WARN, or #ARCHIVE_RETRY is returned.
  269. End Rem
  270. Method Data:Int(buf:Byte Ptr, size:Size_T) Override
  271. Return bmx_libarchive_archive_read_data(archivePtr, buf, size)
  272. End Method
  273. Rem
  274. bbdoc: Returns a readable #TStream of the current entry data.
  275. about: This can be used by any #TStream supported functionality.
  276. End Rem
  277. Method DataStream:TStream()
  278. Return New TArchiveInputStream(Self)
  279. End Method
  280. Rem
  281. bbdoc: Adds a filter for reading.
  282. End Rem
  283. Method AddFilter(filter:EArchiveFilter)
  284. ArchiveAddReadFilter(archivePtr, filter)
  285. End Method
  286. Rem
  287. bbdoc: Sets a format for reading.
  288. End Rem
  289. Method SetFormat(format:EArchiveFormat)
  290. ArchiveSetReadFormat(archivePtr, format)
  291. End Method
  292. Rem
  293. bbdoc: Sets a filter option.
  294. End Rem
  295. Method SetFilterOption:Int(option:String, value:String = Null, moduleName:String = Null)
  296. Return bmx_libarchive_archive_read_set_filter_option(archivePtr, option, value, moduleName)
  297. End Method
  298. Rem
  299. bbdoc: Sets a format option.
  300. End Rem
  301. Method SetFormatOption:Int(option:String, value:String = Null, moduleName:String = Null)
  302. Return bmx_libarchive_archive_read_set_format_option(archivePtr, option, value, moduleName)
  303. End Method
  304. Method Free() Override
  305. If archivePtr Then
  306. bmx_libarchive_archive_read_free(archivePtr)
  307. archivePtr = Null
  308. End If
  309. End Method
  310. End Type
  311. Rem
  312. bbdoc: Data from a TReadArchive entry as a stream.
  313. End Rem
  314. Type TArchiveInputStream Extends TStream
  315. Field archive:TArchive
  316. Field _eof:Int
  317. Method New(archive:TArchive)
  318. Self.archive = archive
  319. End Method
  320. Method Read:Long( buf:Byte Ptr,count:Long )
  321. Local size:Long = archive.Data(buf, Size_T(count))
  322. If size <= 0 Then
  323. _eof = True
  324. If size < 0 Then
  325. size = 0
  326. End If
  327. End If
  328. Return size
  329. End Method
  330. Method ReadBytes:Long( buf:Byte Ptr,count:Long )
  331. Local t:Long=0
  332. While count>0
  333. Local n:Long=Read( buf,count )
  334. If Not n Exit
  335. count:-n
  336. buf:+n
  337. t:+ n
  338. Wend
  339. Return t
  340. End Method
  341. Method Eof:Int()
  342. Return _eof
  343. End Method
  344. End Type
  345. Type TArchiveOutputStream Extends TStream
  346. Field archive:TWriteArchive
  347. Field _eof:Int
  348. Method New(archive:TWriteArchive)
  349. Self.archive = archive
  350. End Method
  351. Method Write:Long( buf:Byte Ptr,count:Long )
  352. Return archive.Data(buf, Size_T(count))
  353. End Method
  354. Method WriteBytes:Long( buf:Byte Ptr,count:Long )
  355. Local t:Long=count
  356. While count>0
  357. Local n:Long=Write( buf,count )
  358. If Not n Exit
  359. count:-n
  360. buf:+n
  361. Wend
  362. Return t
  363. End Method
  364. End Type
  365. Type TArchiveCallbackData
  366. Field data:Byte[]
  367. Field stream:TStream
  368. Field shouldClose:Int
  369. Method New(stream:TStream, blockSize:Int = 10240)
  370. Self.data = New Byte[blockSize]
  371. Self.stream = stream
  372. End Method
  373. Function _read:Byte Ptr(cbData:Object, count:Long Var) { nomangle }
  374. Local data:TArchiveCallbackData = TArchiveCallbackData(cbData)
  375. Local buf:Byte Ptr = data.data
  376. Local c:Long = data.data.Length
  377. Local ncount:Long
  378. While c
  379. Local n:Long = data.stream.Read(buf, c)
  380. If Not n Then
  381. Exit
  382. End If
  383. c:-n
  384. ncount:+ n
  385. buf:+n
  386. Wend
  387. count = ncount
  388. Return data.data
  389. End Function
  390. Function _seek(cbData:Object, offset:Long, whence:Int, count:Long Var) { nomangle }
  391. Local data:TArchiveCallbackData = TArchiveCallbackData(cbData)
  392. Select whence
  393. Case SEEK_SET_
  394. count = data.stream.seek(offset)
  395. Case SEEK_CUR_
  396. count = data.stream.seek(offset + data.stream.pos())
  397. Case SEEK_END_
  398. count = data.stream.seek(data.stream.size())
  399. End Select
  400. End Function
  401. Function _write(cbData:Object, buf:Byte Ptr, length:Size_T, count:Long Var) { nomangle }
  402. Local data:TArchiveCallbackData = TArchiveCallbackData(cbData)
  403. count = data.stream.Write(buf, length)
  404. End Function
  405. Function _close:Int(cbData:Object) { nomangle }
  406. Local data:TArchiveCallbackData = TArchiveCallbackData(cbData)
  407. data.Close()
  408. Return ARCHIVE_OK
  409. End Function
  410. Method Update(stream:TStream, size:Int)
  411. Self.stream = stream
  412. data = data[..size]
  413. End Method
  414. Method Close()
  415. If shouldClose Then
  416. stream.Close()
  417. End If
  418. End Method
  419. Method Delete()
  420. data = Null
  421. End Method
  422. End Type
  423. Rem
  424. bbdoc: A writeable archive.
  425. End Rem
  426. Type TWriteArchive Extends TArchive
  427. Field callbackData:TArchiveCallbackData
  428. Function CreateArchive:TWriteArchive()
  429. Return New TWriteArchive()
  430. End Function
  431. Rem
  432. bbdoc: Creates a new instance of #TWriteArchive.
  433. End Rem
  434. Method New()
  435. archivePtr = bmx_libarchive_write_archive_new()
  436. End Method
  437. Rem
  438. bbdoc: Creates a new instance of #TWriteArchive with the specified format and filters.
  439. End Rem
  440. Method New(format:EArchiveFormat, filters:EArchiveFilter[])
  441. New()
  442. SetFormat(format)
  443. For Local filter:EArchiveFilter = Eachin filters
  444. AddFilter(filter)
  445. Next
  446. End Method
  447. Rem
  448. bbdoc: Opens archive for writing to a file of the given @filename.
  449. about: The file should be writeable.
  450. End Rem
  451. Method Open:Int(filename:String)
  452. Local stream:TStream = WriteStream(filename)
  453. If Not stream Then
  454. Throw New TArchiveException("Unable to create stream for writing")
  455. End If
  456. Return Open(stream, True)
  457. End Method
  458. Rem
  459. bbdoc: Opens archive for writing to memory.
  460. about: The @size should be large enough for the final archive.
  461. After writing, @used will be populated with the total bytes used, so the pointer should remain valid until then.
  462. End Rem
  463. Method Open:Int(buf:Byte Ptr, size:Int, used:Size_T Ptr)
  464. Return bmx_libarchive_archive_write_open_memory(archivePtr, buf, size, Varptr used)
  465. End Method
  466. Rem
  467. bbdoc: Opens archive for writing to a @stream.
  468. about: @stream should already be created and writeable.
  469. If @closeAfterWrite is set, the stream will be closed once the write completes.
  470. End Rem
  471. Method Open:Int(stream:TStream, closeAfterWrite:Int = False)
  472. If Not stream Then
  473. Throw New TArchiveException("stream cannot be Null")
  474. End If
  475. If Not callbackData Then
  476. callbackData = New TArchiveCallbackData(stream, 0)
  477. Else
  478. callbackData.Update(stream, 0)
  479. End If
  480. callbackData.shouldClose = closeAfterWrite
  481. Return bmx_libarchive_archive_write_open(archivePtr, callbackData)
  482. End Method
  483. Rem
  484. bbdoc: Convience method for adding a file or #TStream to the archive.
  485. about: If adding a #TStream, you will also need to provide @pathname, @size and @ftime values.
  486. By default, files are added with the permission '0644' (decimal 420).
  487. @pathname can also be used to define the path (include sub directories) of the file within the archive - this
  488. is also dependent on support from the archive in question.
  489. @fileType will
  490. End Rem
  491. Method AddEntry(file:Object, pathname:String = Null, size:Long = 0, ftime:Long = 0, fileType:EArchiveFileType = EArchiveFileType.File)
  492. If String(file) Then
  493. If Not pathname Then
  494. pathname = StripDir(String(file))
  495. End If
  496. If Not ftime Then
  497. ftime = FileTime(String(file))
  498. End If
  499. End If
  500. If Not pathname Then
  501. Throw New TArchiveException("Pathname is required. Unable to determine pathname from input")
  502. End If
  503. If fileType <> EArchiveFileType.File And fileType <> EArchiveFileType.Dir Then
  504. Throw New TArchiveException("fileType must be a File or a Dir.")
  505. End If
  506. Local stream:TStream
  507. If fileType = EArchiveFileType.File Then
  508. stream = ReadStream(file)
  509. If Not stream Then
  510. Throw New TArchiveException("Unabled to open stream for input file for path '" + pathname + "'")
  511. End If
  512. If Not size Then
  513. size = stream.Size()
  514. End If
  515. End If
  516. Local entry:TArchiveEntry = New TArchiveEntry
  517. entry.SetPathname(pathname)
  518. entry.SetFileType(fileType)
  519. If fileType = EArchiveFileType.File Then
  520. entry.SetPermission(420) ' 0644
  521. entry.SetSize(size)
  522. If ftime Then
  523. entry.SetModifiedTime(ftime)
  524. End If
  525. End If
  526. If Header(entry) <> ARCHIVE_OK Then
  527. Throw New TArchiveException(String.FromUTF8String(archive_error_string(archivePtr)))
  528. End If
  529. If fileType = EArchiveFileType.File Then
  530. Local StaticArray buf:Byte[8192]
  531. Local count:Size_T = size
  532. While count
  533. Local nCount:Long = stream.Read(buf, Min(count, buf.Length))
  534. If nCount <= 0 Then
  535. Exit
  536. End If
  537. Data(buf, Size_T(nCount))
  538. count :- nCount
  539. Wend
  540. If Not TStream(file) Then
  541. stream.Close()
  542. End If
  543. End If
  544. FinishEntry()
  545. entry.Free()
  546. End Method
  547. Rem
  548. bbdoc: Build and write a header using the data in the provided in the TArchiveEntry object.
  549. about: See TArchiveEntry for information on creating and populating such objects.
  550. End Rem
  551. Method Header:Int(entry:TArchiveEntry)
  552. Return bmx_libarchive_archive_write_header(archivePtr, entry.entryPtr)
  553. End Method
  554. Rem
  555. bbdoc: Closes the archive.
  556. End Rem
  557. Method Close:Int()
  558. Return bmx_libarchive_archive_write_close(archivePtr)
  559. End Method
  560. Rem
  561. bbdoc: Informs the archive that the current archive entry is finished.
  562. End Rem
  563. Method FinishEntry:Int()
  564. Return bmx_libarchive_archive_write_finish_entry(archivePtr)
  565. End Method
  566. Rem
  567. bbdoc: Writes @size bytes of data to the current archive entry.
  568. End Rem
  569. Method Data:Int(data:Byte Ptr, size:Size_T) Override
  570. Return bmx_libarchive_archive_write_data(archivePtr, data, size)
  571. End Method
  572. Rem
  573. bbdoc: Returns a writeable #TStream.
  574. about: This can be used by any #TStream supported functionality.
  575. End Rem
  576. Method DataStream:TStream()
  577. Return New TArchiveOutputStream(Self)
  578. End Method
  579. Rem
  580. bbdoc: Sets a passphrase for the archive.
  581. End Rem
  582. Method SetPassphrase:Int(passphrase:String)
  583. Return bmx_libarchive_archive_write_set_passphrase(archivePtr, passphrase)
  584. End Method
  585. Rem
  586. bbdoc: Adds a filter for writing.
  587. End Rem
  588. Method AddFilter(filter:EArchiveFilter)
  589. ArchiveAddWriteFilter(archivePtr, filter)
  590. End Method
  591. Rem
  592. bbdoc: Adds a format for writing.
  593. End Rem
  594. Method SetFormat(format:EArchiveFormat)
  595. ArchiveSetWriteFormat(archivePtr, format)
  596. End Method
  597. Rem
  598. bbdoc: Sets a filter option.
  599. End Rem
  600. Method SetFilterOption:Int(option:String, value:String = Null, moduleName:String = Null)
  601. Return bmx_libarchive_archive_write_set_filter_option(archivePtr, option, value, moduleName)
  602. End Method
  603. Rem
  604. bbdoc: Sets a format option.
  605. End Rem
  606. Method SetFormatOption:Int(option:String, value:String = Null, moduleName:String = Null)
  607. Return bmx_libarchive_archive_write_set_format_option(archivePtr, option, value, moduleName)
  608. End Method
  609. Rem
  610. bbdoc: Sets the compression level for a compatible format/filter.
  611. returns: #ARCHIVE_OK on success, or an error code.
  612. about:
  613. | Type | Supported Compression Level | Notes |
  614. |---------|:---------------------------:|-------------------------------------------------------------------------------------------------------------------------------------------|
  615. | bzip2 | 1 - 9 | |
  616. | gzip | 0 - 9 | |
  617. | lz4 | 0 - 9 | |
  618. | lzop | 1 - 9 | |
  619. | xz | 0 - 9 | |
  620. | zstd | 1 - 22 | |
  621. | 7zip | 0 - 9 | |
  622. | iso9660 | 0 - 9 (default 6) | |
  623. | zip | 0 - 9 | A compression level of 0 switches the compression method to "store", other values will enable "deflate" compression with the given level. |
  624. End Rem
  625. Method SetCompressionLevel:Int(level:Int)
  626. Return bmx_libarchive_archive_write_set_option(archivePtr, "compression-level", String(level), Null)
  627. End Method
  628. Rem
  629. bbdoc: Sets the compression type for a compatible format/filter.
  630. returns: #ARCHIVE_OK on success, or an error code.
  631. about:
  632. | Type | Notes |
  633. |------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
  634. | 7zip | The value is one of "store", "deflate", "bzip2", "lzma1", "lzma2" or "ppmd" to indicate how the following entries should be compressed.<br>Note that this setting is ignored for directories, symbolic links, and other special entries. |
  635. | zip | The value is either "store" or "deflate" to indicate how the following entries should be compressed.<br>Note that this setting is ignored for directories, symbolic links, and other special entries. |
  636. End Rem
  637. Method SetCompressionType:Int(compressionType:String)
  638. Return bmx_libarchive_archive_write_set_option(archivePtr, "compression", compressionType, Null)
  639. End Method
  640. Rem
  641. bbdoc: Sets the encryption type.
  642. about: Only applies to Zip archives.
  643. End Rem
  644. Method SetEncryption:Int(encryptionType:EArchiveEncryptionType)
  645. Local ty:String
  646. Select encryptionType
  647. Case EArchiveEncryptionType.Zip
  648. ty = "zipcrypt"
  649. Case EArchiveEncryptionType.AES128
  650. ty = "aes128"
  651. Case EArchiveEncryptionType.AES256
  652. ty = "aes256"
  653. End Select
  654. If Not ty Then
  655. Return ARCHIVE_FAILED
  656. End If
  657. Return bmx_libarchive_archive_write_set_option(archivePtr, "encryption", ty, Null)
  658. End Method
  659. Rem
  660. bbdoc: Frees the archive.
  661. End Rem
  662. Method Free() Override
  663. If archivePtr Then
  664. bmx_libarchive_archive_write_free(archivePtr)
  665. archivePtr = Null
  666. End If
  667. End Method
  668. End Type
  669. Rem
  670. bbdoc: Represents entries within an archive.
  671. about: You can think of a #TArchiveEntry as a heavy-duty version of the c struct stat: it includes everything from struct stat plus
  672. associated pathname, textual group and user names, etc. These objects are used by libarchive to represent the metadata associated
  673. with a particular entry in an archive.
  674. End Rem
  675. Type TArchiveEntry
  676. Field entryPtr:Byte Ptr
  677. Function _create:TArchiveEntry(entryPtr:Byte Ptr)
  678. If entryPtr Then
  679. Local this:TArchiveEntry = New TArchiveEntry(entryPtr)
  680. Return this
  681. End If
  682. Return Null
  683. End Function
  684. Rem
  685. bbdoc: Creates a new #TArchiveEntry instance.
  686. End Rem
  687. Method New()
  688. entryPtr = bmx_libarchive_archive_entry_new()
  689. SetFileType(EArchiveFileType.File)
  690. End Method
  691. Rem
  692. bbdoc: Creates a new #TArchiveEntry instance using the specified @entryPtr handle.
  693. End Rem
  694. Method New(entryPtr:Byte Ptr)
  695. Self.entryPtr = entryPtr
  696. End Method
  697. Rem
  698. bbdoc: Returns the entry access time, as an #SDateTime.
  699. End Rem
  700. Method AccessDateTime:SDateTime()
  701. Return SDateTime.FromEpoch(bmx_libarchive_archive_entry_atime(entryPtr), bmx_libarchive_archive_entry_atime_nsec(entryPtr))
  702. End Method
  703. Rem
  704. bbdoc: Returns the entry access time, if set.
  705. End Rem
  706. Method AccessTime:Long()
  707. return bmx_libarchive_archive_entry_atime(entryPtr)
  708. End Method
  709. Rem
  710. bbdoc: Returns the entry access time, in nanoseconds.
  711. End Rem
  712. Method AccessTimeNano:Long()
  713. Return bmx_libarchive_archive_entry_atime_nsec(entryPtr)
  714. End Method
  715. Rem
  716. bbdoc: Returns #True if the access time is set.
  717. End Rem
  718. Method AccessTimeIsSet:Int()
  719. Return bmx_libarchive_archive_entry_atime_is_set(entryPtr)
  720. End Method
  721. Rem
  722. bbdoc: Sets the access time for the entry.
  723. End Rem
  724. Method SetAccessTime(atime:Long, nanoseconds:Long = 0)
  725. bmx_libarchive_archive_entry_set_atime(entryPtr, atime, nanoseconds)
  726. End Method
  727. Rem
  728. bbdoc: Unsets entry access time.
  729. End Rem
  730. Method UnsetAccessTime()
  731. bmx_libarchive_archive_entry_unset_atime(entryPtr)
  732. End Method
  733. Rem
  734. bbdoc: Returns the entry birth time, as an #SDateTime.
  735. End Rem
  736. Method BirthDateTime:SDateTime()
  737. Return SDateTime.FromEpoch(bmx_libarchive_archive_entry_birthtime(entryPtr), bmx_libarchive_archive_entry_birthtime_nsec(entryPtr))
  738. End Method
  739. Rem
  740. bbdoc: Returns the entry birth time, if set.
  741. End Rem
  742. Method BirthTime:Long()
  743. return bmx_libarchive_archive_entry_birthtime(entryPtr)
  744. End Method
  745. Rem
  746. bbdoc: Returns the entry birth time, in nanoseconds.
  747. End Rem
  748. Method BirthTimeNano:Long()
  749. return bmx_libarchive_archive_entry_birthtime_nsec(entryPtr)
  750. End Method
  751. Rem
  752. bbdoc: Returns #True if the birth time is set.
  753. End Rem
  754. Method BirthTimeIsSet:Int()
  755. return bmx_libarchive_archive_entry_birthtime_is_set(entryPtr)
  756. End Method
  757. Rem
  758. bbdoc: Sets the birth time for the entry.
  759. End Rem
  760. Method SetBirthTime(btime:Long, nanoseconds:Long = 0)
  761. bmx_libarchive_archive_entry_set_birthtime(entryPtr, btime, nanoseconds)
  762. End Method
  763. Rem
  764. bbdoc: Unsets the birth time of the entry.
  765. End Rem
  766. Method UnsetBirthTime()
  767. bmx_libarchive_archive_entry_unset_birthtime(entryPtr)
  768. End Method
  769. Rem
  770. bbdoc: Erases the object, resetting all internal fields to the same state as a newly-created object.
  771. about: This is provided to allow you to quickly recycle objects.
  772. End Rem
  773. Method Clear()
  774. entryPtr = bmx_libarchive_archive_entry_clear(entryPtr)
  775. End Method
  776. Rem
  777. bbdoc: A deep copy operation; all text fields are duplicated.
  778. End Rem
  779. Method Clone:TArchiveEntry()
  780. Return TArchiveEntry._create(bmx_libarchive_archive_entry_clone(entryPtr))
  781. End Method
  782. Rem
  783. bbdoc: Returns the entry inode change time, as an #SDateTime.
  784. End Rem
  785. Method CDateTime:SDateTime()
  786. Return SDateTime.FromEpoch(bmx_libarchive_archive_entry_ctime(entryPtr), bmx_libarchive_archive_entry_ctime_nsec(entryPtr))
  787. End Method
  788. Rem
  789. bbdoc: Returns the entry inode change time, if set.
  790. End Rem
  791. Method CTime:Long()
  792. return bmx_libarchive_archive_entry_ctime(entryPtr)
  793. End Method
  794. Rem
  795. bbdoc: Returns the entry inode change time, in nanoseconds.
  796. End Rem
  797. Method CTimeNano:Long()
  798. return bmx_libarchive_archive_entry_ctime_nsec(entryPtr)
  799. End Method
  800. Rem
  801. bbdoc: Returns #True if the inode change time is set.
  802. End Rem
  803. Method CTimeIsSet:Int()
  804. return bmx_libarchive_archive_entry_ctime_is_set(entryPtr)
  805. End Method
  806. Rem
  807. bbdoc: Unsets the inode change time.
  808. End Rem
  809. Method UnsetCTime()
  810. bmx_libarchive_archive_entry_unset_ctime(entryPtr)
  811. End Method
  812. Rem
  813. bbdoc: Returns the entry file type.
  814. End Rem
  815. Method FileType:EArchiveFileType()
  816. Return bmx_libarchive_archive_entry_filetype(entryPtr)
  817. End Method
  818. Rem
  819. bbdoc: Destination of the hardlink.
  820. End Rem
  821. Method Hardlink:String()
  822. Return bmx_libarchive_archive_entry_hardlink(entryPtr)
  823. End Method
  824. Rem
  825. bbdoc: Returns #True if the entry data is encrypted.
  826. End Rem
  827. Method IsDataEncrypted:Int()
  828. Return bmx_libarchive_archive_entry_is_data_encrypted(entryPtr)
  829. End Method
  830. Rem
  831. bbdoc: Returns #True if the entry metadata is encrypted.
  832. End Rem
  833. Method IsMetadataEncrypted:Int()
  834. Return bmx_libarchive_archive_entry_is_metadata_encrypted(entryPtr)
  835. End Method
  836. Rem
  837. bbdoc: Returns #True if the entry is encrypted.
  838. End Rem
  839. Method IsEncrypted:Int()
  840. Return bmx_libarchive_archive_entry_is_encrypted(entryPtr)
  841. End Method
  842. Rem
  843. bbdoc: Path in the archive.
  844. End Rem
  845. Method Pathname:String()
  846. Return bmx_libarchive_archive_entry_pathname(entryPtr)
  847. End Method
  848. Rem
  849. bbdoc: Destination of the symbolic link.
  850. End Rem
  851. Method Symlink:String()
  852. Return bmx_libarchive_archive_entry_symlink(entryPtr)
  853. End Method
  854. Rem
  855. bbdoc: Sets the creation time of the entry.
  856. End Rem
  857. Method SetCreationTime(time:Long, nanoseconds:Long = 0)
  858. bmx_libarchive_archive_entry_set_ctime(entryPtr, time, nanoseconds)
  859. End Method
  860. Rem
  861. bbdoc: Sets the file type of the entry.
  862. End Rem
  863. Method SetFileType(fType:EArchiveFileType)
  864. bmx_libarchive_archive_entry_set_filetype(entryPtr, fType)
  865. End Method
  866. Rem
  867. bbdoc:
  868. End Rem
  869. Method SetHardlink(path:String)
  870. End Method
  871. Rem
  872. bbdoc: For a symlink, update the destination, otherwise, make the entry a hardlink and alter the destination for that.
  873. about: Update only.
  874. End Rem
  875. Method SetLink(path:String)
  876. bmx_libarchive_archive_entry_set_link(entryPtr, path)
  877. End Method
  878. Rem
  879. bbdoc: Returns the entry modified time, as an #SDateTime.
  880. End Rem
  881. Method ModifiedDateTime:SDateTime()
  882. Return SDateTime.FromEpoch(bmx_libarchive_archive_entry_mtime(entryPtr), bmx_libarchive_archive_entry_mtime_nsec(entryPtr))
  883. End Method
  884. Rem
  885. bbdoc: Sets the modified time of the entry.
  886. End Rem
  887. Method SetModifiedTime(time:Long, nanoseconds:Long = 0)
  888. bmx_libarchive_archive_entry_set_mtime(entryPtr, time, nanoseconds)
  889. End Method
  890. Rem
  891. bbdoc: Returns the entry modified time, if set.
  892. End Rem
  893. Method ModifiedTime:Long()
  894. return bmx_libarchive_archive_entry_mtime(entryPtr)
  895. End Method
  896. Rem
  897. bbdoc: Returns the entry modified time, in nanoseconds.
  898. End Rem
  899. Method ModifiedTimeNano:Long()
  900. return bmx_libarchive_archive_entry_mtime_nsec(entryPtr)
  901. End Method
  902. Rem
  903. bbdoc: Returns #True if the modified time is set.
  904. End Rem
  905. Method ModifiedTimeIsSet:Int()
  906. return bmx_libarchive_archive_entry_mtime_is_set(entryPtr)
  907. End Method
  908. Rem
  909. bbdoc: Unsets the modified time.
  910. End Rem
  911. Method UnsetModifiedTime()
  912. bmx_libarchive_archive_entry_unset_mtime(entryPtr)
  913. End Method
  914. Rem
  915. bbdoc: Sets the pathname of the entry.
  916. End Rem
  917. Method SetPathname(path:String)
  918. bmx_libarchive_archive_entry_set_pathname(entryPtr, path)
  919. End Method
  920. Rem
  921. bbdoc: Sets the permission of the entry.
  922. End Rem
  923. Method SetPermission(perm:Int)
  924. bmx_libarchive_archive_entry_set_perm(entryPtr, perm)
  925. End Method
  926. Rem
  927. bbdoc: Sets the size, in bytes, of the entry.
  928. End Rem
  929. Method SetSize(size:Long)
  930. bmx_libarchive_archive_entry_set_size(entryPtr, size)
  931. End Method
  932. Rem
  933. bbdoc:
  934. End Rem
  935. Method SetSymlink(path:String)
  936. bmx_libarchive_archive_entry_set_symlink(entryPtr, path)
  937. End Method
  938. Rem
  939. bbdoc: Returns true if the size is set.
  940. End Rem
  941. Method SizeIsSet:Int()
  942. Return bmx_libarchive_archive_entry_size_is_set(entryPtr)
  943. End Method
  944. Rem
  945. bbdoc: Returns the uncompressed size, in bytes, of the entry, if available.
  946. End Rem
  947. Method Size:Long()
  948. Return bmx_libarchive_archive_entry_size(entryPtr)
  949. End Method
  950. Rem
  951. bbdoc: Unsets the size of the entry.
  952. End Rem
  953. Method UnsetSize()
  954. bmx_libarchive_archive_entry_unset_size(entryPtr)
  955. End Method
  956. Rem
  957. bbdoc: Releases the archive entry object.
  958. End Rem
  959. Method Free()
  960. If entryPtr Then
  961. bmx_libarchive_archive_entry_free(entryPtr)
  962. entryPtr = Null
  963. End If
  964. End Method
  965. Method Delete()
  966. Free()
  967. End Method
  968. End Type
  969. Private
  970. Global _archive_formats:TArchiveFormat
  971. Function ArchiveSetReadFormat(archive:Byte Ptr, format:EArchiveFormat)
  972. Local af:TArchiveFormat=_archive_formats
  973. While af
  974. If af.AddReadFormat(archive, format) Then
  975. Return
  976. End If
  977. af=af._succ
  978. Wend
  979. Throw New TArchiveException("Read format not found. Ensure the module has been imported : " + format.ToString())
  980. End Function
  981. Function ArchiveSetWriteFormat(archive:Byte Ptr, format:EArchiveFormat)
  982. Local af:TArchiveFormat=_archive_formats
  983. While af
  984. If af.AddWriteFormat(archive, format) Then
  985. Return
  986. End If
  987. af=af._succ
  988. Wend
  989. Throw New TArchiveException("Write format not found. Ensure the module has been imported : " + format.ToString())
  990. End Function
  991. Function ArchiveAddReadFilter(archive:Byte Ptr, filter:EArchiveFilter)
  992. Local af:TArchiveFormat=_archive_formats
  993. While af
  994. If af.AddReadFilter(archive, filter) Then
  995. Return
  996. End If
  997. af=af._succ
  998. Wend
  999. Throw New TArchiveException("Read filter not found. Ensure the module has been imported : " + filter.ToString())
  1000. End Function
  1001. Function ArchiveAddWriteFilter(archive:Byte Ptr, filter:EArchiveFilter)
  1002. Local af:TArchiveFormat=_archive_formats
  1003. While af
  1004. If af.AddWriteFilter(archive, filter) Then
  1005. Return
  1006. End If
  1007. af=af._succ
  1008. Wend
  1009. Throw New TArchiveException("Write filter not found. Ensure the module has been imported : " + filter.ToString())
  1010. End Function
  1011. Public
  1012. Type TArchiveFormat
  1013. Field _succ:TArchiveFormat
  1014. Method New()
  1015. _succ=_archive_formats
  1016. _archive_formats=Self
  1017. End Method
  1018. Method AddReadFormat:Int(archive:Byte Ptr, format:EArchiveFormat) Abstract
  1019. Method AddWriteFormat:Int(archive:Byte Ptr, format:EArchiveFormat) Abstract
  1020. Method AddReadFilter:Int(archive:Byte Ptr, filter:EArchiveFilter) Abstract
  1021. Method AddWriteFilter:Int(archive:Byte Ptr, filter:EArchiveFilter) Abstract
  1022. End Type
  1023. Type TArchiveException Extends TRuntimeException
  1024. End Type