Loading commands/system/CMakeLists.txt +1 −1 Changes for commands/system/CMakeLists.txt: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -34,4 +34,4 @@ target_sources(fresh PRIVATE set(FRESH_APPLETS ${FRESH_APPLETS} uname whoami hostname id date sleep env true false clear kill mount umount mknod switch_root cpio mkinitramfs losetup blkid halt reboot poweroff sysctl swapon swapoff pivot_root fsck mkswap hwclock ps tar gzip xz nproc PARENT_SCOPE) halt reboot poweroff sysctl swapon swapoff pivot_root fsck mkswap hwclock ps tar gzip gunzip zcat xz nproc PARENT_SCOPE) commands/system/deflate.h 0 → 100644 +383 −0 Changes for commands/system/deflate.h: 383 added lines, 0 removed lines. Original line number Diff line number Diff line /******************************************************************************* Copyright (c) 2026, Jan Koester jan.koester@gmx.net All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the <organization> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #pragma once // DEFLATE compressor (RFC 1951): LZ77 over a 32 KiB window with hash // chains (lazy matching from level 4 on), each block emitted as whichever // of dynamic Huffman, fixed Huffman or stored is smallest. Levels 1-9 set // how hard the match search tries, like gzip's. #include <vector> #include <queue> #include <algorithm> #include <cstdint> #include <cstring> namespace fresh { namespace deflate { struct BitWriter { std::vector<unsigned char> &out; uint64_t buf=0; int count=0; explicit BitWriter(std::vector<unsigned char> &o):out(o){} void bits(uint32_t v,int n){ buf|=(uint64_t)v<<count; count+=n; while(count>=8){ out.push_back((unsigned char)buf); buf>>=8; count-=8; } } void align(){ if(count>0) bits(0,8-count); } }; static const int lenBase[29]={3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258}; static const int lenExtra[29]={0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; static const int distBase[30]={1,2,3,4,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}; static const int distExtra[30]={0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static const int clOrder[19]={16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; inline int lengthCode(int len){ int c=0; while(c<28 && lenBase[c+1]<=len) ++c; return c; } inline int distCode(int dist){ int c=0; while(c<29 && distBase[c+1]<=dist) ++c; return c; } // code lengths (<= maxLen) for the given symbol frequencies: a // Huffman tree, clamped to maxLen and rebalanced to a complete code // (zlib's inflate rejects incomplete literal/length codes) inline std::vector<int> codeLengths(const std::vector<uint32_t> &freq,int maxLen){ int n=(int)freq.size(); std::vector<int> len(n,0); std::vector<int> used; for(int i=0;i<n;++i) if(freq[i]) used.push_back(i); if(used.empty()) return len; if(used.size()==1){ // one symbol: a second dummy one makes the code complete len[used[0]]=1; len[used[0]==0 ? 1 : 0]=1; return len; } struct Node { uint64_t f; int left,right,sym; }; std::vector<Node> nodes; typedef std::pair<uint64_t,int> Item; std::priority_queue<Item,std::vector<Item>,std::greater<Item>> pq; for(int s: used){ nodes.push_back({freq[s],-1,-1,s}); pq.push({freq[s],(int)nodes.size()-1}); } while(pq.size()>1){ Item a=pq.top(); pq.pop(); Item b=pq.top(); pq.pop(); nodes.push_back({a.first+b.first,a.second,b.second,-1}); pq.push({a.first+b.first,(int)nodes.size()-1}); } // depths std::vector<std::pair<int,int>> stack{{pq.top().second,0}}; while(!stack.empty()){ auto [idx,d]=stack.back(); stack.pop_back(); const Node &nd=nodes[idx]; if(nd.sym>=0){ len[nd.sym]=d ? d : 1; continue; } stack.push_back({nd.left,d+1}); stack.push_back({nd.right,d+1}); } // clamp, then restore the Kraft sum to exactly 2^maxLen const uint64_t full=1ull<<maxLen; uint64_t kraft=0; for(int s: used){ if(len[s]>maxLen) len[s]=maxLen; kraft+=1ull<<(maxLen-len[s]); } // over-subscribed: lengthen the longest codes still below maxLen while(kraft>full){ int best=-1; for(int s: used) if(len[s]<maxLen && (best<0 || len[s]>len[best])) best=s; kraft-=1ull<<(maxLen-len[best]-1); ++len[best]; } // incomplete: shorten codes, most frequent first, while it fits if(kraft<full){ std::vector<int> order=used; std::sort(order.begin(),order.end(),[&](int a,int b){ return freq[a]>freq[b]; }); bool changed=true; while(kraft<full && changed){ changed=false; for(int s: order){ if(len[s]>1 && kraft+(1ull<<(maxLen-len[s]))<=full){ kraft+=1ull<<(maxLen-len[s]); --len[s]; changed=true; if(kraft==full) break; } } } } return len; } // canonical codes, bit-reversed for LSB-first output inline std::vector<uint32_t> canonicalCodes(const std::vector<int> &len){ int maxLen=0; for(int l: len) maxLen=std::max(maxLen,l); std::vector<int> count(maxLen+1,0); for(int l: len) if(l) ++count[l]; std::vector<uint32_t> next(maxLen+2,0); uint32_t code=0; for(int b=1;b<=maxLen;++b){ code=(code+count[b-1])<<1; next[b]=code; } std::vector<uint32_t> codes(len.size(),0); for(size_t s=0;s<len.size();++s){ int l=len[s]; if(!l) continue; uint32_t c=next[l]++,r=0; for(int k=0;k<l;++k){ r=(r<<1)|(c&1); c>>=1; } codes[s]=r; } return codes; } struct Token { uint16_t litOrLen; uint16_t dist; }; // dist 0: literal class Compressor { public: explicit Compressor(int level):_level(level<1 ? 1 : level>9 ? 9 : level){} void compress(const unsigned char *data,size_t n,std::vector<unsigned char> &out){ BitWriter bw(out); static const int chains[10]={0,4,8,16,32,64,128,256,1024,4096}; int maxChain=chains[_level]; int nice=_level>=8 ? 258 : _level>=6 ? 128 : _level>=4 ? 64 : 32; bool lazy=_level>=4; const int WSIZE=32768,HBITS=15,HSIZE=1<<HBITS; std::vector<int> head(HSIZE,-1),prev(WSIZE,-1); auto hash=[&](size_t i)->uint32_t{ return ((uint32_t)data[i]<<10 ^ (uint32_t)data[i+1]<<5 ^ data[i+2])&(HSIZE-1); }; auto insert=[&](size_t i){ if(i+2>=n) return; uint32_t h=hash(i); prev[i&(WSIZE-1)]=head[h]; head[h]=(int)i; }; auto longest=[&](size_t i,int &bestDist)->int{ if(i+2>=n) return 0; int best=0,chain=maxChain; int cand=head[hash(i)]; size_t maxLen=std::min<size_t>(258,n-i); while(cand>=0 && chain-->0){ size_t c=(size_t)cand; if(i-c>(size_t)WSIZE-1) break; if(data[c+best]==data[i+best] && data[c]==data[i]){ size_t l=0; while(l<maxLen && data[c+l]==data[i+l]) ++l; if((int)l>best){ best=(int)l; bestDist=(int)(i-c); if(best>=nice || (size_t)best>=maxLen) break; } } int nx=prev[c&(WSIZE-1)]; if(nx>=cand) break; cand=nx; } return best>=3 ? best : 0; }; std::vector<Token> tokens; size_t blockStart=0; size_t i=0; while(i<n){ int dist=0; int len=longest(i,dist); if(len && lazy && len<nice && i+1<n){ insert(i); int d2=0; int l2=longest(i+1,d2); if(l2>len){ tokens.push_back({data[i],0}); ++i; len=l2; dist=d2; }else{ // i already inserted tokens.push_back({(uint16_t)len,(uint16_t)dist}); for(size_t k=1;k<(size_t)len;++k) insert(i+k); i+=len; goto flushCheck; } } if(len){ tokens.push_back({(uint16_t)len,(uint16_t)dist}); for(size_t k=0;k<(size_t)len;++k) insert(i+k); i+=len; }else{ tokens.push_back({data[i],0}); insert(i); ++i; } flushCheck: if(tokens.size()>=16384){ writeBlock(bw,tokens,data+blockStart,i-blockStart,false); tokens.clear(); blockStart=i; } } writeBlock(bw,tokens,data+blockStart,n-blockStart,true); bw.align(); } private: int _level; static void writeStored(BitWriter &bw,const unsigned char *raw,size_t n,bool final){ size_t off=0; do{ size_t chunk=std::min<size_t>(65535,n-off); bool last=final && off+chunk==n; bw.bits(last ? 1 : 0,1); bw.bits(0,2); bw.align(); bw.bits((uint32_t)chunk,16); bw.bits((uint32_t)(~chunk)&0xffff,16); bw.out.insert(bw.out.end(),raw+off,raw+off+chunk); off+=chunk; }while(off<n); } static void writeTokens(BitWriter &bw,const std::vector<Token> &tokens, const std::vector<int> &ll,const std::vector<uint32_t> &lc, const std::vector<int> &dl,const std::vector<uint32_t> &dc){ for(const Token &t: tokens){ if(!t.dist){ bw.bits(lc[t.litOrLen],ll[t.litOrLen]); continue; } int c=lengthCode(t.litOrLen); bw.bits(lc[257+c],ll[257+c]); if(lenExtra[c]) bw.bits(t.litOrLen-lenBase[c],lenExtra[c]); int d=distCode(t.dist); bw.bits(dc[d],dl[d]); if(distExtra[d]) bw.bits(t.dist-distBase[d],distExtra[d]); } bw.bits(lc[256],ll[256]); } static uint64_t tokenBits(const std::vector<Token> &tokens,const std::vector<int> &ll,const std::vector<int> &dl){ uint64_t b=ll[256]; for(const Token &t: tokens){ if(!t.dist){ b+=ll[t.litOrLen]; continue; } int c=lengthCode(t.litOrLen),d=distCode(t.dist); b+=ll[257+c]+lenExtra[c]+dl[d]+distExtra[d]; } return b; } void writeBlock(BitWriter &bw,const std::vector<Token> &tokens,const unsigned char *raw,size_t rawLen,bool final){ std::vector<uint32_t> lf(286,0),df(30,0); for(const Token &t: tokens){ if(!t.dist) ++lf[t.litOrLen]; else { ++lf[257+lengthCode(t.litOrLen)]; ++df[distCode(t.dist)]; } } lf[256]=1; std::vector<int> ll=codeLengths(lf,15),dl=codeLengths(df,15); if(std::all_of(dl.begin(),dl.end(),[](int l){ return l==0; })){ dl[0]=1; dl[1]=1; } // header: trim trailing zero lengths, run-length code them int hlit=286; while(hlit>257 && ll[hlit-1]==0) --hlit; int hdist=30; while(hdist>1 && dl[hdist-1]==0) --hdist; std::vector<int> all(ll.begin(),ll.begin()+hlit); all.insert(all.end(),dl.begin(),dl.begin()+hdist); std::vector<std::pair<int,int>> rle; // (symbol 0-18, extra value) for(size_t k=0;k<all.size();){ int v=all[k]; size_t run=1; while(k+run<all.size() && all[k+run]==v) ++run; if(v==0 && run>=3){ size_t r=run; while(r>=11){ size_t t=std::min<size_t>(138,r); rle.push_back({18,(int)t-11}); r-=t; } if(r>=3){ rle.push_back({17,(int)r-3}); r=0; } while(r--) rle.push_back({0,0}); }else if(v!=0 && run>=4){ rle.push_back({v,0}); size_t r=run-1; while(r>=3){ size_t t=std::min<size_t>(6,r); rle.push_back({16,(int)t-3}); r-=t; } while(r--) rle.push_back({v,0}); }else{ for(size_t r=0;r<run;++r) rle.push_back({v,0}); } k+=run; } std::vector<uint32_t> cf(19,0); for(auto &e: rle) ++cf[e.first]; std::vector<int> cl=codeLengths(cf,7); int hclen=19; while(hclen>4 && cl[clOrder[hclen-1]]==0) --hclen; uint64_t dynBits=3+5+5+4+3*hclen; for(auto &e: rle) dynBits+=cl[e.first]+(e.first==16 ? 2 : e.first==17 ? 3 : e.first==18 ? 7 : 0); dynBits+=tokenBits(tokens,ll,dl); std::vector<int> fl(288),fd(30,5); for(int k=0;k<144;++k) fl[k]=8; for(int k=144;k<256;++k) fl[k]=9; for(int k=256;k<280;++k) fl[k]=7; for(int k=280;k<288;++k) fl[k]=8; uint64_t fixBits=3+tokenBits(tokens,fl,fd); uint64_t storedBits=(rawLen/65535+1)*40+rawLen*8+8; if(storedBits<=dynBits && storedBits<=fixBits){ writeStored(bw,raw,rawLen,final); }else if(fixBits<=dynBits){ bw.bits(final ? 1 : 0,1); bw.bits(1,2); writeTokens(bw,tokens,fl,canonicalCodes(fl),fd,canonicalCodes(fd)); }else{ bw.bits(final ? 1 : 0,1); bw.bits(2,2); bw.bits(hlit-257,5); bw.bits(hdist-1,5); bw.bits(hclen-4,4); for(int k=0;k<hclen;++k) bw.bits(cl[clOrder[k]],3); std::vector<uint32_t> cc=canonicalCodes(cl); for(auto &e: rle){ bw.bits(cc[e.first],cl[e.first]); if(e.first==16) bw.bits(e.second,2); else if(e.first==17) bw.bits(e.second,3); else if(e.first==18) bw.bits(e.second,7); } writeTokens(bw,tokens,ll,canonicalCodes(ll),dl,canonicalCodes(dl)); } } }; inline uint32_t crc32(uint32_t crc,const unsigned char *p,size_t n){ static uint32_t table[256]; static bool init=false; if(!init){ for(uint32_t i=0;i<256;++i){ uint32_t c=i; for(int k=0;k<8;++k) c=(c&1) ? 0xedb88320u^(c>>1) : c>>1; table[i]=c; } init=true; } crc=~crc; for(size_t i=0;i<n;++i) crc=table[(crc^p[i])&0xff]^(crc>>8); return ~crc; } }} commands/system/gzip.cpp +249 −98 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
commands/system/CMakeLists.txt +1 −1 Changes for commands/system/CMakeLists.txt: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -34,4 +34,4 @@ target_sources(fresh PRIVATE set(FRESH_APPLETS ${FRESH_APPLETS} uname whoami hostname id date sleep env true false clear kill mount umount mknod switch_root cpio mkinitramfs losetup blkid halt reboot poweroff sysctl swapon swapoff pivot_root fsck mkswap hwclock ps tar gzip xz nproc PARENT_SCOPE) halt reboot poweroff sysctl swapon swapoff pivot_root fsck mkswap hwclock ps tar gzip gunzip zcat xz nproc PARENT_SCOPE)
commands/system/deflate.h 0 → 100644 +383 −0 Changes for commands/system/deflate.h: 383 added lines, 0 removed lines. Original line number Diff line number Diff line /******************************************************************************* Copyright (c) 2026, Jan Koester jan.koester@gmx.net All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the <organization> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ #pragma once // DEFLATE compressor (RFC 1951): LZ77 over a 32 KiB window with hash // chains (lazy matching from level 4 on), each block emitted as whichever // of dynamic Huffman, fixed Huffman or stored is smallest. Levels 1-9 set // how hard the match search tries, like gzip's. #include <vector> #include <queue> #include <algorithm> #include <cstdint> #include <cstring> namespace fresh { namespace deflate { struct BitWriter { std::vector<unsigned char> &out; uint64_t buf=0; int count=0; explicit BitWriter(std::vector<unsigned char> &o):out(o){} void bits(uint32_t v,int n){ buf|=(uint64_t)v<<count; count+=n; while(count>=8){ out.push_back((unsigned char)buf); buf>>=8; count-=8; } } void align(){ if(count>0) bits(0,8-count); } }; static const int lenBase[29]={3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258}; static const int lenExtra[29]={0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; static const int distBase[30]={1,2,3,4,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}; static const int distExtra[30]={0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static const int clOrder[19]={16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; inline int lengthCode(int len){ int c=0; while(c<28 && lenBase[c+1]<=len) ++c; return c; } inline int distCode(int dist){ int c=0; while(c<29 && distBase[c+1]<=dist) ++c; return c; } // code lengths (<= maxLen) for the given symbol frequencies: a // Huffman tree, clamped to maxLen and rebalanced to a complete code // (zlib's inflate rejects incomplete literal/length codes) inline std::vector<int> codeLengths(const std::vector<uint32_t> &freq,int maxLen){ int n=(int)freq.size(); std::vector<int> len(n,0); std::vector<int> used; for(int i=0;i<n;++i) if(freq[i]) used.push_back(i); if(used.empty()) return len; if(used.size()==1){ // one symbol: a second dummy one makes the code complete len[used[0]]=1; len[used[0]==0 ? 1 : 0]=1; return len; } struct Node { uint64_t f; int left,right,sym; }; std::vector<Node> nodes; typedef std::pair<uint64_t,int> Item; std::priority_queue<Item,std::vector<Item>,std::greater<Item>> pq; for(int s: used){ nodes.push_back({freq[s],-1,-1,s}); pq.push({freq[s],(int)nodes.size()-1}); } while(pq.size()>1){ Item a=pq.top(); pq.pop(); Item b=pq.top(); pq.pop(); nodes.push_back({a.first+b.first,a.second,b.second,-1}); pq.push({a.first+b.first,(int)nodes.size()-1}); } // depths std::vector<std::pair<int,int>> stack{{pq.top().second,0}}; while(!stack.empty()){ auto [idx,d]=stack.back(); stack.pop_back(); const Node &nd=nodes[idx]; if(nd.sym>=0){ len[nd.sym]=d ? d : 1; continue; } stack.push_back({nd.left,d+1}); stack.push_back({nd.right,d+1}); } // clamp, then restore the Kraft sum to exactly 2^maxLen const uint64_t full=1ull<<maxLen; uint64_t kraft=0; for(int s: used){ if(len[s]>maxLen) len[s]=maxLen; kraft+=1ull<<(maxLen-len[s]); } // over-subscribed: lengthen the longest codes still below maxLen while(kraft>full){ int best=-1; for(int s: used) if(len[s]<maxLen && (best<0 || len[s]>len[best])) best=s; kraft-=1ull<<(maxLen-len[best]-1); ++len[best]; } // incomplete: shorten codes, most frequent first, while it fits if(kraft<full){ std::vector<int> order=used; std::sort(order.begin(),order.end(),[&](int a,int b){ return freq[a]>freq[b]; }); bool changed=true; while(kraft<full && changed){ changed=false; for(int s: order){ if(len[s]>1 && kraft+(1ull<<(maxLen-len[s]))<=full){ kraft+=1ull<<(maxLen-len[s]); --len[s]; changed=true; if(kraft==full) break; } } } } return len; } // canonical codes, bit-reversed for LSB-first output inline std::vector<uint32_t> canonicalCodes(const std::vector<int> &len){ int maxLen=0; for(int l: len) maxLen=std::max(maxLen,l); std::vector<int> count(maxLen+1,0); for(int l: len) if(l) ++count[l]; std::vector<uint32_t> next(maxLen+2,0); uint32_t code=0; for(int b=1;b<=maxLen;++b){ code=(code+count[b-1])<<1; next[b]=code; } std::vector<uint32_t> codes(len.size(),0); for(size_t s=0;s<len.size();++s){ int l=len[s]; if(!l) continue; uint32_t c=next[l]++,r=0; for(int k=0;k<l;++k){ r=(r<<1)|(c&1); c>>=1; } codes[s]=r; } return codes; } struct Token { uint16_t litOrLen; uint16_t dist; }; // dist 0: literal class Compressor { public: explicit Compressor(int level):_level(level<1 ? 1 : level>9 ? 9 : level){} void compress(const unsigned char *data,size_t n,std::vector<unsigned char> &out){ BitWriter bw(out); static const int chains[10]={0,4,8,16,32,64,128,256,1024,4096}; int maxChain=chains[_level]; int nice=_level>=8 ? 258 : _level>=6 ? 128 : _level>=4 ? 64 : 32; bool lazy=_level>=4; const int WSIZE=32768,HBITS=15,HSIZE=1<<HBITS; std::vector<int> head(HSIZE,-1),prev(WSIZE,-1); auto hash=[&](size_t i)->uint32_t{ return ((uint32_t)data[i]<<10 ^ (uint32_t)data[i+1]<<5 ^ data[i+2])&(HSIZE-1); }; auto insert=[&](size_t i){ if(i+2>=n) return; uint32_t h=hash(i); prev[i&(WSIZE-1)]=head[h]; head[h]=(int)i; }; auto longest=[&](size_t i,int &bestDist)->int{ if(i+2>=n) return 0; int best=0,chain=maxChain; int cand=head[hash(i)]; size_t maxLen=std::min<size_t>(258,n-i); while(cand>=0 && chain-->0){ size_t c=(size_t)cand; if(i-c>(size_t)WSIZE-1) break; if(data[c+best]==data[i+best] && data[c]==data[i]){ size_t l=0; while(l<maxLen && data[c+l]==data[i+l]) ++l; if((int)l>best){ best=(int)l; bestDist=(int)(i-c); if(best>=nice || (size_t)best>=maxLen) break; } } int nx=prev[c&(WSIZE-1)]; if(nx>=cand) break; cand=nx; } return best>=3 ? best : 0; }; std::vector<Token> tokens; size_t blockStart=0; size_t i=0; while(i<n){ int dist=0; int len=longest(i,dist); if(len && lazy && len<nice && i+1<n){ insert(i); int d2=0; int l2=longest(i+1,d2); if(l2>len){ tokens.push_back({data[i],0}); ++i; len=l2; dist=d2; }else{ // i already inserted tokens.push_back({(uint16_t)len,(uint16_t)dist}); for(size_t k=1;k<(size_t)len;++k) insert(i+k); i+=len; goto flushCheck; } } if(len){ tokens.push_back({(uint16_t)len,(uint16_t)dist}); for(size_t k=0;k<(size_t)len;++k) insert(i+k); i+=len; }else{ tokens.push_back({data[i],0}); insert(i); ++i; } flushCheck: if(tokens.size()>=16384){ writeBlock(bw,tokens,data+blockStart,i-blockStart,false); tokens.clear(); blockStart=i; } } writeBlock(bw,tokens,data+blockStart,n-blockStart,true); bw.align(); } private: int _level; static void writeStored(BitWriter &bw,const unsigned char *raw,size_t n,bool final){ size_t off=0; do{ size_t chunk=std::min<size_t>(65535,n-off); bool last=final && off+chunk==n; bw.bits(last ? 1 : 0,1); bw.bits(0,2); bw.align(); bw.bits((uint32_t)chunk,16); bw.bits((uint32_t)(~chunk)&0xffff,16); bw.out.insert(bw.out.end(),raw+off,raw+off+chunk); off+=chunk; }while(off<n); } static void writeTokens(BitWriter &bw,const std::vector<Token> &tokens, const std::vector<int> &ll,const std::vector<uint32_t> &lc, const std::vector<int> &dl,const std::vector<uint32_t> &dc){ for(const Token &t: tokens){ if(!t.dist){ bw.bits(lc[t.litOrLen],ll[t.litOrLen]); continue; } int c=lengthCode(t.litOrLen); bw.bits(lc[257+c],ll[257+c]); if(lenExtra[c]) bw.bits(t.litOrLen-lenBase[c],lenExtra[c]); int d=distCode(t.dist); bw.bits(dc[d],dl[d]); if(distExtra[d]) bw.bits(t.dist-distBase[d],distExtra[d]); } bw.bits(lc[256],ll[256]); } static uint64_t tokenBits(const std::vector<Token> &tokens,const std::vector<int> &ll,const std::vector<int> &dl){ uint64_t b=ll[256]; for(const Token &t: tokens){ if(!t.dist){ b+=ll[t.litOrLen]; continue; } int c=lengthCode(t.litOrLen),d=distCode(t.dist); b+=ll[257+c]+lenExtra[c]+dl[d]+distExtra[d]; } return b; } void writeBlock(BitWriter &bw,const std::vector<Token> &tokens,const unsigned char *raw,size_t rawLen,bool final){ std::vector<uint32_t> lf(286,0),df(30,0); for(const Token &t: tokens){ if(!t.dist) ++lf[t.litOrLen]; else { ++lf[257+lengthCode(t.litOrLen)]; ++df[distCode(t.dist)]; } } lf[256]=1; std::vector<int> ll=codeLengths(lf,15),dl=codeLengths(df,15); if(std::all_of(dl.begin(),dl.end(),[](int l){ return l==0; })){ dl[0]=1; dl[1]=1; } // header: trim trailing zero lengths, run-length code them int hlit=286; while(hlit>257 && ll[hlit-1]==0) --hlit; int hdist=30; while(hdist>1 && dl[hdist-1]==0) --hdist; std::vector<int> all(ll.begin(),ll.begin()+hlit); all.insert(all.end(),dl.begin(),dl.begin()+hdist); std::vector<std::pair<int,int>> rle; // (symbol 0-18, extra value) for(size_t k=0;k<all.size();){ int v=all[k]; size_t run=1; while(k+run<all.size() && all[k+run]==v) ++run; if(v==0 && run>=3){ size_t r=run; while(r>=11){ size_t t=std::min<size_t>(138,r); rle.push_back({18,(int)t-11}); r-=t; } if(r>=3){ rle.push_back({17,(int)r-3}); r=0; } while(r--) rle.push_back({0,0}); }else if(v!=0 && run>=4){ rle.push_back({v,0}); size_t r=run-1; while(r>=3){ size_t t=std::min<size_t>(6,r); rle.push_back({16,(int)t-3}); r-=t; } while(r--) rle.push_back({v,0}); }else{ for(size_t r=0;r<run;++r) rle.push_back({v,0}); } k+=run; } std::vector<uint32_t> cf(19,0); for(auto &e: rle) ++cf[e.first]; std::vector<int> cl=codeLengths(cf,7); int hclen=19; while(hclen>4 && cl[clOrder[hclen-1]]==0) --hclen; uint64_t dynBits=3+5+5+4+3*hclen; for(auto &e: rle) dynBits+=cl[e.first]+(e.first==16 ? 2 : e.first==17 ? 3 : e.first==18 ? 7 : 0); dynBits+=tokenBits(tokens,ll,dl); std::vector<int> fl(288),fd(30,5); for(int k=0;k<144;++k) fl[k]=8; for(int k=144;k<256;++k) fl[k]=9; for(int k=256;k<280;++k) fl[k]=7; for(int k=280;k<288;++k) fl[k]=8; uint64_t fixBits=3+tokenBits(tokens,fl,fd); uint64_t storedBits=(rawLen/65535+1)*40+rawLen*8+8; if(storedBits<=dynBits && storedBits<=fixBits){ writeStored(bw,raw,rawLen,final); }else if(fixBits<=dynBits){ bw.bits(final ? 1 : 0,1); bw.bits(1,2); writeTokens(bw,tokens,fl,canonicalCodes(fl),fd,canonicalCodes(fd)); }else{ bw.bits(final ? 1 : 0,1); bw.bits(2,2); bw.bits(hlit-257,5); bw.bits(hdist-1,5); bw.bits(hclen-4,4); for(int k=0;k<hclen;++k) bw.bits(cl[clOrder[k]],3); std::vector<uint32_t> cc=canonicalCodes(cl); for(auto &e: rle){ bw.bits(cc[e.first],cl[e.first]); if(e.first==16) bw.bits(e.second,2); else if(e.first==17) bw.bits(e.second,3); else if(e.first==18) bw.bits(e.second,7); } writeTokens(bw,tokens,ll,canonicalCodes(ll),dl,canonicalCodes(dl)); } } }; inline uint32_t crc32(uint32_t crc,const unsigned char *p,size_t n){ static uint32_t table[256]; static bool init=false; if(!init){ for(uint32_t i=0;i<256;++i){ uint32_t c=i; for(int k=0;k<8;++k) c=(c&1) ? 0xedb88320u^(c>>1) : c>>1; table[i]=c; } init=true; } crc=~crc; for(size_t i=0;i<n;++i) crc=table[(crc^p[i])&0xff]^(crc>>8); return ~crc; } }}
commands/system/gzip.cpp +249 −98 File changed.Preview size limit exceeded, changes collapsed. Show changes