2 * GRUB -- GRand Unified Bootloader
3 * Copyright (c) 1999-2008 Igor Pavlov
4 * Copyright (C) 2008 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21 * This code was taken from LZMA SDK 4.58 beta, and was slightly modified
22 * to adapt it to GRUB's requirement.
24 * See <http://www.7-zip.org>, for more information about LZMA.
29 #include <grub/lib/LzFind.h>
30 #include <grub/lib/LzHash.h>
32 #define kEmptyHashValue 0
33 #define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
34 #define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
35 #define kNormalizeMask (~(kNormalizeStepMin - 1))
36 #define kMaxHistorySize ((UInt32)3 << 30)
38 #define kStartMaxLen 3
40 static void LzInWindow_Free(CMatchFinder
*p
, ISzAlloc
*alloc
)
44 alloc
->Free(alloc
, p
->bufferBase
);
49 /* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
51 static int LzInWindow_Create(CMatchFinder
*p
, UInt32 keepSizeReserv
, ISzAlloc
*alloc
)
53 UInt32 blockSize
= p
->keepSizeBefore
+ p
->keepSizeAfter
+ keepSizeReserv
;
56 p
->blockSize
= blockSize
;
59 if (p
->bufferBase
== 0 || p
->blockSize
!= blockSize
)
61 LzInWindow_Free(p
, alloc
);
62 p
->blockSize
= blockSize
;
63 p
->bufferBase
= (Byte
*)alloc
->Alloc(alloc
, (size_t)blockSize
);
65 return (p
->bufferBase
!= 0);
68 Byte
*MatchFinder_GetPointerToCurrentPos(CMatchFinder
*p
) { return p
->buffer
; }
69 Byte
MatchFinder_GetIndexByte(CMatchFinder
*p
, Int32 index
) { return p
->buffer
[index
]; }
71 UInt32
MatchFinder_GetNumAvailableBytes(CMatchFinder
*p
) { return p
->streamPos
- p
->pos
; }
73 void MatchFinder_ReduceOffsets(CMatchFinder
*p
, UInt32 subValue
)
75 p
->posLimit
-= subValue
;
77 p
->streamPos
-= subValue
;
80 static void MatchFinder_ReadBlock(CMatchFinder
*p
)
82 if (p
->streamEndWasReached
|| p
->result
!= SZ_OK
)
86 Byte
*dest
= p
->buffer
+ (p
->streamPos
- p
->pos
);
87 size_t size
= (p
->bufferBase
+ p
->blockSize
- dest
);
90 p
->result
= p
->stream
->Read(p
->stream
, dest
, &size
);
91 if (p
->result
!= SZ_OK
)
95 p
->streamEndWasReached
= 1;
98 p
->streamPos
+= (UInt32
)size
;
99 if (p
->streamPos
- p
->pos
> p
->keepSizeAfter
)
104 void MatchFinder_MoveBlock(CMatchFinder
*p
)
106 memmove(p
->bufferBase
,
107 p
->buffer
- p
->keepSizeBefore
,
108 (size_t)(p
->streamPos
- p
->pos
+ p
->keepSizeBefore
));
109 p
->buffer
= p
->bufferBase
+ p
->keepSizeBefore
;
112 int MatchFinder_NeedMove(CMatchFinder
*p
)
114 /* if (p->streamEndWasReached) return 0; */
115 return ((size_t)(p
->bufferBase
+ p
->blockSize
- p
->buffer
) <= p
->keepSizeAfter
);
118 void MatchFinder_ReadIfRequired(CMatchFinder
*p
)
120 if (p
->streamEndWasReached
)
122 if (p
->keepSizeAfter
>= p
->streamPos
- p
->pos
)
123 MatchFinder_ReadBlock(p
);
126 static void MatchFinder_CheckAndMoveAndRead(CMatchFinder
*p
)
128 if (MatchFinder_NeedMove(p
))
129 MatchFinder_MoveBlock(p
);
130 MatchFinder_ReadBlock(p
);
133 static void MatchFinder_SetDefaultSettings(CMatchFinder
*p
)
138 /* p->skipModeBits = 0; */
143 #define kCrcPoly 0xEDB88320
145 void MatchFinder_Construct(CMatchFinder
*p
)
151 MatchFinder_SetDefaultSettings(p
);
153 for (i
= 0; i
< 256; i
++)
157 for (j
= 0; j
< 8; j
++)
158 r
= (r
>> 1) ^ (kCrcPoly
& ~((r
& 1) - 1));
163 static void MatchFinder_FreeThisClassMemory(CMatchFinder
*p
, ISzAlloc
*alloc
)
165 alloc
->Free(alloc
, p
->hash
);
169 void MatchFinder_Free(CMatchFinder
*p
, ISzAlloc
*alloc
)
171 MatchFinder_FreeThisClassMemory(p
, alloc
);
172 LzInWindow_Free(p
, alloc
);
175 static CLzRef
* AllocRefs(UInt32 num
, ISzAlloc
*alloc
)
177 size_t sizeInBytes
= (size_t)num
* sizeof(CLzRef
);
178 if (sizeInBytes
/ sizeof(CLzRef
) != num
)
180 return (CLzRef
*)alloc
->Alloc(alloc
, sizeInBytes
);
183 int MatchFinder_Create(CMatchFinder
*p
, UInt32 historySize
,
184 UInt32 keepAddBufferBefore
, UInt32 matchMaxLen
, UInt32 keepAddBufferAfter
,
188 if (historySize
> kMaxHistorySize
)
190 MatchFinder_Free(p
, alloc
);
193 sizeReserv
= historySize
>> 1;
194 if (historySize
> ((UInt32
)2 << 30))
195 sizeReserv
= historySize
>> 2;
196 sizeReserv
+= (keepAddBufferBefore
+ matchMaxLen
+ keepAddBufferAfter
) / 2 + (1 << 19);
198 p
->keepSizeBefore
= historySize
+ keepAddBufferBefore
+ 1;
199 p
->keepSizeAfter
= matchMaxLen
+ keepAddBufferAfter
;
200 /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
201 if (LzInWindow_Create(p
, sizeReserv
, alloc
))
203 UInt32 newCyclicBufferSize
= (historySize
/* >> p->skipModeBits */) + 1;
205 p
->matchMaxLen
= matchMaxLen
;
207 p
->fixedHashSize
= 0;
208 if (p
->numHashBytes
== 2)
212 hs
= historySize
- 1;
218 /* hs >>= p->skipModeBits; */
219 hs
|= 0xFFFF; /* don't change it! It's required for Deflate */
222 if (p
->numHashBytes
== 3)
230 if (p
->numHashBytes
> 2) p
->fixedHashSize
+= kHash2Size
;
231 if (p
->numHashBytes
> 3) p
->fixedHashSize
+= kHash3Size
;
232 if (p
->numHashBytes
> 4) p
->fixedHashSize
+= kHash4Size
;
233 hs
+= p
->fixedHashSize
;
237 UInt32 prevSize
= p
->hashSizeSum
+ p
->numSons
;
239 p
->historySize
= historySize
;
241 p
->cyclicBufferSize
= newCyclicBufferSize
;
242 p
->numSons
= (p
->btMode
? newCyclicBufferSize
* 2 : newCyclicBufferSize
);
243 newSize
= p
->hashSizeSum
+ p
->numSons
;
244 if (p
->hash
!= 0 && prevSize
== newSize
)
246 MatchFinder_FreeThisClassMemory(p
, alloc
);
247 p
->hash
= AllocRefs(newSize
, alloc
);
250 p
->son
= p
->hash
+ p
->hashSizeSum
;
255 MatchFinder_Free(p
, alloc
);
259 static void MatchFinder_SetLimits(CMatchFinder
*p
)
261 UInt32 limit
= kMaxValForNormalize
- p
->pos
;
262 UInt32 limit2
= p
->cyclicBufferSize
- p
->cyclicBufferPos
;
265 limit2
= p
->streamPos
- p
->pos
;
266 if (limit2
<= p
->keepSizeAfter
)
272 limit2
-= p
->keepSizeAfter
;
276 UInt32 lenLimit
= p
->streamPos
- p
->pos
;
277 if (lenLimit
> p
->matchMaxLen
)
278 lenLimit
= p
->matchMaxLen
;
279 p
->lenLimit
= lenLimit
;
281 p
->posLimit
= p
->pos
+ limit
;
284 void MatchFinder_Init(CMatchFinder
*p
)
287 for(i
= 0; i
< p
->hashSizeSum
; i
++)
288 p
->hash
[i
] = kEmptyHashValue
;
289 p
->cyclicBufferPos
= 0;
290 p
->buffer
= p
->bufferBase
;
291 p
->pos
= p
->streamPos
= p
->cyclicBufferSize
;
293 p
->streamEndWasReached
= 0;
294 MatchFinder_ReadBlock(p
);
295 MatchFinder_SetLimits(p
);
298 static UInt32
MatchFinder_GetSubValue(CMatchFinder
*p
)
300 return (p
->pos
- p
->historySize
- 1) & kNormalizeMask
;
303 void MatchFinder_Normalize3(UInt32 subValue
, CLzRef
*items
, UInt32 numItems
)
306 for (i
= 0; i
< numItems
; i
++)
308 UInt32 value
= items
[i
];
309 if (value
<= subValue
)
310 value
= kEmptyHashValue
;
317 static void MatchFinder_Normalize(CMatchFinder
*p
)
319 UInt32 subValue
= MatchFinder_GetSubValue(p
);
320 MatchFinder_Normalize3(subValue
, p
->hash
, p
->hashSizeSum
+ p
->numSons
);
321 MatchFinder_ReduceOffsets(p
, subValue
);
324 static void MatchFinder_CheckLimits(CMatchFinder
*p
)
326 if (p
->pos
== kMaxValForNormalize
)
327 MatchFinder_Normalize(p
);
328 if (!p
->streamEndWasReached
&& p
->keepSizeAfter
== p
->streamPos
- p
->pos
)
329 MatchFinder_CheckAndMoveAndRead(p
);
330 if (p
->cyclicBufferPos
== p
->cyclicBufferSize
)
331 p
->cyclicBufferPos
= 0;
332 MatchFinder_SetLimits(p
);
335 static UInt32
* Hc_GetMatchesSpec(UInt32 lenLimit
, UInt32 curMatch
, UInt32 pos
, const Byte
*cur
, CLzRef
*son
,
336 UInt32 _cyclicBufferPos
, UInt32 _cyclicBufferSize
, UInt32 cutValue
,
337 UInt32
*distances
, UInt32 maxLen
)
339 son
[_cyclicBufferPos
] = curMatch
;
342 UInt32 delta
= pos
- curMatch
;
343 if (cutValue
-- == 0 || delta
>= _cyclicBufferSize
)
346 const Byte
*pb
= cur
- delta
;
347 curMatch
= son
[_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)];
348 if (pb
[maxLen
] == cur
[maxLen
] && *pb
== *cur
)
351 while(++len
!= lenLimit
)
352 if (pb
[len
] != cur
[len
])
356 *distances
++ = maxLen
= len
;
357 *distances
++ = delta
- 1;
366 UInt32
* GetMatchesSpec1(UInt32 lenLimit
, UInt32 curMatch
, UInt32 pos
, const Byte
*cur
, CLzRef
*son
,
367 UInt32 _cyclicBufferPos
, UInt32 _cyclicBufferSize
, UInt32 cutValue
,
368 UInt32
*distances
, UInt32 maxLen
)
370 CLzRef
*ptr0
= son
+ (_cyclicBufferPos
<< 1) + 1;
371 CLzRef
*ptr1
= son
+ (_cyclicBufferPos
<< 1);
372 UInt32 len0
= 0, len1
= 0;
375 UInt32 delta
= pos
- curMatch
;
376 if (cutValue
-- == 0 || delta
>= _cyclicBufferSize
)
378 *ptr0
= *ptr1
= kEmptyHashValue
;
382 CLzRef
*pair
= son
+ ((_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)) << 1);
383 const Byte
*pb
= cur
- delta
;
384 UInt32 len
= (len0
< len1
? len0
: len1
);
385 if (pb
[len
] == cur
[len
])
387 if (++len
!= lenLimit
&& pb
[len
] == cur
[len
])
388 while(++len
!= lenLimit
)
389 if (pb
[len
] != cur
[len
])
393 *distances
++ = maxLen
= len
;
394 *distances
++ = delta
- 1;
403 if (pb
[len
] < cur
[len
])
421 static void SkipMatchesSpec(UInt32 lenLimit
, UInt32 curMatch
, UInt32 pos
, const Byte
*cur
, CLzRef
*son
,
422 UInt32 _cyclicBufferPos
, UInt32 _cyclicBufferSize
, UInt32 cutValue
)
424 CLzRef
*ptr0
= son
+ (_cyclicBufferPos
<< 1) + 1;
425 CLzRef
*ptr1
= son
+ (_cyclicBufferPos
<< 1);
426 UInt32 len0
= 0, len1
= 0;
429 UInt32 delta
= pos
- curMatch
;
430 if (cutValue
-- == 0 || delta
>= _cyclicBufferSize
)
432 *ptr0
= *ptr1
= kEmptyHashValue
;
436 CLzRef
*pair
= son
+ ((_cyclicBufferPos
- delta
+ ((delta
> _cyclicBufferPos
) ? _cyclicBufferSize
: 0)) << 1);
437 const Byte
*pb
= cur
- delta
;
438 UInt32 len
= (len0
< len1
? len0
: len1
);
439 if (pb
[len
] == cur
[len
])
441 while(++len
!= lenLimit
)
442 if (pb
[len
] != cur
[len
])
453 if (pb
[len
] < cur
[len
])
472 ++p->cyclicBufferPos; \
474 if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
476 #define MOVE_POS_RET MOVE_POS return offset;
478 static void MatchFinder_MovePos(CMatchFinder
*p
) { MOVE_POS
; }
480 #define GET_MATCHES_HEADER2(minLen, ret_op) \
481 UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
482 lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
485 #define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
486 #define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
488 #define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
490 #define GET_MATCHES_FOOTER(offset, maxLen) \
491 offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
492 distances + offset, maxLen) - distances); MOVE_POS_RET;
494 #define SKIP_FOOTER \
495 SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
497 static UInt32
Bt2_MatchFinder_GetMatches(CMatchFinder
*p
, UInt32
*distances
)
500 GET_MATCHES_HEADER(2)
502 curMatch
= p
->hash
[hashValue
];
503 p
->hash
[hashValue
] = p
->pos
;
505 GET_MATCHES_FOOTER(offset
, 1)
508 UInt32
Bt3Zip_MatchFinder_GetMatches(CMatchFinder
*p
, UInt32
*distances
)
511 GET_MATCHES_HEADER(3)
513 curMatch
= p
->hash
[hashValue
];
514 p
->hash
[hashValue
] = p
->pos
;
516 GET_MATCHES_FOOTER(offset
, 2)
519 static UInt32
Bt3_MatchFinder_GetMatches(CMatchFinder
*p
, UInt32
*distances
)
521 UInt32 hash2Value
, delta2
, maxLen
, offset
;
522 GET_MATCHES_HEADER(3)
526 delta2
= p
->pos
- p
->hash
[hash2Value
];
527 curMatch
= p
->hash
[kFix3HashSize
+ hashValue
];
529 p
->hash
[hash2Value
] =
530 p
->hash
[kFix3HashSize
+ hashValue
] = p
->pos
;
535 if (delta2
< p
->cyclicBufferSize
&& *(cur
- delta2
) == *cur
)
537 for (; maxLen
!= lenLimit
; maxLen
++)
538 if (cur
[(ptrdiff_t)maxLen
- delta2
] != cur
[maxLen
])
540 distances
[0] = maxLen
;
541 distances
[1] = delta2
- 1;
543 if (maxLen
== lenLimit
)
545 SkipMatchesSpec(lenLimit
, curMatch
, MF_PARAMS(p
));
549 GET_MATCHES_FOOTER(offset
, maxLen
)
552 static UInt32
Bt4_MatchFinder_GetMatches(CMatchFinder
*p
, UInt32
*distances
)
554 UInt32 hash2Value
, hash3Value
, delta2
, delta3
, maxLen
, offset
;
555 GET_MATCHES_HEADER(4)
559 delta2
= p
->pos
- p
->hash
[ hash2Value
];
560 delta3
= p
->pos
- p
->hash
[kFix3HashSize
+ hash3Value
];
561 curMatch
= p
->hash
[kFix4HashSize
+ hashValue
];
563 p
->hash
[ hash2Value
] =
564 p
->hash
[kFix3HashSize
+ hash3Value
] =
565 p
->hash
[kFix4HashSize
+ hashValue
] = p
->pos
;
569 if (delta2
< p
->cyclicBufferSize
&& *(cur
- delta2
) == *cur
)
571 distances
[0] = maxLen
= 2;
572 distances
[1] = delta2
- 1;
575 if (delta2
!= delta3
&& delta3
< p
->cyclicBufferSize
&& *(cur
- delta3
) == *cur
)
578 distances
[offset
+ 1] = delta3
- 1;
584 for (; maxLen
!= lenLimit
; maxLen
++)
585 if (cur
[(ptrdiff_t)maxLen
- delta2
] != cur
[maxLen
])
587 distances
[offset
- 2] = maxLen
;
588 if (maxLen
== lenLimit
)
590 SkipMatchesSpec(lenLimit
, curMatch
, MF_PARAMS(p
));
596 GET_MATCHES_FOOTER(offset
, maxLen
)
599 static UInt32
Hc4_MatchFinder_GetMatches(CMatchFinder
*p
, UInt32
*distances
)
601 UInt32 hash2Value
, hash3Value
, delta2
, delta3
, maxLen
, offset
;
602 GET_MATCHES_HEADER(4)
606 delta2
= p
->pos
- p
->hash
[ hash2Value
];
607 delta3
= p
->pos
- p
->hash
[kFix3HashSize
+ hash3Value
];
608 curMatch
= p
->hash
[kFix4HashSize
+ hashValue
];
610 p
->hash
[ hash2Value
] =
611 p
->hash
[kFix3HashSize
+ hash3Value
] =
612 p
->hash
[kFix4HashSize
+ hashValue
] = p
->pos
;
616 if (delta2
< p
->cyclicBufferSize
&& *(cur
- delta2
) == *cur
)
618 distances
[0] = maxLen
= 2;
619 distances
[1] = delta2
- 1;
622 if (delta2
!= delta3
&& delta3
< p
->cyclicBufferSize
&& *(cur
- delta3
) == *cur
)
625 distances
[offset
+ 1] = delta3
- 1;
631 for (; maxLen
!= lenLimit
; maxLen
++)
632 if (cur
[(ptrdiff_t)maxLen
- delta2
] != cur
[maxLen
])
634 distances
[offset
- 2] = maxLen
;
635 if (maxLen
== lenLimit
)
637 p
->son
[p
->cyclicBufferPos
] = curMatch
;
643 offset
= (UInt32
)(Hc_GetMatchesSpec(lenLimit
, curMatch
, MF_PARAMS(p
),
644 distances
+ offset
, maxLen
) - (distances
));
648 UInt32
Hc3Zip_MatchFinder_GetMatches(CMatchFinder
*p
, UInt32
*distances
)
651 GET_MATCHES_HEADER(3)
653 curMatch
= p
->hash
[hashValue
];
654 p
->hash
[hashValue
] = p
->pos
;
655 offset
= (UInt32
)(Hc_GetMatchesSpec(lenLimit
, curMatch
, MF_PARAMS(p
),
656 distances
, 2) - (distances
));
660 static void Bt2_MatchFinder_Skip(CMatchFinder
*p
, UInt32 num
)
666 curMatch
= p
->hash
[hashValue
];
667 p
->hash
[hashValue
] = p
->pos
;
673 void Bt3Zip_MatchFinder_Skip(CMatchFinder
*p
, UInt32 num
)
679 curMatch
= p
->hash
[hashValue
];
680 p
->hash
[hashValue
] = p
->pos
;
686 static void Bt3_MatchFinder_Skip(CMatchFinder
*p
, UInt32 num
)
693 curMatch
= p
->hash
[kFix3HashSize
+ hashValue
];
694 p
->hash
[hash2Value
] =
695 p
->hash
[kFix3HashSize
+ hashValue
] = p
->pos
;
701 static void Bt4_MatchFinder_Skip(CMatchFinder
*p
, UInt32 num
)
705 UInt32 hash2Value
, hash3Value
;
708 curMatch
= p
->hash
[kFix4HashSize
+ hashValue
];
709 p
->hash
[ hash2Value
] =
710 p
->hash
[kFix3HashSize
+ hash3Value
] = p
->pos
;
711 p
->hash
[kFix4HashSize
+ hashValue
] = p
->pos
;
717 static void Hc4_MatchFinder_Skip(CMatchFinder
*p
, UInt32 num
)
721 UInt32 hash2Value
, hash3Value
;
724 curMatch
= p
->hash
[kFix4HashSize
+ hashValue
];
725 p
->hash
[ hash2Value
] =
726 p
->hash
[kFix3HashSize
+ hash3Value
] =
727 p
->hash
[kFix4HashSize
+ hashValue
] = p
->pos
;
728 p
->son
[p
->cyclicBufferPos
] = curMatch
;
734 void Hc3Zip_MatchFinder_Skip(CMatchFinder
*p
, UInt32 num
)
740 curMatch
= p
->hash
[hashValue
];
741 p
->hash
[hashValue
] = p
->pos
;
742 p
->son
[p
->cyclicBufferPos
] = curMatch
;
748 void MatchFinder_CreateVTable(CMatchFinder
*p
, IMatchFinder
*vTable
)
750 vTable
->Init
= (Mf_Init_Func
)MatchFinder_Init
;
751 vTable
->GetIndexByte
= (Mf_GetIndexByte_Func
)MatchFinder_GetIndexByte
;
752 vTable
->GetNumAvailableBytes
= (Mf_GetNumAvailableBytes_Func
)MatchFinder_GetNumAvailableBytes
;
753 vTable
->GetPointerToCurrentPos
= (Mf_GetPointerToCurrentPos_Func
)MatchFinder_GetPointerToCurrentPos
;
756 vTable
->GetMatches
= (Mf_GetMatches_Func
)Hc4_MatchFinder_GetMatches
;
757 vTable
->Skip
= (Mf_Skip_Func
)Hc4_MatchFinder_Skip
;
759 else if (p
->numHashBytes
== 2)
761 vTable
->GetMatches
= (Mf_GetMatches_Func
)Bt2_MatchFinder_GetMatches
;
762 vTable
->Skip
= (Mf_Skip_Func
)Bt2_MatchFinder_Skip
;
764 else if (p
->numHashBytes
== 3)
766 vTable
->GetMatches
= (Mf_GetMatches_Func
)Bt3_MatchFinder_GetMatches
;
767 vTable
->Skip
= (Mf_Skip_Func
)Bt3_MatchFinder_Skip
;
771 vTable
->GetMatches
= (Mf_GetMatches_Func
)Bt4_MatchFinder_GetMatches
;
772 vTable
->Skip
= (Mf_Skip_Func
)Bt4_MatchFinder_Skip
;