-
Notifications
You must be signed in to change notification settings - Fork 1
/
ArcvProcessExtract.hs
354 lines (317 loc) · 19.4 KB
/
ArcvProcessExtract.hs
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
{-# OPTIONS_GHC -cpp #-}
----------------------------------------------------------------------------------------------------
---- Ïðîöåññ ðàñïàêîâêè âõîäíûõ àðõèâîâ. ----
---- Âûçûâàåòñÿ èç ArcExtract.hs è ArcCreate.hs (ïðè îáíîâëåíèè è ñëèÿíèè àðõèâîâ). ----
----------------------------------------------------------------------------------------------------
module ArcvProcessExtract where
import Prelude hiding (catch)
import Control.OldException
import Control.Monad
import Data.Int
import Data.IORef
import Data.Maybe
import Foreign.C.Types
import Foreign.Ptr
import Foreign.Marshal.Utils
import Foreign.Storable
#ifdef FREEARC_CELS
import TABI
#endif
import Utils
import Errors
import Process
import FileInfo
import CompressionLib
import Compression
import Encryption
import Options
import UI
import ArhiveStructure
import Arhive7zLib
{-# NOINLINE decompress_file #-}
-- |Ðàñïàêîâêà ôàéëà èç àðõèâà ñ èñïîëüçîâàíèåì ïåðåäàííîãî ïðîöåññà äåêîìïðåññîðà
-- è çàïèñüþ ðàñïàêîâàííûõ äàííûõ ñ ïîìîùüþ ôóíêöèè `writer`
decompress_file decompress_pipe compressed_file writer = do
-- Íå ïûòàòüñÿ ðàñïàêîâàòü êàòàëîãè/ïóñòûå ôàéëû è ôàéëû áåç äàííûõ, ïîñêîëüêó îæèäàòü ïîëó÷åíèå 0 áàéòîâ - âîèñòèíó äçåíñêîå çàíÿòèå ;)
when (fiSize(cfFileInfo compressed_file) > 0 && not (isCompressedFake compressed_file)) $ do
sendP decompress_pipe (Just compressed_file)
repeat_while (receiveP decompress_pipe) ((>=0).snd) (uncurry writer .>> send_backP decompress_pipe ()) -- çàïèøåì äàííûå è ñîîáùèì ðàñïàêîâùèêó, ÷òî òåïåðü áóôåð ñâîáîäåí
failOnTerminated
return (cfCRC compressed_file)
{-# NOINLINE decompress_PROCESS #-}
-- |Ïðîöåññ, ðàñïàêîâûâàþùèé ôàéëû èç àðõèâîâ
decompress_PROCESS command count_cbytes pipe = do
cmd <- receiveP pipe
case cmd of
Nothing -> return ()
Just cfile' -> do
cfile <- ref cfile'
state <- ref (error "Decompression state is not initialized!")
repeat_until $ do
decompress_block command cfile state count_cbytes pipe
operationTerminated' <- val operationTerminated
when operationTerminated' $ do
sendP pipe (error "Decompression terminated", aFREEARC_ERRCODE_OPERATION_TERMINATED)
(x,_,_) <- val state
return (x == aSTOP_DECOMPRESS_THREAD || operationTerminated')
{-# NOINLINE decompress_block #-}
-- |Ðàñïàêîâàòü îäèí ñîëèä-áëîê
decompress_block command cfile state count_cbytes pipe = do
; cfile' <- val cfile
let size = fiSize (cfFileInfo cfile')
pos = cfPos cfile'
block = cfArcBlock cfile'
; compressor <- block.$ blCompressor.$ limit_decompression command -- âñòàâèì âûçîâû tempfile åñëè íóæíî
let startPos | compressor==aNO_COMPRESSION = pos -- äëÿ -m0 íà÷èíàåì ÷òåíèå íàïðÿìóþ ñ íóæíîé ïîçèöèè â áëîêå
| otherwise = 0
state =: (startPos, pos, size)
archiveBlockSeek block startPos
bytesLeft <- ref (blCompSize block - startPos)
let reader buf size = do aBytesLeft <- val bytesLeft
let bytes = minI (size::Int) aBytesLeft
len <- archiveBlockReadBuf block buf bytes
bytesLeft -= i len
count_cbytes len
return len
let writer (DataBuf buf len) = decompress_step cfile state pipe buf len
writer NoMoreData = return 0
-- Óìåíüøàåò ÷èñëî òðåäîâ ðàñïàêîâêè (èëè èíà÷å ìîäèôèöèðóåò àëãîðèòì, íå òåðÿÿ ñîâìåñòèìîñòè ñ óïàêîâàííûìè èì äàííûìè),
-- åñëè â ìîìåíò ñòàðòà àëãîðèòìà ðàñïàêîâêè äëÿ íåãî íå õâàòàåò ïàìÿòè
let limit_memory num method = limit_decompression command method
-- Äîáàâèòü êëþ÷ â çàïèñü àëãîðèòìà äåøèôðîâàíèÿ
keyed_compressor <- generateDecryption compressor (opt_decryption_info command)
when (any isNothing keyed_compressor) $ do
registerError$ BAD_PASSWORD (cmd_arcname command) (cfile'.$cfFileInfo.$storedName)
times <- uiStartDeCompression "decompression" -- ñîçäàòü ñòðóêòóðó äëÿ ó÷¸òà âðåìåíè ðàñïàêîâêè
-- Ïðåâðàòèì ñïèñîê ìåòîäîâ ñæàòèÿ/øèôðîâàíèÿ â êîíâåéåð ïðîöåññîâ ðàñïàêîâêè
let decompress1 = de_compress_PROCESS1 freearcDecompress reader times command limit_memory -- ïåðâûé ïðîöåññ â êîíâåéåðå
decompressN = de_compress_PROCESS freearcDecompress times command limit_memory -- ïîñëåäóþùèå ïðîöåññû â êîíâåéåðå
decompressa [p] = decompress1 p 0
decompressa [p1,p2] = decompress1 p2 0 |> decompressN p1 0
decompressa (p1:ps) = decompress1 (last ps) 0 |> foldl1 (|>) (map (\x->decompressN x 0) (reverse$ init ps)) |> decompressN p1 0
-- È íàêîíåö ïðîöåäóðà ðàñïàêîâêè
; result <- ref 0 -- êîëè÷åñòâî áàéò, çàïèñàííûõ â ïîñëåäíåì âûçîâå writer
; runFuncP (decompressa (map fromJust keyed_compressor)) (fail "decompress_block::runFuncP") (doNothing) (writer .>>= writeIORef result) (val result)
uiFinishDeCompression times -- ó÷åñòü â UI ÷èñòîå âðåìÿ îïåðàöèè
{-# NOINLINE de_compress_PROCESS #-}
-- |Âñïîìîãàòåëüíûé ïðîöåññ ïåðåêëàäûâàíèÿ äàííûõ èç áóôåðîâ âõîäíîãî ïîòîêà
-- âî âõîäíûå áóôåðà ïðîöåäóðû óïàêîâêè/ðàñïàêîâêè
-- comprMethod - ñòðîêà ìåòîäà ñæàòèÿ ñ ïàðàìåòðàìè, òèïà "ppmd:o10:m48m"
-- num - íîìåð ïðîöåññà â öåïî÷êå ïðîöåññîâ óïàêîâêè (0 äëÿ ïðîöåññîâ ðàñïàêîâêè)
de_compress_PROCESS de_compress times command limit_memory comprMethod num pipe = do
-- Èíôîðìàöèÿ îá îñòàòêå äàííûõ, ïîëó÷åííûõ èç ïðåäûäóùåãî ïðîöåññà, íî åù¸ íå îòïðàâëåííûõ íà óïàêîâêó/ðàñïàêîâêó
remains <- ref$ Just (error "undefined remains:buf0", error "undefined remains:srcbuf", 0)
let no_progress = not$ comprMethod.$compressionIs "has_progress?"
let
-- Ïðîöåäóðà "÷òåíèÿ" âõîäíûõ äàííûõ. Âàæíî, ÷òîáû ïåðâûé âûçîâ ñ dstlen=0 íå âîçâðàùàë óïðàâëåíèå ïîêà íå ïîñòóïèò õîòÿ áû îäèí áàéò äàííûõ îò ïðåäûäóùåãî ïðîöåññà
read_data prevlen -- ñêîëüêî äàííûõ óæå ïðî÷èòàíî
dstbuf -- áóôåð, êóäà íóæíî ïîìåñòèòü âõîäíûå äàííûå
dstlen -- ðàçìåð áóôåðà
= do -- -> ïðîöåäóðà äîëæíà âîçâðàòèòü êîëè÷åñòâî ïðî÷èòàííûõ áàéò èëè 0, åñëè äàííûå çàêîí÷èëèñü
remains' <- val remains
case remains' of
Just (buf0, srcbuf, srclen) -- Åñëè åù¸ åñòü äàííûå, ïîëó÷åííûå èç ïðåäûäóùåãî ïðîöåññà
| srclen>0 -> copyData buf0 srcbuf srclen -- òî ïåðåäàòü èõ óïàêîâùèêó/ðàñïàêîâùèêó
| otherwise -> processNextInstruction -- èíà÷å ïîëó÷èòü íîâûå
Nothing -> return prevlen -- Ýòîò solid-áëîê çàêîí÷èëñÿ, äàííûõ áîëüøå íåò
where
-- Ñêîïèðîâàòü äàííûå èç srcbuf â dstbuf è âîçâðàòèòü ðàçìåð ñêîïèðîâàííûõ äàííûõ
copyData buf0 srcbuf srclen = do
let len = srclen `min` dstlen -- îïðåäåëèòü - ñêîëüêî äàííûõ ìû ìîæåì ïðî÷èòàòü
copyBytes dstbuf srcbuf len
no_progress &&& uiReadData num (i len) -- îáíîâèòü èíäèêàòîð ïðîãðåññà
remains =: Just (buf0, srcbuf+:len, srclen-len)
case () of
_ | len==srclen -> do send_backP pipe (srcbuf-:buf0+srclen) -- âîçâðàòèòü ðàçìåð áóôåðà, ïîñêîëüêó âñå äàííûå èç íåãî óæå ïåðåäàíû óïàêîâùèêó/ðàñïàêîâùèêó
read_data (prevlen+len) (dstbuf+:len) (dstlen-len) -- ïðî÷èòàòü ñëåäóþùóþ èíñòðóêöèþ
| len==dstlen -> return (prevlen+len) -- áóôåð äîñòàòî÷íî çàïîëíåí
| otherwise -> read_data (prevlen+len) (dstbuf+:len) (dstlen-len) -- çàïîëíèì îñòàòîê áóôåðà ñîäåðæèìûì ñëåäóþùèõ ôàéëîâ
-- Ïîëó÷èòü ñëåäóþùóþ èíñòðóêöèþ èç ïîòîêà âõîäíûõ äàííûõ è îòðàáîòàòü å¸
processNextInstruction = do
instr <- receiveP pipe
case instr of
DataBuf srcbuf srclen -> copyData srcbuf srcbuf srclen
NoMoreData -> do remains =: Nothing; return prevlen
-- Ïðîöåäóðà ÷òåíèÿ âõîäíûõ äàííûõ ïðîöåññà óïàêîâêè/ðàñïàêîâêè (âûçûâàåòñÿ ëèøü îäíàæäû, â îòëè÷èå îò ðåêóðñèâíîé read_data)
let reader = read_data 0
de_compress_PROCESS1 de_compress reader times command limit_memory comprMethod num pipe
{-# NOINLINE de_compress_PROCESS1 #-}
-- |de_compress_PROCESS ñ ïàðàìåòðèçóåìîé ôóíêöèåé ÷òåíèÿ (ìîæåò ÷èòàòü äàííûå íàïðÿìóþ
-- èç àðõèâà äëÿ ïåðâîãî ïðîöåññà â öåïî÷êå ðàñïàêîâêè)
de_compress_PROCESS1 de_compress reader times command limit_memory comprMethod num pipe = do
total' <- ref ( 0 :: FileSize)
time' <- ref (-1 :: Double)
let no_progress = not$ comprMethod.$compressionIs "has_progress?"
let -- Íàïå÷àòàòü êàðòó ïàìÿòè
showMemoryMap = do printLine$ "\nBefore "++show num++": "++comprMethod++"\n"
testMalloc
#ifdef FREEARC_CELS
let callback p = do
TABI.dump p
service <- TABI.required p "request"
case service of
-- Ïðîöåäóðà ÷òåíèÿ âõîäíûõ äàííûõ ïðîöåññà óïàêîâêè/ðàñïàêîâêè
"read" -> do buf <- TABI.required p "buf"
size <- TABI.required p "size"
reader buf size
-- Ïðîöåäóðà çàïèñè âûõîäíûõ äàííûõ
"write" -> do buf <- TABI.required p "buf"
size <- TABI.required p "size"
total' += i size
no_progress &&& uiWriteData num (i size)
resend_data pipe (DataBuf buf size)
-- "Êâàçèçàïèñü" ïðîñòî ñèãíàëèçèðóåò ñêîëüêî äàííûõ áóäåò çàïèñàíî â ðåçóëüòàòå ñæàòèÿ
"quasiwrite" -> do bytes <- TABI.required p "bytes"
uiQuasiWriteData num bytes
return aFREEARC_OK
-- Èíôîðìèðóåì ïîëüçîâàòåëÿ î õîäå ðàñïàêîâêè
"progress" -> do insize <- peekElemOff (castPtr ptr::Ptr Int64) 0 >>==i
outsize <- peekElemOff (castPtr ptr::Ptr Int64) 1 >>==i
uiReadData num insize
uiWriteData num outsize
return aFREEARC_OK
-- Èíôîðìàöèÿ î ÷èñòîì âðåìåíè âûïîëíåíèÿ óïàêîâêè/ðàñïàêîâêè
"time" -> do time <- TABI.required p "time"
time' =: time
return aFREEARC_OK
-- Ïðî÷èå (íåïîääåðæèâàåìûå) callbacks
_ -> return aFREEARC_ERRCODE_NOT_IMPLEMENTED
let -- Ïîñêîëüêó Haskell'îâñêèé êîä, âûçûâàåìûé èç Ñè, íå ìîæåò ïîëó÷àòü èñêëþ÷åíèé, äîáàâèì ê ïðîöåäóðàì ÷òåíèÿ/çàïèñè ÿâíûå ïðîâåðêè
checked_callback p = do
operationTerminated' <- val operationTerminated
if operationTerminated'
then return CompressionLib.aFREEARC_ERRCODE_OPERATION_TERMINATED -- foreverM doNothing0
else callback p
-- Non-debugging wrapper
debug f = f
debug_checked_callback what buf size = TABI.call (\a->fromIntegral `fmap` checked_callback a) [Pair "request" what, Pair "buf" buf, Pair "size" size]
#else
let -- Ïðîöåäóðà ÷òåíèÿ âõîäíûõ äàííûõ ïðîöåññà óïàêîâêè/ðàñïàêîâêè
callback "read" buf size = do res <- reader buf size
return res
-- Ïðîöåäóðà çàïèñè âûõîäíûõ äàííûõ
callback "write" buf size = do total' += i size
no_progress &&& uiWriteData num (i size)
resend_data pipe (DataBuf buf size)
-- "Êâàçèçàïèñü" ïðîñòî ñèãíàëèçèðóåò ñêîëüêî äàííûõ áóäåò çàïèñàíî â ðåçóëüòàòå ñæàòèÿ
-- óæå ïðî÷èòàííûõ äàííûõ. Çíà÷åíèå ïåðåäà¸òñÿ ÷åðåç int64* ptr
callback "quasiwrite" ptr _ = do bytes <- peek (castPtr ptr::Ptr Int64) >>==i
uiQuasiWriteData num bytes
return aFREEARC_OK
-- Èíôîðìèðóåì ïîëüçîâàòåëÿ î õîäå ðàñïàêîâêè
callback "progress" ptr _ = do insize <- peekElemOff (castPtr ptr::Ptr Int64) 0 >>==i
outsize <- peekElemOff (castPtr ptr::Ptr Int64) 1 >>==i
uiReadData num insize
uiWriteData num outsize
return aFREEARC_OK
-- Èíôîðìàöèÿ î ÷èñòîì âðåìåíè âûïîëíåíèÿ óïàêîâêè/ðàñïàêîâêè
callback "time" ptr 0 = do t <- peek (castPtr ptr::Ptr CDouble) >>==realToFrac
time' =: t
return aFREEARC_OK
-- Ïðî÷èå (íåïîääåðæèâàåìûå) callbacks
callback _ _ _ = return aFREEARC_ERRCODE_NOT_IMPLEMENTED
let -- Ïîñêîëüêó Haskell'îâñêèé êîä, âûçûâàåìûé èç Ñè, íå ìîæåò ïîëó÷àòü èñêëþ÷åíèé, äîáàâèì ê ïðîöåäóðàì ÷òåíèÿ/çàïèñè ÿâíûå ïðîâåðêè
checked_callback what buf size = do
operationTerminated' <- val operationTerminated
if operationTerminated'
then return CompressionLib.aFREEARC_ERRCODE_OPERATION_TERMINATED -- foreverM doNothing0
else callback what buf size
{-
-- Debugging wrapper
debug f what buf size = inside (print (comprMethod,what,size))
(print (comprMethod,what,size,"done"))
(f what buf size)
-}
-- Non-debugging wrapper
debug f what buf size = f what buf size
debug_checked_callback = debug checked_callback
#endif
-- ÑÎÁÑÒÂÅÍÍÎ ÓÏÀÊÎÂÊÀ ÈËÈ ÐÀÑÏÀÊÎÂÊÀ
res <- debug_checked_callback "read" nullPtr (0::Int) -- ýòîò âûçîâ ïîçâîëÿåò îòëîæèòü çàïóñê ñëåäóþùåãî â öåïî÷êå àëãîðèòìà óïàêîâêè/ðàñïàêîâêè äî ìîìåíòà, êîãäà ïðåäûäóùèé âîçâðàòèò õîòü êàêèå-íèáóäü äàííûå (à åñëè ýòî ïîáëî÷íûé àëãîðèòì - äî ìîìåíòà, êîãäà îí îáðàáîòàåò âåñü áëîê)
opt_testMalloc command &&& showMemoryMap -- íàïå÷àòàåì êàðòó ïàìÿòè íåïîñðåäñòâåííî ïåðåä íà÷àëîì ñæàòèÿ
real_method <- limit_memory num comprMethod -- îáðåæåì ìåòîä ñæàòèÿ ïðè íåõâàòêå ïàìÿòè
result <- if res<0 then return res
else wrapCompressionThreadPriority$ de_compress num real_method debug_checked_callback
debug_checked_callback "finished" nullPtr result
-- Ñòàòèñòèêà
total <- val total'
time <- val time'
uiDeCompressionTime times (real_method,time,total)
-- Âûéäåì ñ ñîîáùåíèåì, åñëè ïðîèçîøëà îøèáêà
unlessM (val operationTerminated) $ do
when (result `notElem` [aFREEARC_OK, aFREEARC_ERRCODE_NO_MORE_DATA_REQUIRED]) $ do
registerThreadError$ COMPRESSION_ERROR [compressionErrorMessage result, real_method]
operationTerminated =: True
-- Ñîîáùèì ïðåäûäóùåìó ïðîöåññó, ÷òî äàííûå áîëüøå íå íóæíû, à ñëåäóþùåìó - ÷òî äàííûõ áîëüøå íåò
send_backP pipe aFREEARC_ERRCODE_NO_MORE_DATA_REQUIRED
resend_data pipe NoMoreData
return ()
-- |Îáðàáîòêà î÷åðåäíîé ïîðöèè ðàñïàêîâàííûõ äàííûõ (writer äëÿ ðàñïàêîâùèêà).
-- Ñîñòîÿíèå (õðàíèìîå ïî ññûëêå state) ñîäåðæèò:
-- 1) block_pos - òåêóùóþ ïîçèöèþ â áëîêå äàííûõ
-- 2) pos - ïîçèöèþ, ñ êîòîðîé íà÷èíàåòñÿ ôàéë (èëè åãî îñòàâøàÿñÿ ÷àñòü)
-- 3) size - ðàçìåð ôàéëà (èëè åãî îñòàâøåéñÿ ÷àñòè)
-- Ñîîòâåòñòâåííî, ïîëó÷èâ îò ðàñïàêîâùèêà äàííûå ïî àäðåñó buf äëèíîé len, ìû äîëæíû:
-- 1) ïðîïóñòèòü â íà÷àëå áóôåðà äàííûå, ïðåäøåñòâóþùèå ðàñïàêîâûâàåìîìó ôàéëó (åñëè åñòü)
-- 2) ïåðåäàòü íà âûõîä äàííûå, îòíîñÿùèåñÿ ê ýòîìó ôàéëó (åñëè åñòü)
-- 3) îáíîâèòü ñîñòîÿíèå - ïîçèöèÿ â áëîêå èçìåíèëàñü íà ðàçìåð ïîëó÷åííîãî áóôåðà,
-- à ïîçèöèÿ è ðàçìåð îñòàâøèõñÿ äàííûõ ôàéëà - íà ðàçìåð ïåðåäàííûõ íà âûõîä äàííûõ
-- 4) åñëè ôàéë ðàñïàêîâàí ïîëíîñòüþ - íàäî èçâåñòèòü îá ýòîì ïðèíèìàþùóþ ñòîðîíó
-- è ïîëó÷èòü ñëåäóþùóþ êîìàíäó íà ðàñïàêîâêó
-- 5) åñëè ñëåäóþùèé ðàñïàêîâûâàåìûé ôàéë îêàçàëñÿ â äðóãîì áëîêå èëè â óæå ïðîøåäøåé ÷àñòè
-- òåêóùåãî áëîêà - íàäî ïðåðâàòü ðàñïàêîâêó ýòîãî áëîêà ñ òåì, ÷òîáû decompress_block
-- ïåðåø¸ë ê ðàñïàêîâêå òîãî, ÷òî íóæíî (îí ÷èòàåò ýòè äàííûå èç cfile)
--
decompress_step cfile state pipe buf len = do
(block_pos, pos, size) <- val state
if block_pos<0 -- ïîõîæå, ÷òî ðàñïàêîâùèê íå îáðàòèë âíèìàíèå, ÷òî ìû õîòèì ïåðåéòè ê äðóãîìó áëîêó äàííûõ
then return aFREEARC_ERRCODE_NO_MORE_DATA_REQUIRED -- íè÷åãî, ïîòåðïèì, ïîêà îí îáðàçóìèòñÿ. àëüòåðíàòèâà: fail$ "Block isn't changed!!!"
else do
let skip_bytes = min (pos-block_pos) (i len) -- ïðîïóñòèòü äàííûå ïðåäûäóùèõ ôàéëîâ â íà÷àëå áóôåðà
data_start = buf +: skip_bytes -- íà÷àëî äàííûõ, ïðèíàäëåæàùèõ ðàñïàêîâûâàåìîìó ôàéëó
data_size = min size (i len-skip_bytes) -- êîë-âî áàéò, ïðèíàäëåæàùèõ ðàñïàêîâûâàåìîìó ôàéëó
block_end = block_pos+i len -- ïîçèöèÿ â ñîëèä-áëîêå, ñîîòâåòñòâóþùàÿ êîíöó ïîëó÷åííîãî áóôåðà
when (data_size>0) $ do -- åñëè â áóôåðå íàøëèñü äàííûå, ïðèíàäëåæàùèå ðàñïàêîâûâàåìîìó ôàéëó
sendP pipe (data_start, i data_size) -- òî âûñëàòü ýòè äàííûå ïî êàíàëó ñâÿçè ïîòðåáèòåëþ
receive_backP pipe -- ïîëó÷èòü ïîäòâåðæäåíèå òîãî, ÷òî äàííûå áûëè èñïîëüçîâàíû
state =: (block_end, pos+data_size, size-data_size)
if data_size<size -- åñëè ôàéë åù¸ íå ðàñïàêîâàí ïîëíîñòüþ
then return len -- òî ïðîäîëæàåì ðàñïàêîâêó áëîêà
else do -- èíà÷å ïåðåõîäèì ê ñëåäóþùåìó çàäàíèþ íà ðàñïàêîâêó
sendP pipe (error "End of decompressed data", aFREEARC_ERRCODE_NO_MORE_DATA_REQUIRED)
old_block <- cfArcBlock ==<< val cfile
cmd <- receiveP pipe
case cmd of
Nothing -> do -- Ýòî ñîîáùåíèå îçíà÷àåò, ÷òî áîëüøå íèêàêèõ ôàéëîâ îò òðåäà ðàñïàêîâêè íå òðåáóåòñÿ è îí äîëæåí áûòü çàâåðø¸í
state =: (aSTOP_DECOMPRESS_THREAD, error "undefined state.pos", error "undefined state.size")
cfile =: error "undefined cfile"
return aFREEARC_ERRCODE_NO_MORE_DATA_REQUIRED
Just cfile' -> do
cfile =: cfile'
let size = fiSize (cfFileInfo cfile')
pos = cfPos cfile'
block = cfArcBlock cfile'
if block/=old_block || pos<block_pos -- åñëè íîâûé ôàéë íàõîäèòñÿ â äðóãîì áëîêå èëè â ýòîì, íî ðàíüøå
|| (pos>block_end && blCompressor block==aNO_COMPRESSION) -- èëè ìû ðàñïàêîâûâàåì áëîê, ñæàòûé ñ -m0, è ó íàñ åñòü âîçìîæíîñòü ïðîïóñòèòü ÷àñòü ôàéëîâ
then do state =: (-1, error "undefined state.pos", error "undefined state.size")
return aFREEARC_ERRCODE_NO_MORE_DATA_REQUIRED -- ïðèçíàê òîãî, ÷òî íóæíî çàâåðøèòü ðàñïàêîâêó ýòîãî áëîêà
else do state =: (block_pos, pos, size) -- ñíîâà ðàññìîòðèì ïåðåäàííûé áóôåð,
decompress_step cfile state pipe buf len -- óæå â êîíòåêñòå ðàñïàêîâêè íîâîãî ôàéëà
-- |Ñèãíàë, òðåáóþùèé çàâåðøåíèÿ ðàáîòû òðåäà ðàñïàêîâêè
aSTOP_DECOMPRESS_THREAD = -99
-- |Ñòðóêòóðà, èñïîëüçóåìàÿ äëÿ ïåðåäà÷è äàííûõ ñëåäóþùåìó ïðîöåññó óïàêîâêè/ðàñïàêîâêè
data CompressionData = DataBuf (Ptr CChar) Int
| NoMoreData
{-# NOINLINE resend_data #-}
-- |Ïðîöåäóðà ïåðåäà÷è âûõîäíûõ äàííûõ óïàêîâùèêà/ðàñïàêîâùèêà ñëåäóþùåé ïðîöåäóðå â öåïî÷êå
resend_data pipe x@DataBuf{} = sendP pipe x >> receive_backP pipe -- âîçâðàòèòü êîëè÷åñòâî ïîòðåáë¸ííûõ áàéò, âîçâðàùàåìîå èç ïðîöåññà-ïîòðåáèòåëÿ
resend_data pipe x@NoMoreData = sendP pipe x >> return 0
----------------------------------------------------------------------------------------------------
----- External functions ---------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------
-- |Lower thread priority for the time it performs compression algorithm
wrapCompressionThreadPriority = bracket beginCompressionThreadPriority endCompressionThreadPriority . const
foreign import ccall unsafe "BeginCompressionThreadPriority"
beginCompressionThreadPriority :: IO Int
foreign import ccall unsafe "EndCompressionThreadPriority"
endCompressionThreadPriority :: Int -> IO ()