📄 lzrw3.c
字号:
} control>>=1; /* This loop is all set up for a decrement and jump instruction! */#ifndef linux` end_unrolled_loop: if (--unroll) goto begin_unrolled_loop;#else /* end_unrolled_loop: */ if (--unroll) goto begin_unrolled_loop;#endif /* At this point it will nearly always be the end of a group in which */ /* case, we have to do some control-word processing. However, near the */ /* end of the input block, the inner unrolled loop is only executed once. */ /* This necessitates the 'if' test. */ if ((control&TOPWORD)==0) { /* Write the control word to the place we saved for it in the output. */ *p_control++= control &0xFF; *p_control = (control>>8) &0xFF; /* Reserve the next word in the output block for the control word */ /* for the group about to be processed. */ p_control=p_dst; p_dst+=2; /* Reset the control bits buffer. */ control=TOPWORD; } } /* End main processing loop. */ /* After the main processing loop has executed, all the input bytes have */ /* been processed. However, the control word has still to be written to the */ /* word reserved for it in the output at the start of the most recent group. */ /* Before writing, the control word has to be shifted so that all the bits */ /* are in the right place. The "empty" bit positions are filled with 1s */ /* which partially fill the top word. */ while(control&TOPWORD) control>>=1; *p_control++= control &0xFF; *p_control++=(control>>8) &0xFF; /* If the last group contained no items, delete the control word too. */ if (p_control==p_dst) p_dst-=2; /* Write the length of the output block to the dst_len parameter and return. */ *p_dst_len=p_dst-p_dst_first; return; /* Jump here as soon as an overrun is detected. An overrun is defined to */ /* have occurred if p_dst>p_dst_first+src_len. That is, the moment the */ /* length of the output written so far exceeds the length of the input block.*/ /* The algorithm checks for overruns at least at the end of each group */ /* which means that the maximum overrun is MAX_CMP_GROUP bytes. */ /* Once an overrun occurs, the only thing to do is to set the copy flag and */ /* copy the input over. */ overrun:#if 0 *p_dst_first=FLAG_COPY; fast_copy(p_src_first,p_dst_first+FLAG_BYTES,src_len); *p_dst_len=src_len+FLAG_BYTES;#else fast_copy(p_src_first,p_dst_first,src_len); *p_dst_len= -src_len; /* return a negative number to indicate uncompressed data */#endif}/******************************************************************************//* Input : Hand over the required amount of working memory in p_wrk_mem. *//* Input : Specify input block using p_src_first and src_len. *//* Input : Point p_dst_first to the start of the output zone. *//* Input : Point p_dst_len to a ULONG to receive the output length. *//* Input : Input block and output zone must not overlap. User knows *//* Input : upperbound on output block length from earlier compression. *//* Input : In any case, maximum expansion possible is nine times. *//* Output : Length of output block written to *p_dst_len. *//* Output : Output block in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. *//* Output : Writes only in Mem[p_dst_first..p_dst_first+*p_dst_len-1]. */LOCAL void compress_decompress( UBYTE *p_wrk_mem, UBYTE *p_src_first, LONG src_len, UBYTE *p_dst_first, ULONG *p_dst_len){ /* Byte pointers p_src and p_dst scan through the input and output blocks. */ register UBYTE *p_src = p_src_first+FLAG_BYTES; register UBYTE *p_dst = p_dst_first; /* we need to avoid a SEGV when trying to uncompress corrupt data */ register UBYTE *p_dst_post = p_dst_first + *p_dst_len; /* The following two variables are never modified and are used to control */ /* the main loop. */ UBYTE *p_src_post = p_src_first+src_len; UBYTE *p_src_max16 = p_src_first+src_len-(MAX_CMP_GROUP-2); /* The hash table is the only resident of the working memory. The hash table */ /* contains HASH_TABLE_LENGTH=4096 pointers to positions in the history. To */ /* keep Macintoshes happy, it is longword aligned. */ UBYTE **hash = (UBYTE **) ULONG_ALIGN_UP(p_wrk_mem); /* The variable 'control' is used to buffer the control bits which appear in */ /* groups of 16 bits (control words) at the start of each compressed group. */ /* When each group is read, bit 16 of the register is set to one. Whenever */ /* a new bit is needed, the register is shifted right. When the value of the */ /* register becomes 1, we know that we have reached the end of a group. */ /* Initializing the register to 1 thus instructs the code to follow that it */ /* should read a new control word immediately. */ register ULONG control=1; /* The value of 'literals' is always in the range 0..3. It is the number of */ /* consecutive literal items just seen. We have to record this number so as */ /* to know when to update the hash table. When literals gets to 3, there */ /* have been three consecutive literals and we can update at the position of */ /* the oldest of the three. */ register UWORD literals=0; /* Check the leading copy flag to see if the compressor chose to use a copy */ /* operation instead of a compression operation. If a copy operation was */ /* used, then all we need to do is copy the data over, set the output length */ /* and return. */#if 0 if (*p_src_first==FLAG_COPY) { fast_copy(p_src_first+FLAG_BYTES,p_dst_first,src_len-FLAG_BYTES); *p_dst_len=src_len-FLAG_BYTES; return; }#else if ( src_len < 0 ) { fast_copy(p_src_first,p_dst_first,-src_len ); *p_dst_len = (ULONG)-src_len; return; }#endif /* Initialize all elements of the hash table to point to a constant string. */ /* Use of an unrolled loop speeds this up considerably. */ {UWORD i; UBYTE **p_h=hash;# define ZJ *p_h++=START_STRING_18 for (i=0;i<256;i++) /* 256=HASH_TABLE_LENGTH/16. */ {ZJ;ZJ;ZJ;ZJ; ZJ;ZJ;ZJ;ZJ; ZJ;ZJ;ZJ;ZJ; ZJ;ZJ;ZJ;ZJ;} } /* The outer loop processes either 1 or 16 items per iteration depending on */ /* how close p_src is to the end of the input block. */ while (p_src!=p_src_post) {/* Start of outer loop */ register UWORD unroll; /* Counts unrolled loop executions. */ /* When 'control' has the value 1, it means that the 16 buffered control */ /* bits that were read in at the start of the current group have all been */ /* shifted out and that all that is left is the 1 bit that was injected */ /* into bit 16 at the start of the current group. When we reach the end */ /* of a group, we have to load a new control word and inject a new 1 bit. */ if (control==1) { control=0x10000|*p_src++; control|=(*p_src++)<<8; } /* If it is possible that we are within 16 groups from the end of the */ /* input, execute the unrolled loop only once, else process a whole group */ /* of 16 items by looping 16 times. */ unroll= p_src<=p_src_max16 ? 16 : 1; /* This inner loop processes one phrase (item) per iteration. */ while (unroll--) { /* Begin unrolled inner loop. */ /* Process a literal or copy item depending on the next control bit. */ if (control&1) { /* Copy item. */ register UBYTE *p; /* Points to place from which to copy. */ register UWORD lenmt; /* Length of copy item minus three. */ register UBYTE **p_hte; /* Pointer to current hash table entry.*/ register UBYTE *p_ziv=p_dst; /* Pointer to start of current Ziv. */ /* Read and dismantle the copy word. Work out from where to copy. */ lenmt=*p_src++; p_hte=&hash[((lenmt&0xF0)<<4)|*p_src++]; p=*p_hte; lenmt&=0xF; /* Now perform the copy using a half unrolled loop. */ *p_dst++=*p++; *p_dst++=*p++; *p_dst++=*p++; while (lenmt--) *p_dst++=*p++; /* Because we have just received 3 or more bytes in a copy item */ /* (whose bytes we have just installed in the output), we are now */ /* in a position to flush all the pending literal hashings that had */ /* been postponed for lack of bytes. */ if (literals>0) { register UBYTE *r=p_ziv-literals; hash[HASH(r)]=r; if (literals==2) {r++; hash[HASH(r)]=r;} literals=0; } /* In any case, we can immediately update the hash table with the */ /* current position. We don't need to do a HASH(...) to work out */ /* where to put the pointer, as the compressor just told us!!! */ *p_hte=p_ziv; } else { /* Literal item. */ /* Copy over the literal byte. */ *p_dst++=*p_src++; /* If we now have three literals waiting to be hashed into the hash */ /* table, we can do one of them now (because there are three). */ if (++literals == 3) {register UBYTE *p=p_dst-3; hash[HASH(p)]=p; literals=2;} } /* Shift the control buffer so the next control bit is in bit 0. */ control>>=1;#if 1 if (p_dst > p_dst_post) { /* Shit: we tried to decompress corrupt data */ *p_dst_len = 0; return; }#endif } /* End unrolled inner loop. */ } /* End of outer loop */ /* Write the length of the decompressed data before returning. */ *p_dst_len=p_dst-p_dst_first;}/******************************************************************************//* End of LZRW3.C *//******************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -