#ifndef __DEFLATE_READER_H__ #define __DEFLATE_READER_H__ #include #include #include "BitStreamReader.h" typedef struct DeflateReader DeflateReader; typedef void DeflateInputFunction(DeflateReader *self,void *context); struct DeflateReader { BitStreamReader bitstream; uint32_t pos; bool isstoredblock,islastblock; int storedbytesleft; uint8_t window[32768]; uint16_t literalcode[32768],distancecode[32768]; }; static void InitializeDeflateReader(DeflateReader *self); static void SetDeflateInputCallback(DeflateReader *self,DeflateInputFunction *callback,void *context); static void ProvideDeflateInputBuffer(DeflateReader *self,const void *bytes,size_t length); static bool ReadDeflateStreamToPosition(DeflateReader *self,uint32_t pos); static bool ReadDeflateCode(DeflateReader *self); static bool ReadDeflateBlockHeader(DeflateReader *self); static bool ReadDeflateMetaCode(DeflateReader *self,uint16_t *table,int size); static void InitializeDeflateFixedLiteralCode(uint16_t *table); static void InitializeDeflateFixedDistanceCode(uint16_t *table); static void OutputDeflateLiteral(DeflateReader *self,uint8_t literal); static void OutputDeflateMatch(DeflateReader *self,int offset,int length); static uint32_t DeflateStreamPosition(DeflateReader *self); static uint8_t ByteFromDeflateWindow(DeflateReader *self,uint32_t pos); static void CopyBytesFromDeflateWindow(DeflateReader *self,void *destination,uint32_t pos,uint32_t length); static void InitializeDeflateReader(DeflateReader *self) { InitializeBitStreamReader(&self->bitstream); self->pos=0; self->isstoredblock=true; // This will trigger a header read. self->islastblock=false; self->storedbytesleft=0; } static void SetDeflateInputCallback(DeflateReader *self,DeflateInputFunction *callback,void *context) { SetBitStreamInputCallback(&self->bitstream,(BitStreamInputFunction *)callback,context); } static void ProvideDeflateInputBuffer(DeflateReader *self,const void *bytes,size_t length) { ProvideBitStreamInputBuffer(&self->bitstream,bytes,length); } static bool ReadDeflateStreamToPosition(DeflateReader *self,uint32_t pos) { while(DeflateStreamPosition(self)isstoredblock) { if(self->storedbytesleft>0) { self->storedbytesleft--; OutputDeflateLiteral(self,ReadBitString(&self->bitstream,8)); // Could be faster. } else { if(self->islastblock) return false; if(!ReadDeflateBlockHeader(self)) return false; } } else { int literal=ReadHuffmanCode(&self->bitstream,self->literalcode,15); if(literal<0) return false; if(literal<256) { OutputDeflateLiteral(self,literal); } else if(literal==256) { if(self->islastblock) return false; // Should set a flag to block future calls? if(!ReadDeflateBlockHeader(self)) return false; // Also here. } else { int length; if(literal<265) length=literal-254; else if(literal<285) { static const int baselengths[]={11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227}; int size=(literal-261)/4; length=baselengths[literal-265]+ReadBitString(&self->bitstream,size); } else // literal==285 { length=258; } int distcode=ReadHuffmanCode(&self->bitstream,self->distancecode,15); if(distcode<0) return false; int offset; if(distcode<4) offset=distcode+1; else { static const int baseoffsets[]={5,7,9,13,17,25,33,49,65,97,129,193,257, 385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,32769,49153}; int size=(distcode-2)/2; offset=baseoffsets[distcode-4]+ReadBitString(&self->bitstream,size); } OutputDeflateMatch(self,offset,length); } } return true; } static bool ReadDeflateBlockHeader(DeflateReader *self) { self->islastblock=ReadBitString(&self->bitstream,1); int type=ReadBitString(&self->bitstream,2); if(type<0) return false; switch(type) { case 0: // Stored. { FlushBitStream(&self->bitstream); int count=ReadBitString(&self->bitstream,16); int count2=ReadBitString(&self->bitstream,16); if(count!=(count2^0xffff)) return false; self->storedbytesleft=count; self->isstoredblock=true; } break; case 1: // Fixed Huffman. InitializeDeflateFixedLiteralCode(self->literalcode); InitializeDeflateFixedDistanceCode(self->distancecode); self->isstoredblock=false; break; case 2: // Dynamic Huffman. { int numliterals=ReadBitString(&self->bitstream,5)+257; int numdistances=ReadBitString(&self->bitstream,5)+1; int nummetas=ReadBitString(&self->bitstream,4)+4; uint16_t metacode[128]; if(!ReadDeflateMetaCode(self,metacode,nummetas)) return false; int total=numliterals+numdistances; int lengths[total]; int i=0; while(ibitstream,metacode,7); if(val<0) return false; if(val<16) { lengths[i++]=val; } else if(val==16) { int repeats=ReadBitString(&self->bitstream,2)+3; if(i==0||i+repeats>total) return false; for(int j=0;jbitstream,3)+3; else repeats=ReadBitString(&self->bitstream,7)+11; if(i+repeats>total) return false; for(int j=0;jliteralcode,15,lengths,numliterals)) return false; if(!BuildHuffmanTableFromLengths(self->distancecode,15,lengths+numliterals,numdistances)) return false; self->isstoredblock=false; } break; default: return false; } return true; } static bool ReadDeflateMetaCode(DeflateReader *self,uint16_t *table,int size) { static const int order[19]={16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; int lengths[19]; for(int i=0;ibitstream,3); for(int i=size;i<19;i++) lengths[order[i]]=0; return BuildHuffmanTableFromLengths(table,7,lengths,19); } static void InitializeDeflateFixedLiteralCode(uint16_t *table) { int lengths[288]; for(int i=0;i<144;i++) lengths[i]=8; for(int i=144;i<256;i++) lengths[i]=9; for(int i=256;i<280;i++) lengths[i]=7; for(int i=280;i<288;i++) lengths[i]=8; BuildHuffmanTableFromLengths(table,15,lengths,288); } static void InitializeDeflateFixedDistanceCode(uint16_t *table) { int lengths[32]; for(int i=0;i<32;i++) lengths[i]=5; BuildHuffmanTableFromLengths(table,15,lengths,32); } static void OutputDeflateLiteral(DeflateReader *self,uint8_t literal) { self->window[self->pos&0x7fff]=literal; self->pos++; } static void OutputDeflateMatch(DeflateReader *self,int offset,int length) { for(int i=0;iwindow[(self->pos+i)&0x7fff]=self->window[(self->pos-offset+i)&0x7fff]; self->pos+=length; } static inline uint32_t DeflateStreamPosition(DeflateReader *self) { return self->pos; } static inline uint8_t ByteFromDeflateWindow(DeflateReader *self,uint32_t pos) { return self->window[pos&0x7fff]; } static void CopyBytesFromDeflateWindow(DeflateReader *self,void *destination,uint32_t pos,uint32_t length) { uint32_t start=pos&0x7fff; if(start+length>0x8000) { uint32_t firstlength=0x8000-start; memcpy(destination,&self->window[start],firstlength); memcpy((uint8_t *)destination+firstlength,&self->window[0],length-firstlength); } else { memcpy(destination,&self->window[start],length); } } #endif