decode.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 609 行 · 第 1/2 页

C
609
字号
        curroffset++;
    }
}

extern void NoShannonDecode( unsigned long textsize )
/***************************************************/
/* Decoding/Uncompressing */
{
    int             i, j, k, r, c;
    unsigned long   count;

    if (textsize == 0) return;
    getlen = 0;
    getbuf = 0;
    secondbuf = DecReadByte();
    for (i = 0; i < N - F; i++) {
        text_buf[i] = ' ';
    }
    r = N - F;
    for (count = 0; count < textsize; ) {
        if( getlen == 0 ) {
            getbuf = ((unsigned short)secondbuf << 8) | DecReadByte();
            getlen = 16;
            secondbuf = DecReadByte();
        } else if( getlen <= 8 ) {
            getbuf |= (unsigned short)secondbuf << ( 8 - getlen );
            getlen += 8;
            secondbuf = DecReadByte();
        }
        if( (short int) getbuf < 0 ) {    // it is a copy command.
            j = (getbuf >> 9) & 0x3F;
            getlen -= 7;
            getbuf <<= 7;
            i = (r - DecodePosition() - 1) & (N - 1);
            for (k = 0; k < j; k++) {
                c = text_buf[(i + k) & (N - 1)];
                text_buf[r++] = c;
                DecWriteByte( c );
                r &= (N - 1);
            }
            count += j;
        } else {
            c = getbuf >> 7;
            getbuf <<= 9;
            getlen -= 9;
            DecWriteByte( c);
            text_buf[r++] = c;
            r &= (N - 1);
            count++;
        }
    }
    FlushWrite();
}

extern void DoDecode( unsigned long textsize )
/********************************************/
/* Decoding/Uncompressing */
{
    int             i, j, k, r, c;
    int             spare;
    int             codelen;
    unsigned long   count;

    if (textsize == 0) return;
    MakeShannonTrie();
    getlen = 0;
    getbuf = 0;
    secondbuf = DecReadByte();
    for (i = 0; i < N - F; i++) {
        text_buf[i] = ' ';
    }
    r = N - F;
    for (count = 0; count < textsize; ) {
        if( getlen < 8 ) {
            getbuf |= (unsigned short)secondbuf << ( 8 - getlen );
            getlen += 8;
            secondbuf = DecReadByte();
        }
        spare = getlen - 8;
        getlen = 16;
        getbuf |= secondbuf >> spare;    // fill getbuf to 16 bits.
        codelen = MinCodeLen;
        for(;;) {
            if( getbuf >= MinVal[ codelen ] )break;
            codelen++;
        }
        c = CharMap[ MapOffset[ codelen ] +
                            ((getbuf - MinVal[ codelen ]) >> (16 - codelen)) ];
        getbuf <<= codelen;
        getlen -= codelen;
        if( spare > codelen ) {
            getlen -= 8 - spare;
        } else {
            getbuf |= (secondbuf & Mask[ spare ]) << (codelen - spare);
            getlen += spare;
            secondbuf = DecReadByte();
        }
        if (c < 256) {
            DecWriteByte( c);
            text_buf[r++] = c;
            r &= (N - 1);
            count++;
        } else {
            i = (r - DecodePosition() - 1) & (N - 1);
            j = c - 255 + THRESHOLD;
            for (k = 0; k < j; k++) {
                c = text_buf[(i + k) & (N - 1)];
                text_buf[r++] = c;
                DecWriteByte( c );
                r &= (N - 1);
            }
            count += j;
        }
    }
    FlushWrite();
}

static bool CompareCRC( unsigned long crcvalue )
/**********************************************/
// this modifies the old CRC for the bit lookahead, checks the CRC, and then
// it adds the lookahead to the CRC for the next file.
// note this assumes intel byte ordering
{
    bool    retval;

    if( getlen == 16 ) {
        ModifyCRC( &crcvalue, getbuf >> 8 );
        ModifyCRC( &crcvalue, getbuf & 0xFF );
        ModifyCRC( &crcvalue, secondbuf );
        retval = CheckCRC( crcvalue );
        UnReadByte( secondbuf );
        UnReadByte( getbuf & 0xFF );
        UnReadByte( getbuf >> 8 );
    } else if( getlen >= 8 ) {
        getbuf >>= 16 - getlen;
        ModifyCRC( &crcvalue, getbuf & 0xFF );
        ModifyCRC( &crcvalue, secondbuf );
        retval = CheckCRC( crcvalue );
        UnReadByte( secondbuf );
        UnReadByte( getbuf );
    } else {
        ModifyCRC( &crcvalue, secondbuf );
        retval = CheckCRC( crcvalue );
        UnReadByte( secondbuf );
    }
    return( retval );
}

