File indexing completed on 2025-02-02 04:26:01

0001 /* Copyright 2015 the unarr project authors (see AUTHORS file).
0002    License: LGPLv3 */
0003 
0004 /* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/LZSS.h */
0005 
0006 #ifndef rar_lzss_h
0007 #define rar_lzss_h
0008 
0009 #include <stdlib.h>
0010 #include <stdint.h>
0011 #include <stdbool.h>
0012 #include <string.h>
0013 
0014 #if defined(_MSC_VER) && !defined(inline)
0015 #define inline __inline
0016 #endif
0017 
0018 typedef struct {
0019     uint8_t *window;
0020     int mask;
0021     int64_t position;
0022 } LZSS;
0023 
0024 static inline int64_t lzss_position(LZSS *self) { return self->position; }
0025 
0026 static inline int lzss_mask(LZSS *self) { return self->mask; }
0027 
0028 static inline int lzss_size(LZSS *self) { return self->mask + 1; }
0029 
0030 static inline uint8_t *lzss_window_pointer(LZSS *self) { return self->window; }
0031 
0032 static inline int lzss_offset_for_position(LZSS *self, int64_t pos) { return (int)(pos & self->mask); }
0033 
0034 static inline uint8_t *lzss_window_pointer_for_position(LZSS *self, int64_t pos) { return &self->window[lzss_offset_for_position(self, pos)]; }
0035 
0036 static inline int lzss_current_window_offset(LZSS *self) { return lzss_offset_for_position(self, self->position); }
0037 
0038 static inline uint8_t *lzss_current_window_pointer(LZSS *self) { return lzss_window_pointer_for_position(self, self->position); }
0039 
0040 static inline int64_t lzss_next_window_edge_after_position(LZSS *self, int64_t pos) { return (pos + lzss_size(self)) & ~(int64_t)lzss_mask(self); }
0041 
0042 static inline int64_t lzss_next_window_edge(LZSS *self) { return lzss_next_window_edge_after_position(self, self->position); }
0043 
0044 static inline uint8_t lzss_get_byte_from_window(LZSS *self, int64_t pos) { return *lzss_window_pointer_for_position(self, pos); }
0045 
0046 static inline void lzss_emit_literal(LZSS *self, uint8_t literal) {
0047     /* self->window[(self->position & self->mask)] = literal; */
0048     *lzss_current_window_pointer(self) = literal;
0049     self->position++;
0050 }
0051 
0052 static inline void lzss_emit_match(LZSS *self, int offset, int length) {
0053     int windowoffs = lzss_current_window_offset(self);
0054     int i;
0055     for (i = 0; i < length; i++) {
0056         self->window[(windowoffs + i) & lzss_mask(self)] = self->window[(windowoffs + i - offset) & lzss_mask(self)];
0057     }
0058     self->position += length;
0059 }
0060 
0061 static inline void lzss_copy_bytes_from_window(LZSS *self, uint8_t *buffer, int64_t startpos, int length) {
0062     int windowoffs = lzss_offset_for_position(self, startpos);
0063     int firstpart = lzss_size(self) - windowoffs;
0064     if (length <= firstpart) {
0065         /* Request fits inside window */
0066         memcpy(buffer, &self->window[windowoffs], length);
0067     }
0068     else {
0069         /* Request wraps around window */
0070         memcpy(buffer, &self->window[windowoffs], firstpart);
0071         memcpy(buffer + firstpart, &self->window[0], length - firstpart);
0072     }
0073 }
0074 
0075 static inline bool lzss_initialize(LZSS *self, int windowsize) {
0076     self->window = malloc(windowsize);
0077     if (!self->window)
0078         return false;
0079 
0080     self->mask = windowsize - 1; /* Assume windows are power-of-two sized! */
0081     memset(self->window, 0, lzss_size(self));
0082     self->position = 0;
0083     return true;
0084 }
0085 
0086 static inline void lzss_cleanup(LZSS *self) { free(self->window); }
0087 
0088 #endif