xar unarchiver (.xar, .pkg, .xip)
1# memory map crystal IO to C interop FILE*
2
3@[Link("c")]
4lib LibC
5 alias FILE = Void
6
7 {% if flag?(:darwin) %}
8 fun funopen(
9 cookie : Void*,
10 readfn : (Void*, UInt8*, LibC::SizeT) -> LibC::SizeT,
11 writefn : Void*,
12 seekfn : (Void*, LibC::OffT, Int32) -> LibC::OffT,
13 closefn : (Void*) -> Int32
14 ) : FILE*
15 {% else %}
16 fun fopencookie(
17 cookie : Void*,
18 mode : LibC::Char*,
19 ops : CookieIO
20 ) : FILE*
21
22 struct CookieIO
23 read : (Void*, UInt8*, LibC::SizeT) -> LibC::SizeT
24 write : Void*
25 seek : (Void*, LibC::OffT, Int32) -> LibC::OffT
26 close : (Void*) -> Int32
27 end
28 {% end %}
29end
30
31module MemFile
32 class IOCookie
33 getter io : IO
34
35 def initialize(@io : IO)
36 end
37 end
38
39 def self.from_io(io : IO) : Pointer(LibC::FILE)
40 cookie = Box.box(IOCookie.new(io))
41
42 read_cb = ->(cookie_ptr : Void*, buf : UInt8*, size : LibC::SizeT) : LibC::SizeT {
43 wrapper = Box(IOCookie).unbox(cookie_ptr)
44 begin
45 bytes_read = wrapper.io.read(Slice.new(buf, size))
46 bytes_read.to_u64
47 rescue
48 0.to_u64
49 end
50 }
51
52 seek_cb = ->(cookie_ptr : Void*, offset : LibC::OffT, whence : Int32) : LibC::OffT {
53 wrapper = Box(IOCookie).unbox(cookie_ptr)
54 begin
55 wrapper.io.seek(offset, IO::Seek.new(whence))
56 wrapper.io.pos.to_i64
57 rescue
58 -1.to_i64
59 end
60 }
61
62 close_cb = ->(cookie_ptr : Void*) : Int32 {
63 Box(IOCookie).unbox(cookie_ptr) # let GC handle it
64 0
65 }
66
67 {% if flag?(:darwin) %}
68 LibC.funopen(
69 cookie.as(Void*),
70 read_cb,
71 Pointer(Void).null,
72 seek_cb,
73 close_cb
74 )
75 {% else %}
76 ops = LibC::CookieIO.new(
77 read: read_cb,
78 write: Pointer(Void).null,
79 seek: seek_cb,
80 close: close_cb
81 )
82 LibC.fopencookie(cookie.as(Void*), "r".to_unsafe, ops)
83 {% end %}
84 end
85end