static int FileExists( char *name, file_info *info );           // FileExists defined further down in this file
extern bool DecodeFile( file_info *info, arccmd *cmd )
/****************************************************/
{
    char           drive[_MAX_DRIVE];
    char           directory[_MAX_DIR];
    char           fname[_MAX_FNAME];
    char           extin[_MAX_EXT];
    char *         name;
    char *         thename;      // filename terminated with a nullchar.
    int            pathlen;
    unsigned short namelen;

    namelen = info->namelen & NAMELEN_MASK;
    thename = alloca( namelen + 1 );
    memcpy( thename, info->name, namelen );
    *(thename + namelen) = '\0';
    if( (cmd->flags & KEEP_PATHNAME) ) {
        name = cmd->u.path;
    } else if( !(cmd->flags & (REPLACE_PATH | PREPEND_PATH)) ) {
        name = thename;
    } else {
        pathlen = strlen( cmd->u.path );
        name = alloca( namelen + pathlen  + 1 );
        if( cmd->flags & REPLACE_PATH ) {
            _splitpath( cmd->u.path, drive, directory, NULL, NULL );
            _splitpath( thename, NULL, NULL, fname, extin );
            _makepath( name, drive, directory, fname, extin );
        } else {
            memcpy( name, cmd->u.path, pathlen );
            memcpy( name + pathlen, info->name, namelen );
            *(name + pathlen + namelen) = '\0';
        }
    }
    if( ! FileExists( name, info ) ) {
        outfile = QOpenW( name );
        if( outfile == -1 )  {
            return( FALSE );
        } else {
            LogUnPacking( name );
            if( info->namelen & NO_SHANNON_CODE ) {
                NoShannonDecode( info->length );
            } else {
                DoDecode( info->length );
            }
            QClose( outfile );
            QSetDate( name, info->stamp );
            if( !CompareCRC( info->crc ) && info->length > 0 ) {
                char msg[ 100 ];
                strcpy( msg, LookupText( NULL, TXT_WARN_FILE ) );
                strcat( msg, " \'" );
                strcat( msg, name );
                strcat( msg, "\' " );
                strcat( msg, LookupText( NULL, TXT_INC_CRC ) );
                Error( TXT_INC_CRC, msg );
                return( FALSE );
            }
        }
    }
    return( TRUE );
}

static int FileExists( char *name, file_info *info )            /* 26-may-90 */
{
    auto struct stat            statblk;
#if !defined( UNIX ) && !defined( __UNIX__ )
    unsigned                    attribute;
#endif
    int                         rc;

    rc = stat( name, &statblk );
    if( rc == 0 ) {
#if defined( UNIX ) || defined( __UNIX__ )
        if( !( statblk.st_mode & S_IWRITE ) ) {
#else
        _dos_getfileattr( name, &attribute );
        if( attribute & ( _A_RDONLY | _A_HIDDEN ) ) {
#endif
            /* file is read-only */
            if( !OK_ReplaceRDOnly( name ) ) {
                return( 1 );
            }
#if defined( UNIX ) || defined( __UNIX__ )
            chmod( name, 0777 );
#else
            _dos_setfileattr( name, _A_NORMAL );
#endif
        }
        if( UnPackHook( name ) ) return( 0 ); // this is allowed to modify name
        if( statblk.st_mtime == info->stamp ) {
            return( 1 );
        }
        if( statblk.st_mtime > info->stamp ) {                  /* 14-sep-91 */
            /* file already exists with newer date */
            if( !OK_ToReplace( name ) ) {
                return( 1 );
            }
        }
    } else {
        UnPackHook( name );
    }
    return( 0 );    /* file does not exist, or it has different date or size */
}

extern int Decode( arccmd *cmd )
/*******************************/
{
    file_info **    currfile;
    file_info **    filedata;
    wpackfile *     currname;
    arc_header      header;
    unsigned short  namelen;
    char            *msg;

    filedata = ReadHeader( cmd, &header );
    if( filedata == NULL ) {
        msg = LookupText( NULL, TXT_ARC_NOT_EXIST );
        Error( TXT_ARC_NOT_EXIST, msg );
        return FALSE;
    }
    if( cmd->files == NULL  ||  cmd->files->filename == NULL ) {
//      BufSeek( sizeof( arc_header ) );    // skip header.
        for( currfile = filedata; *currfile != NULL; currfile++ ) {
            if( BufSeek( (*currfile)->disk_addr ) != -1 ) {
                if( !DecodeFile( *currfile, cmd ) ) {
                    return FALSE;
                }
            }
        }
    } else {
        for( currname = cmd->files; currname->filename != NULL; currname++ ) {
            for( currfile = filedata; *currfile != NULL; currfile++ ) {
                namelen = (*currfile)->namelen & NAMELEN_MASK;
                if( strlen( currname->filename ) == namelen &&
                    memicmp(currname->filename, (*currfile)->name, namelen) == 0 ) {
                    if( BufSeek( (*currfile)->disk_addr ) != -1 ) {
                        if( !DecodeFile( *currfile, cmd ) ) {
                            return FALSE;
                        }
                    }
                    break;
                }
            }
            if( *currfile == NULL ) {
                char msg[ 50 ];
                strcpy( msg, LookupText( NULL, TXT_NOT_IN_ARC ) );
                Log( LookupText( NULL, TXT_WARN_FILE ), "\"", currname->filename, "\"",
                     msg, NULL );
            }
        }  // end for
    } // end if
    QClose( infile );       // close the archive file.
    FreeHeader( filedata );
    return TRUE;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?