2015-07-12 15:37:50 +04:00
//! \file ImageWBM.cs
//! \date Thu Jul 09 20:59:09 2015
//! \brief Wild Bug's image format.
//
// Copyright (C) 2015 by morkt
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//
using System ;
using System.ComponentModel.Composition ;
using System.IO ;
using System.Windows.Media ;
using System.Windows.Media.Imaging ;
using GameRes.Utility ;
namespace GameRes.Formats.WildBug
{
internal class WbmMetaData : ImageMetaData
{
public int EntryCount ;
public int EntrySize ;
public byte [ ] Header ;
}
2015-08-17 23:08:02 +04:00
internal class WpxSection
{
public int DataFormat ;
public int Offset ;
public int UnpackedSize ;
public int PackedSize ;
public static WpxSection Find ( byte [ ] header , byte id , int count , int dir_size )
{
int ptr = 0 ;
int n = 0 ;
while ( header [ ptr ] ! = id )
{
ptr + = dir_size ;
if ( ptr > = header . Length )
return null ;
if ( + + n > = count )
return null ;
}
return new WpxSection {
DataFormat = header [ ptr + 1 ] ,
Offset = LittleEndian . ToInt32 ( header , ptr + 4 ) ,
UnpackedSize = LittleEndian . ToInt32 ( header , ptr + 8 ) ,
PackedSize = LittleEndian . ToInt32 ( header , ptr + 12 ) ,
} ;
}
}
2015-07-12 15:37:50 +04:00
[Export(typeof(ImageFormat))]
public class WbmFormat : ImageFormat
{
public override string Tag { get { return "WBM" ; } }
public override string Description { get { return "Wild Bug's image format" ; } }
public override uint Signature { get { return 0x1A585057 ; } } // 'WPX'
public override ImageMetaData ReadMetaData ( Stream stream )
{
byte [ ] header = new byte [ 0x10 ] ;
if ( header . Length ! = stream . Read ( header , 0 , header . Length ) )
return null ;
2015-08-17 23:08:02 +04:00
if ( ! Binary . AsciiEqual ( header , 4 , "BMP" ) )
return null ;
2015-07-12 15:37:50 +04:00
int count = header [ 0xE ] ;
int dir_size = header [ 0xF ] ;
if ( 1 ! = header [ 0xC ] | | 0 = = count | | 0 = = dir_size )
return null ;
header = new byte [ count * dir_size ] ;
if ( header . Length ! = stream . Read ( header , 0 , header . Length ) )
return null ;
2015-08-17 23:08:02 +04:00
var section = WpxSection . Find ( header , 0x10 , count , dir_size ) ;
if ( null = = section )
2015-07-12 15:37:50 +04:00
return null ;
2015-08-17 23:08:02 +04:00
if ( section . UnpackedSize < 0x10 )
2015-07-12 15:37:50 +04:00
return null ;
2015-08-17 23:08:02 +04:00
stream . Seek ( section . Offset , SeekOrigin . Begin ) ;
byte [ ] data = new byte [ section . UnpackedSize ] ;
if ( data . Length ! = stream . Read ( data , 0 , data . Length ) )
2015-07-12 15:37:50 +04:00
return null ;
return new WbmMetaData
{
Width = LittleEndian . ToUInt16 ( data , 4 ) ,
Height = LittleEndian . ToUInt16 ( data , 6 ) ,
BPP = data [ 0xC ] ,
EntryCount = count ,
EntrySize = dir_size ,
Header = header ,
} ;
}
public override ImageData Read ( Stream stream , ImageMetaData info )
{
var meta = info as WbmMetaData ;
if ( null = = meta )
throw new ArgumentException ( "WbmFormat.Read should be supplied with WbmMetaData" , "info" ) ;
2015-08-17 23:08:02 +04:00
var section = WpxSection . Find ( meta . Header , 0x11 , meta . EntryCount , meta . EntrySize ) ;
if ( null = = section )
2015-07-12 15:37:50 +04:00
throw new InvalidFormatException ( ) ;
PixelFormat format ;
int pixel_size ;
switch ( meta . BPP )
{
case 24 :
format = PixelFormats . Bgr24 ;
pixel_size = 3 ;
break ;
case 32 :
format = PixelFormats . Bgr32 ;
pixel_size = 4 ;
break ;
case 16 :
format = PixelFormats . Bgr555 ;
pixel_size = 2 ;
break ;
default :
throw new NotSupportedException ( "Not supported WBM bitdepth" ) ;
}
int stride = ( ( int ) meta . Width * pixel_size + 3 ) & - 4 ;
2015-08-17 23:08:02 +04:00
var reader = new WbmReader ( stream , section ) ;
var pixels = reader . Unpack ( stride , pixel_size , section . DataFormat ) ;
2015-07-12 15:37:50 +04:00
if ( null = = pixels )
throw new InvalidFormatException ( ) ;
2015-08-17 23:08:02 +04:00
if ( meta . BPP < 24 )
return ImageData . Create ( info , format , null , pixels , stride ) ;
section = WpxSection . Find ( meta . Header , 0x13 , meta . EntryCount , meta . EntrySize ) ;
if ( null = = section )
return ImageData . Create ( info , format , null , pixels , stride ) ;
int alpha_stride = ( ( int ) meta . Width + 3 ) & - 4 ;
byte [ ] alpha = null ;
try
{
reader = new WbmReader ( stream , section ) ;
alpha = reader . Unpack ( alpha_stride , 1 , section . DataFormat ) ;
}
catch { }
if ( null = = alpha )
return ImageData . Create ( info , format , null , pixels , stride ) ;
2015-07-12 15:37:50 +04:00
2015-08-17 23:08:02 +04:00
byte [ ] alpha_image = new byte [ 4 * meta . Width * meta . Height ] ;
int dst = 0 ;
for ( int y = 0 ; y < meta . Height ; + + y )
{
int alpha_src = y * alpha_stride ;
int src = y * stride ;
for ( int x = 0 ; x < meta . Width ; + + x )
{
alpha_image [ dst + + ] = pixels [ src ] ;
alpha_image [ dst + + ] = pixels [ src + 1 ] ;
alpha_image [ dst + + ] = pixels [ src + 2 ] ;
alpha_image [ dst + + ] = alpha [ alpha_src + x ] ;
src + = pixel_size ;
}
}
return ImageData . Create ( info , PixelFormats . Bgra32 , null , alpha_image , ( int ) meta . Width * 4 ) ;
2015-07-12 15:37:50 +04:00
}
public override void Write ( Stream file , ImageData image )
{
throw new System . NotImplementedException ( "WbmFormat.Write not implemented" ) ;
}
}
2015-08-18 00:17:50 +04:00
internal class WbmReader : WpxDecoder
2015-07-12 15:37:50 +04:00
{
2015-08-18 00:17:50 +04:00
public WbmReader ( Stream input , WpxSection section ) : base ( input , section )
2015-07-12 15:37:50 +04:00
{
}
2015-08-17 23:08:02 +04:00
void GenerateOffsetTableV1 ( int [ ] offset_table , int stride , int pixel_size )
2015-07-12 15:37:50 +04:00
{
offset_table [ 4 ] = pixel_size ;
offset_table [ 2 ] = 2 * pixel_size ;
offset_table [ 5 ] = 3 * pixel_size ;
if ( 5 * pixel_size < stride )
{
offset_table [ 6 ] = stride - pixel_size ;
offset_table [ 0 ] = stride ;
offset_table [ 7 ] = pixel_size + stride ;
offset_table [ 3 ] = 2 * pixel_size + stride ;
offset_table [ 1 ] = 2 * stride ;
}
else
{
offset_table [ 6 ] = 4 * pixel_size ;
offset_table [ 0 ] = 5 * pixel_size ;
offset_table [ 7 ] = 6 * pixel_size ;
offset_table [ 3 ] = 7 * pixel_size ;
offset_table [ 1 ] = 8 * pixel_size ;
}
2015-08-17 23:08:02 +04:00
}
void GenerateOffsetTableV2 ( int [ ] offset_table , int stride , int pixel_size )
{
offset_table [ 0 ] = pixel_size ;
offset_table [ 1 ] = 2 * pixel_size ;
offset_table [ 2 ] = 3 * pixel_size ;
if ( 5 * pixel_size < stride )
{
offset_table [ 3 ] = stride - pixel_size ;
offset_table [ 4 ] = stride ;
offset_table [ 5 ] = pixel_size + stride ;
offset_table [ 6 ] = 2 * pixel_size + stride ;
offset_table [ 7 ] = 2 * stride ;
}
else
2015-07-12 15:37:50 +04:00
{
2015-08-17 23:08:02 +04:00
offset_table [ 3 ] = 4 * pixel_size ;
offset_table [ 4 ] = 5 * pixel_size ;
offset_table [ 5 ] = 6 * pixel_size ;
offset_table [ 6 ] = 7 * pixel_size ;
offset_table [ 7 ] = 8 * pixel_size ;
2015-07-12 15:37:50 +04:00
}
2015-08-17 23:08:02 +04:00
}
2015-07-12 15:37:50 +04:00
2015-08-17 23:08:02 +04:00
int m_condition ;
public byte [ ] Unpack ( int stride , int pixel_size , int flags ) // sub_40919C
{
int [ ] offset_table = new int [ 8 ] ;
GenerateOffsetTableV2 ( offset_table , stride , pixel_size ) ;
for ( m_condition = 1 ; m_condition > = 0 ; - - m_condition )
{
try
{
ResetInput ( ) ;
2015-08-18 00:17:50 +04:00
if ( 0 = = ( flags & 0x80 ) & & 0 ! = PackedSize )
2015-08-17 23:08:02 +04:00
{
byte [ ] ref_table = new byte [ 0x10000 ] ;
if ( 0 ! = ( flags & 1 ) )
{
if ( 0 ! = ( flags & 8 ) )
{
if ( 0 ! = ( flags & 4 ) )
return UnpackVD ( ref_table , offset_table , pixel_size ) ;
else if ( 0 ! = ( flags & 2 ) )
return UnpackVB ( ref_table , offset_table , pixel_size ) ;
else
return UnpackV9 ( offset_table , pixel_size ) ;
}
else if ( 0 ! = ( flags & 4 ) )
return UnpackV5 ( ref_table , offset_table , pixel_size ) ;
else if ( 0 ! = ( flags & 2 ) )
return UnpackV3 ( ref_table , offset_table , pixel_size ) ;
else
return UnpackV1 ( offset_table , pixel_size ) ;
}
else if ( 0 ! = ( flags & 4 ) )
return UnpackV4 ( ref_table , offset_table , pixel_size ) ;
else if ( 0 ! = ( flags & 2 ) )
return UnpackV2 ( ref_table , offset_table , pixel_size ) ;
else
return UnpackV0 ( offset_table , pixel_size ) ;
}
2015-08-18 00:17:50 +04:00
else
return ReadUncompressed ( ) ;
2015-08-17 23:08:02 +04:00
}
catch
{
if ( 0 = = m_condition )
throw ;
}
GenerateOffsetTableV1 ( offset_table , stride , pixel_size ) ;
}
2015-07-12 15:37:50 +04:00
return null ;
}
2015-08-17 23:08:02 +04:00
byte [ ] UnpackVD ( byte [ ] a4 , int [ ] offset_table , int pixel_size ) // 0x0F format
// int sub_460470(void *dst, const void *src, unsigned __int8 *ref_table, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
byte [ ] v47 = BuildTable ( ) ; //sub_46C26C();
int min_count = 1 = = pixel_size ? 2 : 1 ;
m_available = FillBuffer ( ) ;
if ( 0 = = m_available )
return null ;
int step = ( pixel_size + 3 ) & - 4 ;
if ( m_available < step + 0x80 )
return null ;
int v7 = - pixel_size & 3 ;
Buffer . BlockCopy ( m_buffer , 0 , m_output , 0 , pixel_size ) ;
int dst = pixel_size ;
int remaining = m_output . Length - pixel_size ;
m_current = pixel_size + v7 + 128 ;
if ( ! FillRefTable ( a4 , pixel_size + v7 ) )
return null ;
int v45 = 16384 ;
while ( remaining > 0 )
{
while ( 0 = = ( GetNextBit ( ) ^ m_condition ) )
{
int v24 = 0 ;
int v25 = 0 ;
v45 & = ~ 0xff00 ;
v45 | = m_output [ dst - pixel_size ] < < 8 ;
int v26 = 16384 ;
for ( ; ; )
{
v24 = ( v24 + 1 ) & 0xFF ;
if ( GetNextBit ( ) ! = 0 )
v25 | = v26 ;
if ( a4 [ 2 * v25 ] = = v24 )
break ;
v26 > > = 1 ;
if ( 0 = = v26 )
return null ;
}
v24 = a4 [ 2 * v25 + 1 ] ;
byte v28 = v47 [ v45 + v24 ] ;
if ( 0 ! = v24 )
{
Buffer . BlockCopy ( v47 , v45 , v47 , v45 + 1 , v24 ) ;
v47 [ v45 ] = v28 ;
}
m_output [ dst + + ] = v28 ;
- - remaining ;
if ( 0 = = remaining )
return m_output ;
}
int count ;
int src_offset ;
if ( GetNextBit ( ) ! = 0 )
{
int v37 = ReadNext ( ) ;
count = 2 ;
src_offset = dst - 1 - v37 ;
}
else
{
count = min_count ;
int v36 = GetNextBit ( ) < < 2 ;
v36 | = GetNextBit ( ) < < 1 ;
v36 | = GetNextBit ( ) ;
src_offset = dst - offset_table [ v36 ] ;
}
if ( 0 = = GetNextBit ( ) )
{
count + = ReadCount ( ) ;
}
if ( remaining < count )
return null ;
Binary . CopyOverlapped ( m_output , src_offset , dst , count ) ;
dst + = count ;
remaining - = count ;
}
return m_output ;
}
byte [ ] UnpackVB ( byte [ ] a4 , int [ ] offset_table , int pixel_size ) // 0x0B format
{
byte [ ] v47 = BuildTable ( ) ; //sub_46C26C();
int min_count = 1 = = pixel_size ? 2 : 1 ;
m_available = FillBuffer ( ) ;
if ( 0 = = m_available )
return null ;
int step = ( pixel_size + 3 ) & - 4 ;
if ( m_available < step + 0x80 )
return null ;
int v7 = - pixel_size & 3 ;
Buffer . BlockCopy ( m_buffer , 0 , m_output , 0 , pixel_size ) ;
int dst = pixel_size ;
int remaining = m_output . Length - pixel_size ;
m_current = pixel_size + v7 + 128 ;
if ( ! FillRefTable ( a4 , pixel_size + v7 ) )
return null ;
while ( remaining > 0 )
{
while ( 0 = = ( GetNextBit ( ) ^ m_condition ) )
{
int v24 = 0 ;
int v25 = 0 ;
int v26 = 16384 ;
for ( ; ; )
{
v24 = ( v24 + 1 ) & 0xFF ;
if ( GetNextBit ( ) ! = 0 )
v25 | = v26 ;
if ( a4 [ 2 * v25 ] = = v24 )
break ;
v26 > > = 1 ;
if ( 0 = = v26 )
return null ;
}
m_output [ dst + + ] = a4 [ 2 * v25 + 1 ] ;
- - remaining ;
if ( 0 = = remaining )
return m_output ;
}
int count ;
int src_offset ;
if ( GetNextBit ( ) ! = 0 )
{
int v37 = ReadNext ( ) ;
count = 2 ;
src_offset = dst - 1 - v37 ;
}
else
{
count = min_count ;
int v36 = GetNextBit ( ) < < 2 ;
v36 | = GetNextBit ( ) < < 1 ;
v36 | = GetNextBit ( ) ;
src_offset = dst - offset_table [ v36 ] ;
}
if ( 0 = = GetNextBit ( ) )
{
count + = ReadCount ( ) ;
}
if ( remaining < count )
return null ;
Binary . CopyOverlapped ( m_output , src_offset , dst , count ) ;
dst + = count ;
remaining - = count ;
}
return m_output ;
}
byte [ ] UnpackV9 ( int [ ] offset_table , int pixel_size ) // 0x09 format
{
throw new NotImplementedException ( ) ;
}
2015-07-12 15:37:50 +04:00
byte [ ] UnpackV5 ( byte [ ] a4 , int [ ] offset_table , int pixel_size ) // 0x07 format
// int sub_409AF4 (void *a1, FILE *stream, void *ptr, void *a4, unsigned int m_packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
byte [ ] v46 = BuildTable ( ) ;
int min_count = 1 = = pixel_size ? 2 : 1 ;
m_available = FillBuffer ( ) ;
if ( 0 = = m_available )
return null ;
int step = ( pixel_size + 3 ) & - 4 ;
if ( m_available < step + 0x80 )
return null ;
int v10 = - pixel_size & 3 ;
Buffer . BlockCopy ( m_buffer , 0 , m_output , 0 , pixel_size ) ;
int dst = pixel_size ;
int remaining = m_output . Length - pixel_size ;
m_current = pixel_size + v10 + 128 ;
if ( ! FillRefTable ( a4 , pixel_size + v10 ) )
return null ;
int v43 = 16384 ;
while ( remaining > 0 )
{
2015-08-17 23:08:02 +04:00
while ( 0 = = ( GetNextBit ( ) ^ m_condition ) )
2015-07-12 15:37:50 +04:00
{
int v25 = 0 ;
int v26 = 0 ;
v43 & = ~ 0xff00 ;
v43 | = m_output [ dst - pixel_size ] < < 8 ;
int v27 = 16384 ;
for ( ; ; )
{
v25 = ( v25 + 1 ) & 0xff ;
if ( GetNextBit ( ) ! = 0 )
v26 | = v27 ;
if ( a4 [ 2 * v26 ] = = v25 )
break ;
v27 > > = 1 ;
if ( 0 = = v27 )
return null ;
}
v25 = a4 [ 2 * v26 + 1 ] ;
byte v29 = v46 [ v43 + v25 ] ;
if ( 0 ! = v25 )
{
Buffer . BlockCopy ( v46 , v43 , v46 , v43 + 1 , v25 ) ;
v46 [ v43 ] = v29 ;
}
m_output [ dst + + ] = v29 ;
- - remaining ;
if ( 0 = = remaining )
return m_output ;
}
int src_offset ;
int count ;
if ( GetNextBit ( ) ! = 0 )
{
count = min_count ;
2015-08-17 23:08:02 +04:00
int v32 = GetNextBit ( ) < < 2 ;
v32 | = GetNextBit ( ) < < 1 ;
2015-07-12 15:37:50 +04:00
v32 | = GetNextBit ( ) ;
src_offset = dst - offset_table [ v32 ] ;
}
else
{
byte v35 = ReadNext ( ) ;
count = 2 ;
src_offset = dst - 1 - v35 ;
}
if ( 0 = = GetNextBit ( ) )
{
count + = ReadCount ( ) ;
}
if ( remaining < count )
return null ;
Binary . CopyOverlapped ( m_output , src_offset , dst , count ) ;
dst + = count ;
remaining - = count ;
}
return m_output ;
}
byte [ ] UnpackV4 ( byte [ ] a4 , int [ ] offset_table , int pixel_size ) // 0x06 format
// signed int __cdecl sub_40B044(void *a1, FILE *stream, void *ptr, void *a4, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
byte [ ] v48 = BuildTable ( ) ;
int min_count = 1 = = pixel_size ? 2 : 1 ;
m_available = FillBuffer ( ) ;
if ( 0 = = m_available )
return null ;
int step = ( pixel_size + 4 ) & - 4 ;
if ( m_available < step + 0x80 )
return null ;
int v10 = - pixel_size & 3 ;
Buffer . BlockCopy ( m_buffer , 0 , m_output , 0 , pixel_size ) ;
int dst = pixel_size ;
int remaining = m_output . Length - pixel_size ;
m_current = pixel_size + v10 + 128 ;
if ( ! FillRefTable ( a4 , pixel_size + v10 ) )
return null ;
int v46 = 16384 ;
while ( remaining > 0 )
{
int v28 ;
2015-08-17 23:08:02 +04:00
while ( 0 = = ( GetNextBit ( ) ^ m_condition ) )
2015-07-12 15:37:50 +04:00
{
int v27 = 0 ;
v28 = 0 ;
v46 & = ~ 0xff00 ;
v46 | = m_output [ dst - pixel_size ] < < 8 ;
int v29 = 16384 ;
for ( ; ; )
{
v27 = ( v27 + 1 ) & 0xff ;
if ( GetNextBit ( ) ! = 0 )
v28 | = v29 ;
if ( a4 [ 2 * v28 ] = = v27 )
break ;
v29 > > = 1 ;
if ( 0 = = v29 )
return null ;
}
v27 = a4 [ 2 * v28 + 1 ] ;
byte v31 = v48 [ v46 + v27 ] ;
if ( 0 ! = v27 )
{
Buffer . BlockCopy ( v48 , v46 , v48 , v46 + 1 , v27 ) ;
v48 [ v46 ] = v31 ;
}
m_output [ dst + + ] = v31 ;
- - remaining ;
if ( 0 = = remaining )
return m_output ;
}
v28 = GetNextBit ( ) < < 1 ;
v28 | = GetNextBit ( ) ;
v28 < < = 1 ;
v28 | = GetNextBit ( ) ;
int src_offset = dst - offset_table [ v28 ] ;
int count ;
if ( GetNextBit ( ) ! = 0 )
{
count = min_count ;
}
else
{
count = min_count + ReadCount ( ) ;
}
if ( remaining < count )
return null ;
Binary . CopyOverlapped ( m_output , src_offset , dst , count ) ;
dst + = count ;
remaining - = count ;
}
return m_output ;
}
byte [ ] UnpackV3 ( byte [ ] a4 , int [ ] offset_table , int pixel_size ) // 0x03 format
// int sub_409F70(void *a1, FILE *stream, void *ptr, void *a4, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
int min_count = 1 = = pixel_size ? 2 : 1 ;
m_available = FillBuffer ( ) ;
if ( 0 = = m_available )
return null ;
int step = ( pixel_size + 3 ) & - 4 ;
if ( m_available < step + 0x80 )
return null ;
int v9 = - pixel_size & 3 ;
Buffer . BlockCopy ( m_buffer , 0 , m_output , 0 , pixel_size ) ;
int dst = pixel_size ;
int remaining = m_output . Length - pixel_size ;
m_current = pixel_size + v9 + 128 ;
if ( ! FillRefTable ( a4 , pixel_size + v9 ) )
return null ;
while ( remaining > 0 )
{
2015-08-17 23:08:02 +04:00
while ( 0 = = ( GetNextBit ( ) ^ m_condition ) )
2015-07-12 15:37:50 +04:00
{
int v24 = 0 ;
int v25 = 0 ;
int v26 = 16384 ;
for ( ; ; )
{
+ + v24 ;
if ( GetNextBit ( ) ! = 0 )
v25 | = v26 ;
if ( a4 [ 2 * v25 ] = = v24 )
break ;
v26 > > = 1 ;
if ( 0 = = v26 )
return null ;
}
m_output [ dst + + ] = a4 [ 2 * v25 + 1 ] ;
- - remaining ;
if ( 0 = = remaining )
return m_output ;
}
int count , src_offset ;
if ( GetNextBit ( ) ! = 0 )
{
count = min_count ;
int v28 = GetNextBit ( ) < < 1 ;
v28 | = GetNextBit ( ) ;
v28 < < = 1 ;
v28 | = GetNextBit ( ) ;
src_offset = dst - offset_table [ v28 ] ;
}
else
{
count = 2 ;
src_offset = dst - 1 - ReadNext ( ) ;
}
if ( GetNextBit ( ) = = 0 )
{
count + = ReadCount ( ) ;
}
if ( remaining < count )
return null ;
Binary . CopyOverlapped ( m_output , src_offset , dst , count ) ;
dst + = count ;
remaining - = count ;
}
return m_output ;
}
byte [ ] UnpackV2 ( byte [ ] a4 , int [ ] offset_table , int pixel_size ) // 0x02 format
// int sub_40B458(void *a1, FILE *stream, unsigned __int8 *ptr, void *a4, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int a8)
{
byte [ ] v48 = BuildTable ( ) ;
int min_count = 1 = = pixel_size ? 2 : 1 ;
m_available = FillBuffer ( ) ;
if ( 0 = = m_available )
return null ;
int step = ( pixel_size + 3 ) & - 4 ;
if ( m_available < step + 0x80 )
return null ;
int v9 = - pixel_size & 3 ;
Buffer . BlockCopy ( m_buffer , 0 , m_output , 0 , pixel_size ) ;
int dst = pixel_size ;
int remaining = m_output . Length - pixel_size ;
m_current = pixel_size + v9 + 128 ; // within m_buffer
if ( ! FillRefTable ( a4 , pixel_size + v9 ) )
return null ;
while ( remaining > 0 )
{
2015-08-17 23:08:02 +04:00
while ( 0 = = ( GetNextBit ( ) ^ m_condition ) )
2015-07-12 15:37:50 +04:00
{
int v20 = 0 ;
int v21 = 0 ;
v9 = 16384 ;
for ( ; ; )
{
+ + v20 ;
if ( 0 ! = GetNextBit ( ) )
v21 | = v9 ;
if ( a4 [ 2 * v21 ] = = v20 )
break ;
v9 > > = 1 ;
if ( 0 = = v9 )
return null ;
}
m_output [ dst + + ] = a4 [ 2 * v21 + 1 ] ;
- - remaining ;
if ( 0 = = remaining )
return m_output ;
}
int v22 = GetNextBit ( ) < < 1 ;
v22 | = GetNextBit ( ) ;
v22 < < = 1 ;
v22 | = GetNextBit ( ) ;
int src_offset = dst - offset_table [ v22 ] ;
int count ;
if ( 0 ! = GetNextBit ( ) )
{
count = min_count ;
}
else
{
count = min_count + ReadCount ( ) ;
}
if ( remaining < count )
return null ;
Binary . CopyOverlapped ( m_output , src_offset , dst , count ) ;
dst + = count ;
remaining - = count ;
}
return m_output ;
}
byte [ ] UnpackV1 ( int [ ] offset_table , int pixel_size ) // 0x01 format
//int sub_40A3C4(void *a1, FILE *stream, const void *ptr, unsigned int packed_size, int *offset_table, int unpacked_size, unsigned int pixel_size)
{
int min_count = 1 = = pixel_size ? 2 : 1 ;
m_available = FillBuffer ( ) ;
if ( 0 = = m_available )
return null ;
int step = ( pixel_size + 3 ) & - 4 ;
if ( m_available < step )
return null ;
Buffer . BlockCopy ( m_buffer , 0 , m_output , 0 , pixel_size ) ;
int dst = pixel_size ;
int remaining = m_output . Length - pixel_size ;
m_current = pixel_size + ( - pixel_size & 3 ) ;
m_bits = m_buffer [ m_current + + ] ;
m_bit_count = 8 ;
while ( remaining > 0 )
{
2015-08-17 23:08:02 +04:00
while ( 0 = = ( GetNextBit ( ) ^ m_condition ) )
2015-07-12 15:37:50 +04:00
{
m_output [ dst + + ] = ReadNext ( ) ;
- - remaining ;
if ( 0 = = remaining )
return m_output ;
}
int count , src_offset ;
if ( GetNextBit ( ) ! = 0 )
{
count = min_count ;
2015-08-17 23:08:02 +04:00
int v14 = GetNextBit ( ) < < 2 ;
v14 | = GetNextBit ( ) < < 1 ;
2015-07-12 15:37:50 +04:00
v14 | = GetNextBit ( ) ;
src_offset = dst - offset_table [ v14 ] ;
}
else
{
count = 2 ;
src_offset = dst - 1 - ReadNext ( ) ;
}
if ( GetNextBit ( ) = = 0 )
{
count + = ReadCount ( ) ;
}
if ( remaining < count )
return null ;
Binary . CopyOverlapped ( m_output , src_offset , dst , count ) ;
dst + = count ;
remaining - = count ;
}
return m_output ;
}
byte [ ] UnpackV0 ( int [ ] offset_table , int pixel_size ) // 0x00 format
// int sub_40B83C(void *a1, FILE *stream, const void *ptr, unsigned int packed_size, int *a5, int unpacked_size, unsigned int pixel_size)
{
int min_count = 1 = = pixel_size ? 2 : 1 ;
m_available = FillBuffer ( ) ;
if ( 0 = = m_available )
return null ;
int step = ( pixel_size + 3 ) & - 4 ;
if ( m_available < step )
return null ;
Buffer . BlockCopy ( m_buffer , 0 , m_output , 0 , pixel_size ) ;
int dst = pixel_size ;
int remaining = m_output . Length - pixel_size ;
m_current = pixel_size + ( - pixel_size & 3 ) ;
m_bits = m_buffer [ m_current + + ] ;
m_bit_count = 8 ;
while ( remaining > 0 )
{
2015-08-17 23:08:02 +04:00
while ( 0 = = ( GetNextBit ( ) ^ m_condition ) )
2015-07-12 15:37:50 +04:00
{
m_output [ dst + + ] = ReadNext ( ) ;
- - remaining ;
if ( 0 = = remaining )
return m_output ;
}
int v14 = GetNextBit ( ) < < 1 ;
v14 | = GetNextBit ( ) ;
v14 < < = 1 ;
v14 | = GetNextBit ( ) ;
int src_offset = dst - offset_table [ v14 ] ;
int count ;
if ( GetNextBit ( ) ! = 0 )
{
count = min_count ;
}
else
{
count = min_count + ReadCount ( ) ;
}
if ( remaining < count )
return null ;
Binary . CopyOverlapped ( m_output , src_offset , dst , count ) ;
dst + = count ;
remaining - = count ;
}
return m_output ;
}
2015-08-18 00:17:50 +04:00
}
internal class WpxDecoder
{
Stream m_input ;
protected byte [ ] m_output ;
int m_packed_size ;
int m_start_pos ;
2015-07-12 15:37:50 +04:00
2015-08-18 00:17:50 +04:00
public byte [ ] Data { get { return m_output ; } }
protected int PackedSize { get { return m_packed_size ; } }
protected WpxDecoder ( Stream input , WpxSection section )
2015-07-12 15:37:50 +04:00
{
2015-08-18 00:17:50 +04:00
m_input = input ;
m_start_pos = section . Offset ;
m_output = new byte [ section . UnpackedSize ] ;
m_packed_size = section . PackedSize ;
}
protected byte [ ] ReadUncompressed ( )
{
if ( m_output . Length = = m_input . Read ( m_output , 0 , m_output . Length ) )
return m_output ;
else
return null ;
2015-07-12 15:37:50 +04:00
}
2015-08-18 00:17:50 +04:00
protected static byte [ ] BuildTable ( ) // sub_4090E0
2015-07-12 15:37:50 +04:00
{
var table = new byte [ 0x100 * 0x100 ] ;
for ( int i = 0 ; i < 0x100 ; + + i )
{
byte v2 = ( byte ) ( - 1 - i ) ;
for ( int j = 0 ; j < 0x100 ; + + j )
{
2015-08-17 23:08:02 +04:00
table [ 0x100 * i + j ] = v2 - - ;
2015-07-12 15:37:50 +04:00
}
}
return table ;
}
2015-08-18 00:17:50 +04:00
protected bool FillRefTable ( byte [ ] table , int src )
{
m_bits = m_buffer [ m_current + + ] ;
m_bit_count = 8 ;
for ( int n = 0 ; n < 0x100 ; )
{
byte v16 = m_buffer [ src + + ] ;
for ( int half = 0 ; half < 2 ; + + half )
{
byte v17 = ( byte ) ( v16 & 0xF ) ;
if ( 0 ! = v17 )
{
int v18 = 0 ;
for ( int i = v17 ; i ! = 0 ; - - i )
{
if ( 0 = = m_bit_count )
{
if ( m_current > = m_available )
return false ;
m_bits = m_buffer [ m_current + + ] ;
m_bit_count = 8 ;
}
int bit = m_bits > > 7 ;
m_bits < < = 1 ;
- - m_bit_count ;
v18 + = v18 + bit ;
}
if ( 15 ! = v17 )
v18 < < = 15 - v17 ;
table [ 2 * v18 ] = v17 ;
table [ 2 * v18 + 1 ] = ( byte ) n ;
}
+ + n ;
v16 > > = 4 ;
}
}
return true ;
}
protected byte [ ] m_buffer = new byte [ 0x8000 ] ;
protected int m_current = 0 ;
protected int m_available = 0 ;
2015-07-12 15:37:50 +04:00
2015-08-18 00:17:50 +04:00
protected byte ReadNext ( )
2015-07-12 15:37:50 +04:00
{
if ( m_current > = m_available )
{
m_available = FillBuffer ( ) ;
if ( 0 = = m_available )
throw new InvalidFormatException ( "Unexpected end of file" ) ;
m_current = 0 ;
}
return m_buffer [ m_current + + ] ;
}
2015-08-18 00:17:50 +04:00
protected int ReadCount ( )
{
int n = 1 ;
while ( 0 = = GetNextBit ( ) )
{
+ + n ;
}
int count = 1 ;
for ( int i = 0 ; i < n ; + + i )
{
count + = count + GetNextBit ( ) ;
}
return count - 1 ;
}
protected int m_input_remaining ;
2015-08-17 23:08:02 +04:00
2015-08-18 00:17:50 +04:00
protected void ResetInput ( )
2015-08-17 23:08:02 +04:00
{
m_input . Position = m_start_pos ;
m_input_remaining = m_packed_size ;
}
2015-08-18 00:17:50 +04:00
protected int FillBuffer ( ) // sub_409B02
2015-07-12 15:37:50 +04:00
{
int read = 0 ;
2015-08-17 23:08:02 +04:00
if ( m_input_remaining > 0 )
2015-07-12 15:37:50 +04:00
{
2015-08-17 23:08:02 +04:00
int size = Math . Min ( m_input_remaining , 0x8000 ) ;
m_input_remaining - = size ;
2015-07-12 15:37:50 +04:00
read = m_input . Read ( m_buffer , 0 , size ) ;
}
return read ;
}
2015-08-18 00:17:50 +04:00
protected byte m_bits ;
protected int m_bit_count = 0 ;
2015-07-12 15:37:50 +04:00
2015-08-18 00:17:50 +04:00
protected int GetNextBit ( )
2015-07-12 15:37:50 +04:00
{
if ( 0 = = m_bit_count )
{
m_bits = ReadNext ( ) ;
m_bit_count = 8 ;
}
int bit = m_bits > > 7 ;
m_bits < < = 1 ;
- - m_bit_count ;
return bit ;
}
}
}