diff --git a/conatiners.lua b/conatiners.lua new file mode 100644 index 0000000..78dcd88 --- /dev/null +++ b/conatiners.lua @@ -0,0 +1,978 @@ +local deflate = (function () local a;do local b="1.0.2-release"local c="LibDeflate"local d=3;local e="LibDeflate "..b.." Copyright (C) 2018-2021 Haoqian He.".." Licensed under the zlib License"if LibStub then local f,g=LibStub:GetLibrary(c,true)if f and g and g>=d then return f else a=LibStub:NewLibrary(c,d)end else a={}end;a._VERSION=b;a._MAJOR=c;a._MINOR=d;a._COPYRIGHT=e end;local assert=assert;local error=error;local pairs=pairs;local h=string.byte;local i=string.char;local j=string.find;local k=string.gsub;local l=string.sub;local m=table.concat;local n=table.sort;local tostring=tostring;local type=type;local o={}local p={}local q={}local r={}local s={}local t={}local u={}local v={}local w={}local x={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}local y={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}local z={[0]=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}local A={[0]=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}local B={16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}local C;local D;local E;local F;local G;local H;local I;local J;for K=0,255 do p[K]=i(K)end;do local L=1;for K=0,32 do o[K]=L;L=L*2 end end;for K=1,9 do q[K]={}for M=0,o[K+1]-1 do local N=0;local O=M;for P=1,K do N=N-N%2+((N%2==1 or O%2==1)and 1 or 0)O=(O-O%2)/2;N=N*2 end;q[K][M]=(N-N%2)/2 end end;do local Q=18;local R=16;local S=265;local T=1;for U=3,258 do if U<=10 then r[U]=U+254;t[U]=0 elseif U==258 then r[U]=285;t[U]=0 else if U>Q then Q=Q+R;R=R*2;S=S+4;T=T+1 end;local V=U-Q-1+R/2;r[U]=(V-V%(R/8))/(R/8)+S;t[U]=T;s[U]=V%(R/8)end end end;do u[1]=0;u[2]=1;w[1]=0;w[2]=0;local Q=3;local R=4;local W=2;local T=0;for X=3,256 do if X>R then Q=Q*2;R=R*2;W=W+2;T=T+1 end;u[X]=X<=Q and W or W+1;w[X]=T<0 and 0 or T;if R>=8 then v[X]=(X-R/2-1)%(R/4)end end end;function a:Adler32(Y)if type(Y)~="string"then error(("Usage: LibDeflate:Adler32(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;local Z=#Y;local K=1;local Q=1;local R=0;while K<=Z-15 do local _,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac,ad,ae=h(Y,K,K+15)R=(R+16*Q+16*_+15*a0+14*a1+13*a2+12*a3+11*a4+10*a5+9*a6+8*a7+7*a8+6*a9+5*aa+4*ab+3*ac+2*ad+ae)%65521;Q=(Q+_+a0+a1+a2+a3+a4+a5+a6+a7+a8+a9+aa+ab+ac+ad+ae)%65521;K=K+16 end;while K<=Z do local af=h(Y,K,K)Q=(Q+af)%65521;R=(R+Q)%65521;K=K+1 end;return(R*65536+Q)%4294967296 end;local function ag(ah,ai)return ah%4294967296==ai%4294967296 end;function a:CreateDictionary(Y,Z,aj)if type(Y)~="string"then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;if type(Z)~="number"then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'strlen\' - number expected got \'%s\'."):format(type(Z)),2)end;if type(aj)~="number"then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'adler32\' - number expected got \'%s\'."):format(type(aj)),2)end;if Z~=#Y then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'strlen\' does not match the actual length of \'str\'.".." \'strlen\': %u, \'#str\': %u .".." Please check if \'str\' is modified unintentionally."):format(Z,#Y))end;if Z==0 then error("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'str\' - Empty string is not allowed.",2)end;if Z>32768 then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'str\' - string longer than 32768 bytes is not allowed.".." Got %d bytes."):format(Z),2)end;local ak=self:Adler32(Y)if not ag(aj,ak)then error(("Usage: LibDeflate:CreateDictionary(str, strlen, adler32):".." \'adler32\' does not match the actual adler32 of \'str\'.".." \'adler32\': %u, \'Adler32(str)\': %u .".." Please check if \'str\' is modified unintentionally."):format(aj,ak))end;local al={}al.adler32=aj;al.hash_tables={}al.string_table={}al.strlen=Z;local am=al.string_table;local an=al.hash_tables;am[1]=h(Y,1,1)am[2]=h(Y,2,2)if Z>=3 then local K=1;local ao=am[1]*256+am[2]while K<=Z-2-3 do local _,a0,a1,a2=h(Y,K+2,K+5)am[K+2]=_;am[K+3]=a0;am[K+4]=a1;am[K+5]=a2;ao=(ao*256+_)%16777216;local V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1;ao=(ao*256+a0)%16777216;V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1;ao=(ao*256+a1)%16777216;V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1;ao=(ao*256+a2)%16777216;V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1 end;while K<=Z-2 do local af=h(Y,K+2)am[K+2]=af;ao=(ao*256+af)%16777216;local V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=K-Z;K=K+1 end end;return al end;local function ap(al)if type(al)~="table"then return false,("\'dictionary\' - table expected got \'%s\'."):format(type(al))end;if type(al.adler32)~="number"or type(al.string_table)~="table"or type(al.strlen)~="number"or al.strlen<=0 or al.strlen>32768 or al.strlen~=#al.string_table or type(al.hash_tables)~="table"then return false,("\'dictionary\' - corrupted dictionary."):format(type(al))end;return true,""end;local aq={[0]={false,nil,0,0,0},[1]={false,nil,4,8,4},[2]={false,nil,5,18,8},[3]={false,nil,6,32,32},[4]={true,4,4,16,16},[5]={true,8,16,32,32},[6]={true,8,16,128,128},[7]={true,8,32,128,256},[8]={true,32,128,258,1024},[9]={true,32,258,258,4096}}local function ar(Y,as,al,at,au)if type(Y)~="string"then return false,("\'str\' - string expected got \'%s\'."):format(type(Y))end;if as then local av,aw=ap(al)if not av then return false,aw end end;if at then local ax=type(au)if ax~="nil"and ax~="table"then return false,("\'configs\' - nil or table expected got \'%s\'."):format(type(au))end;if ax=="table"then for ay,az in pairs(au)do if ay~="level"and ay~="strategy"then return false,("\'configs\' - unsupported table key in the configs: \'%s\'."):format(ay)elseif ay=="level"and not aq[az]then return false,("\'configs\' - unsupported \'level\': %s."):format(tostring(az))elseif ay=="strategy"and az~="fixed"and az~="huffman_only"and az~="dynamic"then return false,("\'configs\' - unsupported \'strategy\': \'%s\'."):format(tostring(az))end end end end;return true,""end;local aA=0;local aB=1;local aC=2;local aD=3;local function aE()local aF=0;local aG=0;local aH=0;local aI=0;local aJ={}local aK={}local function aL(O,T)aG=aG+O*o[aH]aH=aH+T;aI=aI+T;if aH>=32 then aF=aF+1;aJ[aF]=p[aG%256]..p[(aG-aG%256)/256%256]..p[(aG-aG%65536)/65536%256]..p[(aG-aG%16777216)/16777216%256]local aM=o[32-aH+T]aG=(O-O%aM)/aM;aH=aH-32 end end;local function aN(Y)for P=1,aH,8 do aF=aF+1;aJ[aF]=i(aG%256)aG=(aG-aG%256)/256 end;aH=0;aF=aF+1;aJ[aF]=Y;aI=aI+#Y*8 end;local function aO(aP)if aP==aD then return aI end;if aP==aB or aP==aC then local aQ=(8-aH%8)%8;if aH>0 then aG=aG-o[aH]+o[aH+aQ]for P=1,aH,8 do aF=aF+1;aJ[aF]=p[aG%256]aG=(aG-aG%256)/256 end;aG=0;aH=0 end;if aP==aC then aI=aI+aQ;return aI end end;local aR=m(aJ)aJ={}aF=0;aK[#aK+1]=aR;if aP==aA then return aI else return aI,m(aK)end end;return aL,aN,aO end;local function aS(aT,aU,aV)aV=aV+1;aT[aV]=aU;local O=aU[1]local aW=aV;local aX=(aW-aW%2)/2;while aX>=1 and aT[aX][1]>O do local V=aT[aX]aT[aX]=aU;aT[aW]=V;aW=aX;aX=(aX-aX%2)/2 end end;local function aY(aT,aV)local aZ=aT[1]local aU=aT[aV]local O=aU[1]aT[1]=aU;aT[aV]=aZ;aV=aV-1;local aW=1;local a_=aW*2;local b0=a_+1;while a_<=aV do local b1=aT[a_]if b0<=aV and aT[b0][1]1 do local bk=aY(aT,aV)aV=aV-1;local bl=aY(aT,aV)aV=aV-1;local bm={bk[1]+bl[1],-1,bk,bl}aS(aT,bm,aV)aV=aV+1 end;local bn=0;local bo={aT[1],0,0,0}local bp=1;local bq=1;aT[1][1]=0;while bq<=bp do local aU=bo[bq]local T=aU[1]local bb=aU[2]local b1=aU[3]local b2=aU[4]if b1 then bp=bp+1;bo[bp]=b1;b1[1]=T+1 end;if b2 then bp=bp+1;bo[bp]=b2;b2[1]=T+1 end;bq=bq+1;if T>b7 then bn=bn+1;T=b7 end;if bb>=0 then b5[bb]=T;bf=bb>bf and bb or bf;b4[T]=(b4[T]or 0)+1 end end;if bn>0 then repeat local T=b7-1;while(b4[T]or 0)==0 do T=T-1 end;b4[T]=b4[T]-1;b4[T+1]=(b4[T+1]or 0)+2;b4[b7]=b4[b7]-1;bn=bn-2 until bn<=0;bq=1;for T=b7,1,-1 do local br=b4[T]or 0;while br>0 do local bb=bg[bq][2]b5[bb]=T;br=br-1;bq=bq+1 end end end;bh=b3(b4,b5,b6,b7)return b5,bh,bf end end;local function bs(bt,bu,bv,bw)local bx=0;local by={}local bz={}local bA=0;local bB={}local bC=nil;local bj=0;bw=bw<0 and 0 or bw;local bD=bu+bw+1;for W=0,bD+1 do local U=W<=bu and(bt[W]or 0)or(W<=bD and(bv[W-bu-1]or 0)or nil)if U==bC then bj=bj+1;if U~=0 and bj==6 then bx=bx+1;by[bx]=16;bA=bA+1;bB[bA]=3;bz[16]=(bz[16]or 0)+1;bj=0 elseif U==0 and bj==138 then bx=bx+1;by[bx]=18;bA=bA+1;bB[bA]=127;bz[18]=(bz[18]or 0)+1;bj=0 end else if bj==1 then bx=bx+1;by[bx]=bC;bz[bC]=(bz[bC]or 0)+1 elseif bj==2 then bx=bx+1;by[bx]=bC;bx=bx+1;by[bx]=bC;bz[bC]=(bz[bC]or 0)+2 elseif bj>=3 then bx=bx+1;local bE=bC~=0 and 16 or(bj<=10 and 17 or 18)by[bx]=bE;bz[bE]=(bz[bE]or 0)+1;bA=bA+1;bB[bA]=bj<=10 and bj-3 or bj-11 end;bC=U;if U and U~=0 then bx=bx+1;by[bx]=U;bz[U]=(bz[U]or 0)+1;bj=0 else bj=1 end end end;return by,bB,bz end;local function bF(Y,V,bG,bH,bI)local K=bG-bI;while K<=bH-15-bI do V[K],V[K+1],V[K+2],V[K+3],V[K+4],V[K+5],V[K+6],V[K+7],V[K+8],V[K+9],V[K+10],V[K+11],V[K+12],V[K+13],V[K+14],V[K+15]=h(Y,K+bI,K+15+bI)K=K+16 end;while K<=bH-bI do V[K]=h(Y,K+bI,K+bI)K=K+1 end;return V end;local function bJ(bK,am,an,bL,bM,bI,al)local bN=aq[bK]local bO,bP,bQ,bR,bS=bN[1],bN[2],bN[3],bN[4],bN[5]local bT=not bO and bQ or 2147483646;local bU=bS-bS%4/4;local ao;local bV;local bW;local bX=0;if al then bV=al.hash_tables;bW=al.string_table;bX=al.strlen;assert(bL==1)if bM>=bL and bX>=2 then ao=bW[bX-1]*65536+bW[bX]*256+am[1]local V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=-1 end;if bM>=bL+1 and bX>=1 then ao=bW[bX]*65536+am[1]*256+am[2]local V=an[ao]if not V then V={}an[ao]=V end;V[#V+1]=0 end end;local bY=bX+3;ao=(am[bL-bI]or 0)*256+(am[bL+1-bI]or 0)local bZ={}local b_=0;local c0={}local c1={}local c2=0;local c3={}local c4={}local c5=0;local c6={}local c7=0;local c8=false;local c9;local ca;local cb=0;local cc=0;local bq=bL;local cd=bM+(bO and 1 or 0)while bq<=cd do local ce=bq-bI;local cf=bI-3;c9=cb;ca=cc;cb=0;ao=(ao*256+(am[ce+2]or 0))%16777216;local cg;local ch;local ci=an[ao]local cj;if not ci then cj=0;ci={}an[ao]=ci;if bV then ch=bV[ao]cg=ch and#ch or 0 else cg=0 end else cj=#ci;ch=ci;cg=cj end;if bq<=bM then ci[cj+1]=bq end;if cg>0 and bq+2<=bM and(not bO or c9=bP and bU or bS;local cl=bM-bq;cl=cl>=257 and 257 or cl;cl=cl+ce;local cm=ce+3;while cg>=1 and ck>0 do local bC=ch[cg]if bq-bC>32768 then break end;if bC=-257 then local co=bC-cf;while cn<=cl and am[co]==am[cn]do cn=cn+1;co=co+1 end else local co=bY+bC;while cn<=cl and bW[co]==am[cn]do cn=cn+1;co=co+1 end end;local M=cn-ce;if M>cb then cb=M;cc=bq-bC end;if cb>=bR then break end end;cg=cg-1;ck=ck-1;if cg==0 and bC>0 and bV then ch=bV[ao]cg=ch and#ch or 0 end end end;if not bO then c9,ca=cb,cc end;if(not bO or c8)and(c9>3 or c9==3 and ca<4096)and cb<=c9 then local W=r[c9]local cp=t[c9]local cq,cr,cs;if ca<=256 then cq=u[ca]cs=v[ca]cr=w[ca]else cq=16;cr=7;local Q=384;local R=512;while true do if ca<=Q then cs=(ca-R/2-1)%(R/4)break elseif ca<=R then cs=(ca-R/2-1)%(R/4)cq=cq+1;break else cq=cq+2;cr=cr+1;Q=Q*2;R=R*2 end end end;b_=b_+1;bZ[b_]=W;c0[W]=(c0[W]or 0)+1;c2=c2+1;c1[c2]=cq;c3[cq]=(c3[cq]or 0)+1;if cp>0 then local ct=s[c9]c5=c5+1;c4[c5]=ct end;if cr>0 then c7=c7+1;c6[c7]=cs end;for K=bq+1,bq+c9-(bO and 2 or 1)do ao=(ao*256+(am[K-bI+2]or 0))%16777216;if c9<=bT then ci=an[ao]if not ci then ci={}an[ao]=ci end;ci[#ci+1]=K end end;bq=bq+c9-(bO and 1 or 0)c8=false elseif not bO or c8 then local W=am[bO and ce-1 or ce]b_=b_+1;bZ[b_]=W;c0[W]=(c0[W]or 0)+1;bq=bq+1 else c8=true;bq=bq+1 end end;b_=b_+1;bZ[b_]=256;c0[256]=(c0[256]or 0)+1;return bZ,c4,c0,c1,c6,c3 end;local function cu(c0,c3)local cv,cw,bu=bd(c0,15,285)local cx,cy,bw=bd(c3,15,29)local cz,bB,cA=bs(cv,bu,cx,bw)local cB,cC=bd(cA,7,18)local cD=0;for K=1,19 do local bb=B[K]local cE=cB[bb]or 0;if cE~=0 then cD=K end end;cD=cD-4;local cF=bu+1-257;local cG=bw+1-1;if cG<0 then cG=0 end;return cF,cG,cD,cB,cC,cz,bB,cv,cw,cx,cy end;local function cH(bZ,c1,cD,cB,cz,cv,cx)local cI=17;cI=cI+(cD+4)*3;for K=1,#cz do local W=cz[K]cI=cI+cB[W]if W>=16 then cI=cI+(W==16 and 2 or(W==17 and 3 or 7))end end;local cJ=0;for K=1,#bZ do local W=bZ[K]local cK=cv[W]cI=cI+cK;if W>256 then cJ=cJ+1;if W>264 and W<285 then local cL=y[W-256]cI=cI+cL end;local cq=c1[cJ]local cM=cx[cq]cI=cI+cM;if cq>3 then local cr=(cq-cq%2)/2-1;cI=cI+cr end end end;return cI end;local function cN(aL,cO,bZ,c4,c1,c6,cF,cG,cD,cB,cC,cz,bB,cv,cw,cx,cy)aL(cO and 1 or 0,1)aL(2,2)aL(cF,5)aL(cG,5)aL(cD,4)for K=1,cD+4 do local bb=B[K]local cE=cB[bb]or 0;aL(cE,3)end;local cP=1;for K=1,#cz do local W=cz[K]aL(cC[W],cB[W])if W>=16 then local cQ=bB[cP]aL(cQ,W==16 and 2 or(W==17 and 3 or 7))cP=cP+1 end end;local cJ=0;local cR=0;local cS=0;for K=1,#bZ do local cT=bZ[K]local b8=cw[cT]local cK=cv[cT]aL(b8,cK)if cT>256 then cJ=cJ+1;if cT>264 and cT<285 then cR=cR+1;local cU=c4[cR]local cL=y[cT-256]aL(cU,cL)end;local cV=c1[cJ]local cW=cy[cV]local cM=cx[cV]aL(cW,cM)if cV>3 then cS=cS+1;local cs=c6[cS]local cr=(cV-cV%2)/2-1;aL(cs,cr)end end end end;local function cX(bZ,c1)local cI=3;local cJ=0;for K=1,#bZ do local W=bZ[K]local cK=E[W]cI=cI+cK;if W>256 then cJ=cJ+1;if W>264 and W<285 then local cL=y[W-256]cI=cI+cL end;local cq=c1[cJ]cI=cI+5;if cq>3 then local cr=(cq-cq%2)/2-1;cI=cI+cr end end end;return cI end;local function cY(aL,cO,bZ,c4,c1,c6)aL(cO and 1 or 0,1)aL(1,2)local cJ=0;local cR=0;local cS=0;for K=1,#bZ do local cZ=bZ[K]local b8=C[cZ]local cK=E[cZ]aL(b8,cK)if cZ>256 then cJ=cJ+1;if cZ>264 and cZ<285 then cR=cR+1;local cU=c4[cR]local cL=y[cZ-256]aL(cU,cL)end;local cq=c1[cJ]local cW=G[cq]aL(cW,5)if cq>3 then cS=cS+1;local cs=c6[cS]local cr=(cq-cq%2)/2-1;aL(cs,cr)end end end end;local function c_(bL,bM,aI)assert(bM-bL+1<=65535)local cI=3;aI=aI+3;local aQ=(8-aI%8)%8;cI=cI+aQ;cI=cI+32;cI=cI+(bM-bL+1)*8;return cI end;local function d0(aL,aN,cO,Y,bL,bM,aI)assert(bM-bL+1<=65535)aL(cO and 1 or 0,1)aL(0,2)aI=aI+3;local aQ=(8-aI%8)%8;if aQ>0 then aL(o[aQ]-1,aQ)end;local d1=bM-bL+1;aL(d1,16)local d2=255-d1%256+(255-(d1-d1%256)/256)*256;aL(d2,16)aN(Y:sub(bL,bM))end;local function d3(au,aL,aN,aO,Y,al)local am={}local an={}local cO=nil;local bL;local bM;local d4;local aI=aO(aD)local Z=#Y;local bI;local bK;local d5;if au then if au.level then bK=au.level end;if au.strategy then d5=au.strategy end end;if not bK then if Z<2048 then bK=7 elseif Z>65536 then bK=3 else bK=5 end end;while not cO do if not bL then bL=1;bM=64*1024-1;bI=0 else bL=bM+1;bM=bM+32*1024;bI=bL-32*1024-1 end;if bM>=Z then bM=Z;cO=true else cO=false end;local bZ,c4,c0,c1,c6,c3;local cF,cG,cD,cB,cC,cz,bB,cv,cw,cx,cy;local d6;local d7;local d8;if bK~=0 then bF(Y,am,bL,bM+3,bI)if bL==1 and al then local bW=al.string_table;local d9=al.strlen;for K=0,-d9+1<-257 and-257 or-d9+1,-1 do am[K]=bW[d9+K]end end;if d5=="huffman_only"then bZ={}bF(Y,bZ,bL,bM,bL-1)c4={}c0={}bZ[bM-bL+2]=256;for K=1,bM-bL+2 do local W=bZ[K]c0[W]=(c0[W]or 0)+1 end;c1={}c6={}c3={}else bZ,c4,c0,c1,c6,c3=bJ(bK,am,an,bL,bM,bI,al)end;cF,cG,cD,cB,cC,cz,bB,cv,cw,cx,cy=cu(c0,c3)d6=cH(bZ,c1,cD,cB,cz,cv,cx)d7=cX(bZ,c1)end;d8=c_(bL,bM,aI)local da=d8;da=d7 and d70 and bM+1-V[1]>32768 then if db==1 then an[ay]=nil else local dc={}local dd=0;for K=2,db do M=V[K]if bM+1-M<=32768 then dd=dd+1;dc[dd]=M end end;an[ay]=dc end end end end end end;local function de(Y,al,au)local aL,aN,aO=aE()d3(au,aL,aN,aO,Y,al)local aI,df=aO(aB)local aQ=(8-aI%8)%8;return df,aQ end;local function dg(Y,al,au)local aL,aN,aO=aE()local dh=8;local di=7;local dj=di*16+dh;aL(dj,8)local dk=al and 1 or 0;local dl=2;local dm=dl*64+dk*32;local dn=31-(dj*256+dm)%31;dm=dm+dn;aL(dm,8)if dk==1 then local aj=al.adler32;local dp=aj%256;aj=(aj-dp)/256;local dq=aj%256;aj=(aj-dq)/256;local dr=aj%256;aj=(aj-dr)/256;local ds=aj%256;aL(ds,8)aL(dr,8)aL(dq,8)aL(dp,8)end;d3(au,aL,aN,aO,Y,al)aO(aC)local aj=a:Adler32(Y)local ds=aj%256;aj=(aj-ds)/256;local dr=aj%256;aj=(aj-dr)/256;local dq=aj%256;aj=(aj-dq)/256;local dp=aj%256;aL(dp,8)aL(dq,8)aL(dr,8)aL(ds,8)local aI,df=aO(aB)local aQ=(8-aI%8)%8;return df,aQ end;function a:CompressDeflate(Y,au)local dt,du=ar(Y,false,nil,true,au)if not dt then error("Usage: LibDeflate:CompressDeflate(str, configs): "..du,2)end;return de(Y,nil,au)end;function a:CompressDeflateWithDict(Y,al,au)local dt,du=ar(Y,true,al,true,au)if not dt then error("Usage: LibDeflate:CompressDeflateWithDict".."(str, dictionary, configs): "..du,2)end;return de(Y,al,au)end;function a:CompressZlib(Y,au)local dt,du=ar(Y,false,nil,true,au)if not dt then error("Usage: LibDeflate:CompressZlib(str, configs): "..du,2)end;return dg(Y,nil,au)end;function a:CompressZlibWithDict(Y,al,au)local dt,du=ar(Y,true,al,true,au)if not dt then error("Usage: LibDeflate:CompressZlibWithDict".."(str, dictionary, configs): "..du,2)end;return dg(Y,al,au)end;local function dv(dw)local dx=dw;local dy=#dw;local dz=1;local aH=0;local aG=0;local function dA(T)local aM=o[T]local W;if T<=aH then W=aG%aM;aG=(aG-W)/aM;aH=aH-T else local dB=o[aH]local dq,dr,ds,dC=h(dx,dz,dz+3)aG=aG+((dq or 0)+(dr or 0)*256+(ds or 0)*65536+(dC or 0)*16777216)*dB;dz=dz+4;aH=aH+32-T;W=aG%aM;aG=(aG-W)/aM end;return W end;local function dD(dE,aJ,aF)assert(aH%8==0)local dF=aH/80 then if aH<15 and dx then local dB=o[aH]local dq,dr,ds,dC=h(dx,dz,dz+3)aG=aG+((dq or 0)+(dr or 0)*256+(ds or 0)*65536+(dC or 0)*16777216)*dB;dz=dz+4;aH=aH+32 end;local aM=o[da]aH=aH-da;W=aG%aM;aG=(aG-W)/aM;W=q[da][W]bj=dI[da]if W0 and T285 then return-10 elseif bb<256 then aF=aF+1;aJ[aF]=p[bb]elseif bb>256 then bb=bb-256;local T=x[bb]T=bb>=8 and T+dA(y[bb])or T;bb=dH(cx,dZ,d_)if bb<0 or bb>29 then return-10 end;local X=z[bb]X=X>4 and X+dA(A[bb])or X;local e1=aF-X+1;if e1=-257 then for P=1,T do aF=aF+1;aJ[aF]=aJ[e1]e1=e1+1 end else e1=d9+e1;for P=1,T do aF=aF+1;aJ[aF]=p[bW[e1]]e1=e1+1 end end end;if dN()<0 then return 2 end;if aF>=65536 then aK[#aK+1]=m(aJ,"",1,32768)for K=32769,aF do aJ[K-32768]=aJ[K]end;aF=aF-32768;aJ[aF+1]=nil end until bb==256;dR.buffer_size=aF;return 0 end;local function e2(dR)local aJ,aF,dA,dD,dN,dO,aK=dR.buffer,dR.buffer_size,dR.ReadBits,dR.ReadBytes,dR.ReaderBitlenLeft,dR.SkipToByteBoundary,dR.result_buffer;dO()local dE=dA(16)if dN()<0 then return 2 end;local e3=dA(16)if dN()<0 then return 2 end;if dE%256+e3%256~=255 then return-2 end;if(dE-dE%256)/256+(e3-e3%256)/256~=255 then return-2 end;aF=dD(dE,aJ,aF)if aF<0 then return 2 end;if aF>=65536 then aK[#aK+1]=m(aJ,"",1,32768)for K=32769,aF do aJ[K-32768]=aJ[K]end;aF=aF-32768;aJ[aF+1]=nil end;dR.buffer_size=aF;return 0 end;local function e4(dR)return dW(dR,F,D,7,J,H,5)end;local function e5(dR)local dA,dH=dR.ReadBits,dR.Decode;local e6=dA(5)+257;local e7=dA(5)+1;local e8=dA(4)+4;if e6>286 or e7>30 then return-3 end;local cB={}for K=1,e8 do cB[B[K]]=dA(3)end;local e9,ea,eb,ec=dS(cB,18,7)if e9~=0 then return-4 end;local cv={}local cx={}local bq=0;while bqe6+e7 then return-6 end;while bb>0 do bb=bb-1;if bq7 then return nil,-13 end;local dm=dA(8)if dR.ReaderBitlenLeft()<0 then return nil,2 end;if(dj*256+dm)%31~=0 then return nil,-14 end;local dk=(dm-dm%32)/32%2;local dl=(dm-dm%64)/64%4;if dk==1 then if not al then return nil,-16 end;local ds=dA(8)local dr=dA(8)local dq=dA(8)local dp=dA(8)local ak=ds*16777216+dr*65536+dq*256+dp;if dR.ReaderBitlenLeft()<0 then return nil,2 end;if not ag(ak,al.adler32)then return nil,-17 end end;local df,ej=eh(dR)if not df then return nil,ej end;dR.SkipToByteBoundary()local eo=dA(8)local ep=dA(8)local eq=dA(8)local er=dA(8)if dR.ReaderBitlenLeft()<0 then return nil,2 end;local es=eo*16777216+ep*65536+eq*256+er;local et=a:Adler32(df)if not ag(es,et)then return nil,-15 end;local el=dR.ReaderBitlenLeft()local em=(el-el%8)/8;return df,em end;function a:DecompressDeflate(Y)local dt,du=ar(Y)if not dt then error("Usage: LibDeflate:DecompressDeflate(str): "..du,2)end;return ek(Y)end;function a:DecompressDeflateWithDict(Y,al)local dt,du=ar(Y,true,al)if not dt then error("Usage: LibDeflate:DecompressDeflateWithDict(str, dictionary): "..du,2)end;return ek(Y,al)end;function a:DecompressZlib(Y)local dt,du=ar(Y)if not dt then error("Usage: LibDeflate:DecompressZlib(str): "..du,2)end;return en(Y)end;function a:DecompressZlibWithDict(Y,al)local dt,du=ar(Y,true,al)if not dt then error("Usage: LibDeflate:DecompressZlibWithDict(str, dictionary): "..du,2)end;return en(Y,al)end;do E={}for eu=0,143 do E[eu]=8 end;for eu=144,255 do E[eu]=9 end;for eu=256,279 do E[eu]=7 end;for eu=280,287 do E[eu]=8 end;I={}for X=0,31 do I[X]=5 end;local ej;ej,F,D=dS(E,287,9)assert(ej==0)ej,J,H=dS(I,31,5)assert(ej==0)C=b3(F,E,287,9)G=b3(J,I,31,5)end;local ev={["\000"]="%z",["("]="%(",[")"]="%)",["."]="%.",["%"]="%%",["+"]="%+",["-"]="%-",["*"]="%*",["?"]="%?",["["]="%[",["]"]="%]",["^"]="%^",["$"]="%$"}local function ew(Y)return Y:gsub("([%z%(%)%.%%%+%-%*%?%[%]%^%$])",ev)end;function a:CreateCodec(ex,ey,ez)if type(ex)~="string"or type(ey)~="string"or type(ez)~="string"then error("Usage: LibDeflate:CreateCodec(reserved_chars,".." escape_chars, map_chars):".." All arguments must be string.",2)end;if ey==""then return nil,"No escape characters supplied."end;if#ex<#ez then return nil,"The number of reserved characters must be".." at least as many as the number of mapped chars."end;if ex==""then return nil,"No characters to encode."end;local eA=ex..ey..ez;local eB={}for K=1,#eA do local dG=h(eA,K,K)if eB[dG]then return nil,"There must be no duplicate characters in the".." concatenation of reserved_chars, escape_chars and".." map_chars."end;eB[dG]=true end;local eC={}local eD={}local eE={}local eF={}if#ez>0 then local eG={}local eH={}for K=1,#ez do local eI=l(ex,K,K)local eJ=l(ez,K,K)eF[eI]=eJ;eE[#eE+1]=eI;eH[eJ]=eI;eG[#eG+1]=eJ end;eC[#eC+1]="(["..ew(m(eG)).."])"eD[#eD+1]=eH end;local eK=1;local eL=l(ey,eK,eK)local eM=0;local eG={}local eH={}for K=1,#eA do local S=l(eA,K,K)if not eF[S]then while eM>=256 or eB[eM]do eM=eM+1;if eM>255 then eC[#eC+1]=ew(eL).."(["..ew(m(eG)).."])"eD[#eD+1]=eH;eK=eK+1;eL=l(ey,eK,eK)eM=0;eG={}eH={}if not eL or eL==""then return nil,"Out of escape characters."end end end;local eN=p[eM]eF[S]=eL..eN;eE[#eE+1]=S;eH[eN]=S;eG[#eG+1]=eN;eM=eM+1 end;if K==#eA then eC[#eC+1]=ew(eL).."(["..ew(m(eG)).."])"eD[#eD+1]=eH end end;local eO={}local eP="(["..ew(m(eE)).."])"local eQ=eF;function eO:Encode(Y)if type(Y)~="string"then error(("Usage: codec:Encode(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;return k(Y,eP,eQ)end;local eR=#eC;local eS="(["..ew(ex).."])"function eO:Decode(Y)if type(Y)~="string"then error(("Usage: codec:Decode(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;if j(Y,eS)then return nil end;for K=1,eR do Y=k(Y,eC[K],eD[K])end;return Y end;return eO end;local eT={[0]="a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9","(",")"}local eU={[97]=0,[98]=1,[99]=2,[100]=3,[101]=4,[102]=5,[103]=6,[104]=7,[105]=8,[106]=9,[107]=10,[108]=11,[109]=12,[110]=13,[111]=14,[112]=15,[113]=16,[114]=17,[115]=18,[116]=19,[117]=20,[118]=21,[119]=22,[120]=23,[121]=24,[122]=25,[65]=26,[66]=27,[67]=28,[68]=29,[69]=30,[70]=31,[71]=32,[72]=33,[73]=34,[74]=35,[75]=36,[76]=37,[77]=38,[78]=39,[79]=40,[80]=41,[81]=42,[82]=43,[83]=44,[84]=45,[85]=46,[86]=47,[87]=48,[88]=49,[89]=50,[90]=51,[48]=52,[49]=53,[50]=54,[51]=55,[52]=56,[53]=57,[54]=58,[55]=59,[56]=60,[57]=61,[40]=62,[41]=63}function a:EncodeForPrint(Y)if type(Y)~="string"then error(("Usage: LibDeflate:EncodeForPrint(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;local Z=#Y;local eV=Z-2;local K=1;local aJ={}local aF=0;while K<=eV do local _,a0,a1=h(Y,K,K+2)K=K+3;local aG=_+a0*256+a1*65536;local eW=aG%64;aG=(aG-eW)/64;local eX=aG%64;aG=(aG-eX)/64;local eY=aG%64;local eZ=(aG-eY)/64;aF=aF+1;aJ[aF]=eT[eW]..eT[eX]..eT[eY]..eT[eZ]end;local aG=0;local aH=0;while K<=Z do local af=h(Y,K,K)aG=aG+af*o[aH]aH=aH+8;K=K+1 end;while aH>0 do local e_=aG%64;aF=aF+1;aJ[aF]=eT[e_]aG=(aG-e_)/64;aH=aH-6 end;return m(aJ)end;function a:DecodeForPrint(Y)if type(Y)~="string"then error(("Usage: LibDeflate:DecodeForPrint(str):".." \'str\' - string expected got \'%s\'."):format(type(Y)),2)end;Y=Y:gsub("^[%c ]+","")Y=Y:gsub("[%c ]+$","")local Z=#Y;if Z==1 then return nil end;local f0=Z-3;local K=1;local aJ={}local aF=0;while K<=f0 do local _,a0,a1,a2=h(Y,K,K+3)_=eU[_]a0=eU[a0]a1=eU[a1]a2=eU[a2]if not(_ and a0 and a1 and a2)then return nil end;K=K+4;local aG=_+a0*64+a1*4096+a2*262144;local eW=aG%256;aG=(aG-eW)/256;local eX=aG%256;local eY=(aG-eX)/256;aF=aF+1;aJ[aF]=p[eW]..p[eX]..p[eY]end;local aG=0;local aH=0;while K<=Z do local af=h(Y,K,K)af=eU[af]if not af then return nil end;aG=aG+af*o[aH]aH=aH+6;K=K+1 end;while aH>=8 do local dG=aG%256;aF=aF+1;aJ[aF]=p[dG]aG=(aG-dG)/256;aH=aH-8 end;return m(aJ)end;local function f1()_chat_channel_codec=nil;_addon_channel_codec=nil end;a.internals={LoadStringToTable=bF,IsValidDictionary=ap,IsEqualAdler32=ag,_byte_to_6bit_char=eT,_6bit_to_byte=eU,InternalClearCache=f1}if io and os and debug and _G.arg then local io=io;local os=os;local debug=debug;local f2=_G.arg;local f3=debug.getinfo(1)if f3.source==f2[0]or f3.short_src==f2[0]then local dx;local f4;local K=1;local ej;local f5=false;local f6=false;local bK;local d5;local al;while f2[K]do local Q=f2[K]if Q=="-h"then print(a._COPYRIGHT.."\nUsage: lua LibDeflate.lua [OPTION] [INPUT] [OUTPUT]\n".." -0 store only. no compression.\n".." -1 fastest compression.\n".." -9 slowest and best compression.\n".." -d do decompression instead of compression.\n".." --dict specify the file that contains".." the entire preset dictionary.\n".." -h give this help.\n".." --strategy ".." specify a special compression strategy.\n".." -v print the version and copyright info.\n".." --zlib use zlib format instead of raw deflate.\n")os.exit(0)elseif Q=="-v"then print(a._COPYRIGHT)os.exit(0)elseif Q:find("^%-[0-9]$")then bK=tonumber(Q:sub(2,2))elseif Q=="-d"then f6=true elseif Q=="--dict"then K=K+1;local f7=f2[K]if not f7 then io.stderr:write("You must speicify the dict filename")os.exit(1)end;local f8,f9=io.open(f7,"rb")if not f8 then io.stderr:write(("LibDeflate: Cannot read the dictionary file \'%s\': %s"):format(f7,f9))os.exit(1)end;local fa=f8:read("*all")f8:close()al=a:CreateDictionary(fa,#fa,a:Adler32(fa))elseif Q=="--strategy"then K=K+1;d5=f2[K]elseif Q=="--zlib"then f5=true elseif Q:find("^%-")then io.stderr:write(("LibDeflate: Invalid argument: %s"):format(Q))os.exit(1)else if not dx then dx,ej=io.open(Q,"rb")if not dx then io.stderr:write(("LibDeflate: Cannot read the file \'%s\': %s"):format(Q,tostring(ej)))os.exit(1)end elseif not f4 then f4,ej=io.open(Q,"wb")if not f4 then io.stderr:write(("LibDeflate: Cannot write the file \'%s\': %s"):format(Q,tostring(ej)))os.exit(1)end end end;K=K+1 end;if not dx or not f4 then io.stderr:write("LibDeflate:".." You must specify both input and output files.")os.exit(1)end;local fb=dx:read("*all")local au={level=bK,strategy=d5}local fc;if not f6 then if not f5 then if not al then fc=a:CompressDeflate(fb,au)else fc=a:CompressDeflateWithDict(fb,al,au)end else if not al then fc=a:CompressZlib(fb,au)else fc=a:CompressZlibWithDict(fb,al,au)end end else if not f5 then if not al then fc=a:DecompressDeflate(fb)else fc=a:DecompressDeflateWithDict(fb,al)end else if not al then fc=a:DecompressZlib(fb)else fc=a:DecompressZlibWithDict(fb,al)end end end;if not fc then io.stderr:write("LibDeflate: Decompress fails.")os.exit(1)end;f4:write(fc)if dx and dx~=io.stdin then dx:close()end;if f4 and f4~=io.stdout then f4:close()end;io.stderr:write(("Successfully writes %d bytes"):format(fc:len()))os.exit(0)end end;return a end)() +local expect = dofile("rom/modules/main/cc/expect.lua") +local expect, field = expect.expect, expect.field +local filesystem = nil +settings.define("containers.compression_level", { + description = "The level of compression for the file systems on a scale of 1-8", + default = 4, + type = "number", +}) +settings.save() +local compression_level = settings.get("containers.compression_level") + +local lib = {} + +local function deepcopy(o, seen) + seen = seen or {} + if o == nil then return nil end + if seen[o] then return seen[o] end + + local no + if type(o) == 'table' then + no = {} + seen[o] = no + + for k, v in next, o, nil do + no[deepcopy(k, seen)] = deepcopy(v, seen) + end + setmetatable(no, deepcopy(getmetatable(o), seen)) + else -- number, string, boolean, etc + no = o + end + return no +end + + +local function buildRom(path) + sleep() + local out = {} + for _, file in ipairs(fs.list(path)) do + local fullPath = fs.combine(path, file) + if fs.isDir(fullPath) then + out[file] = buildRom(fullPath) + else + local handle = fs.open(fullPath, "r") + out[file] = handle.readAll() + handle.close() + end + end + return out +end + +local function getRom() + if not _G.rom_cache then + _G.rom_cache = buildRom("/rom") + end + return _G.rom_cache +end + +function lib.getENV(fspath, has_http) + local global = deepcopy(_G) + setmetatable(global, { __index = _G }) + local function getFileSystem() + if filesystem then filesystem.rom = getRom() return filesystem end + if not fs.exists(fspath) then + return {rom=getRom()} + end + local file = fs.open(fspath, "r") + local compressedData = file.readAll() + file.close() + local decompressedData = deflate:DecompressDeflate(compressedData,{level=compression_level}) + local data = textutils.unserialize(decompressedData) or {} + filesystem = data + data.rom = getRom() + return data + end + + local function setFileSystem(data) + filesystem = data + data.rom = nil + data = textutils.serialize(data) + local file = fs.open(fspath, "w") + file.write(deflate:CompressDeflate(data,{level=compression_level})) + file.close() + end + + local function normalizeParts(path) + local parts = {} + for part in string.gmatch(path, "[^/]+") do + if part == "" or part == "." then + -- skip + elseif part == ".." then + if #parts > 0 then table.remove(parts) end + else + parts[#parts + 1] = part + end + end + return parts + end + + local function getDataAt(path) + expect(1, path, "string") + local parts = normalizeParts(path) + local current = getFileSystem() + if #parts == 0 then return current end + for i = 1, #parts do + local part = parts[i] + if type(current) ~= "table" then + -- trying to index into a file + return nil + end + current = current[part] + if current == nil then return nil end + end + return current + end + + local function setDataAt(path, data) + expect(1, path, "string") + local parts = normalizeParts(path) + local filesys = getFileSystem() + local current = filesys + for i, part in ipairs(parts) do + if i == #parts then + current[part] = data + elseif type(current[part]) == "table" then + current = current[part] + elseif type(current[part]) == "string" then + return + end + end + setFileSystem(filesys) + end + + + function global.fs.list(path) + expect(1, path, "string") + local out = {} + local data = getDataAt(path) + if data then + for k, v in pairs(data) do + table.insert(out, k) + end + end + return out + end + + function global.fs.isDir(path) + expect(1, path, "string") + local data = getDataAt(path) + return type(data) == "table" + end + + function global.fs.isReadOnly(path) + if path == "" then return false end + expect(1, path, "string") + local offset = string.find(path, "rom") + return offset ~= nil and offset < 3 + end + + function global.fs.exists(path) + expect(1, path, "string") + local data = getDataAt(path) + return data ~= nil + end + + function global.fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) + expect(1, sPath, "string") + expect(2, sLocation, "string") + local bIncludeHidden = nil + if type(bIncludeFiles) == "table" then + bIncludeDirs = field(bIncludeFiles, "include_dirs", "boolean", "nil") + bIncludeHidden = field(bIncludeFiles, "include_hidden", "boolean", "nil") + bIncludeFiles = field(bIncludeFiles, "include_files", "boolean", "nil") + else + expect(3, bIncludeFiles, "boolean", "nil") + expect(4, bIncludeDirs, "boolean", "nil") + end + + bIncludeHidden = bIncludeHidden ~= false + bIncludeFiles = bIncludeFiles ~= false + bIncludeDirs = bIncludeDirs ~= false + local sDir = sLocation + local nStart = 1 + local nSlash = string.find(sPath, "[/\\]", nStart) + if nSlash == 1 then + sDir = "" + nStart = 2 + end + local sName + while not sName do + local nSlash = string.find(sPath, "[/\\]", nStart) + if nSlash then + local sPart = string.sub(sPath, nStart, nSlash - 1) + sDir = global.fs.combine(sDir, sPart) + nStart = nSlash + 1 + else + sName = string.sub(sPath, nStart) + end + end + + if global.fs.isDir(sDir) then + local tResults = {} + if bIncludeDirs and sPath == "" then + table.insert(tResults, ".") + end + if sDir ~= "" then + if sPath == "" then + table.insert(tResults, bIncludeDirs and ".." or "../") + elseif sPath == "." then + table.insert(tResults, bIncludeDirs and "." or "./") + end + end + local tFiles = global.fs.list(sDir) + for n = 1, #tFiles do + local sFile = tFiles[n] + if #sFile >= #sName and string.sub(sFile, 1, #sName) == sName and ( + bIncludeHidden or sFile:sub(1, 1) ~= "." or sName:sub(1, 1) == "." + ) then + local bIsDir = global.fs.isDir(fs.combine(sDir, sFile)) + local sResult = string.sub(sFile, #sName + 1) + if bIsDir then + table.insert(tResults, sResult .. "/") + if bIncludeDirs and #sResult > 0 then + table.insert(tResults, sResult) + end + else + if bIncludeFiles and #sResult > 0 then + table.insert(tResults, sResult) + end + end + end + end + return tResults + end + + return {} + end + + local function getReadHandle(path, isBinary) + expect(1, path, "string") + local data = getDataAt(path) or "" + local len = #data + local seek = 1 + + return { + readAll = function() + if data == nil then return nil end + data = data:sub(seek) + seek = len + 1 + return data + end, + + readLine = function(includeTrailing) + if data == nil then return nil end + if seek > len then return nil end -- EOF guard + + local start = seek + local nl = data:find("\n", start, true) + local line + + if nl then + if includeTrailing then + line = data:sub(start, nl) -- include "\n" + else + line = data:sub(start, nl - 1) -- exclude "\n" + end + seek = nl + 1 + else + -- last line (no trailing newline) + line = data:sub(start) + seek = len + 1 + end + + -- NOTE: do NOT treat "" as EOF; blank lines are valid + return line + end, + + read = function(count) + if type(count) == "table" then + count = 1 + end + expect(1, count, "number", "nil") + if data == nil then return nil end + if not count then count = 1 end + if seek > len then return nil end + + local toReturn = string.sub(data, seek, seek + count - 1) + seek = seek + #toReturn + if toReturn == "" then + return nil + elseif isBinary and count == 1 then + return string.byte(toReturn) + end + return toReturn + end, + + seek = function (offset, whence) + if data == nil then return nil, "File is closed" end + offset = offset or 0 + whence = whence or "cur" + + if whence == "set" then + seek = math.min(math.max(0, offset), len) + 1 + elseif whence == "cur" then + seek = math.min(math.max(1, seek + offset), len + 1) + elseif whence == "end" then + seek = math.min(math.max(0, len + offset), len) + 1 + end + + return seek - 1 + end, + + close = function() + data = nil + end, + } + end + + + local function getWriteHandle(path, isBinary, append_mode) + local data = "" + local seek = 1 + + if append_mode then + data = getDataAt(path) or "" + seek = #data + 1 + end + + local handle -- forward declared so writeLine can see it + + local function hwrite(str) + if data == nil then error("File is closed", 2) end + if type(str) == "number" and isBinary then + str = string.char(str) + elseif type(str) ~= "string" then + error("bad argument #1 (string or number expected, got " .. type(str) .. " )", 2) + end + + data = string.sub(data, 1, seek - 1) .. str .. string.sub(data, seek + #str) + seek = seek + #str + end + + handle = { + write = hwrite, + writeLine = function (str) + if data == nil then error("File is closed", 2) end + expect(1, str, "string") + hwrite(str .. "\n") -- **no global write** + end, + flush = function() + if data == nil then error("File is closed", 2) end + setDataAt(path, data) + end, + close = function() + if data == nil then error("File is already closed", 2) end + setDataAt(path, data) + data = nil + end, + } + + return handle + end + + local function getReadWriteHandle(path, isBinary, erase_data) + expect(1, path, "string") + local data = erase_data and "" or (getDataAt(path) or "") + local len = #data + local seek = 1 + + local handle = {} + + handle.readAll = function() + if data == nil then return nil end + data = data:sub(seek) + seek = len + 1 + return data + end + + handle.readLine = function(includeTrailing) + if data == nil then return nil end + if seek > len then return nil end -- EOF guard + + local start = seek + local nl = data:find("\n", start, true) + local line + + if nl then + if includeTrailing then + line = data:sub(start, nl) + else + line = data:sub(start, nl - 1) + end + seek = nl + 1 + else + line = data:sub(start) + seek = len + 1 + end + + return line + end + + function handle.read(count) + if type(count) == "table" then + count = 1 + end + expect(1, count, "number", "nil") + if data == nil then error("File is closed", 2) end + if not count then count = 1 end + if seek > len then return nil end + + local toReturn = data:sub(seek, seek + count - 1) + seek = seek + #toReturn + + if toReturn == "" then + return nil + elseif isBinary and count == 1 then + return string.byte(toReturn) + end + return toReturn + end + + function handle.seek(offset, whence) + if data == nil then return nil, "File is closed" end + + offset = offset or 0 + whence = whence or "cur" + + if whence == "set" then + seek = math.min(math.max(0, offset), len) + 1 + elseif whence == "cur" then + seek = math.min(math.max(1, seek + offset), len + 1) + elseif whence == "end" then + seek = math.min(math.max(0, len + offset), len) + 1 + else + error("bad argument #2 (invalid whence)", 2) + end + + return seek - 1 + end + + function handle.write(str) + if type(str) == "number" and isBinary then + str = string.char(str) + elseif type(str) ~= "string" then + error("bad argument #1 (string or number expected, got " .. type(str) .. " )", 2) + end + if data == nil then error("File is closed", 2) end + + data = string.sub(data, 1, seek - 1) .. str .. string.sub(data, seek + #str) + seek = seek + #str + len = #data + end + + function handle.writeLine(str) + expect(1, str, "string") + handle.write(str .. "\n") + end + + function handle.flush() + if data == nil then error("File is closed", 2) end + setDataAt(path, data) + end + + function handle.close() + if data == nil then error("File is already closed", 2) end + setDataAt(path, data) + data = nil + end + + return handle + end + + local function ioHandleWrapper(handle) + local closed = false + return { + read = function (self, mode) + if closed then error("File is closed", 2) end + expect(2, mode, "string", "nil") + if not mode then mode = "l" end + if type(self) ~= "table" then + error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) + end + + if string.find(mode, "%*") == 1 then + mode = mode:gsub("%*", "") + end + + if mode == "l" then + return handle.readLine(false) + elseif mode == "L" then + return handle.readLine(true) + elseif mode == "a" then + return handle.readAll() + else + error("Unsupported read mode", 2) + end + end, + + seek = function (self, whence, offset) + if closed then error("File is closed", 2) end + expect(2, whence, "string", "nil") + expect(3, offset, "number", "nil") + if type(self) ~= "table" then + error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) + end + return handle.seek(offset, whence) + end, + + write = function (self, ...) + if closed then error("File is closed", 2) end + if type(self) ~= "table" then + error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) + end + + local args = { ... } + for i = 1, #args do + local arg = args[i] + if type(arg) ~= "string" and type(arg) ~= "number" then + error("bad argument #" .. (i + 1) .. + " (string or number expected, got " .. type(arg) .. " )", 2) + end + -- preserve your existing semantics: underlying handle decides what to do + handle.write(arg) + end + end, + + close = function (self) + if closed then error("File is already closed", 2) end + if type(self) ~= "table" then + error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) + end + handle.close() + closed = true + end, + + flush = function (self) + if closed then error("File is closed", 2) end + if type(self) ~= "table" then + error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) + end + handle.flush() + end, + + lines = function (self) + if closed then error("File is closed", 2) end + if type(self) ~= "table" then + error("bad argument #1 (FILE expected, got " .. type(self) .. " )", 2) + end + return function() + if closed then error("file is already closed", 2) end + return handle.readLine(false) + end + end, + } + end + + + function global.fs.open(path,mode) + expect(1, path, "string") + expect(2, mode, "string") + if mode == "r" or mode == "rb" then + if global.fs.exists(path) then + return getReadHandle(path, mode == "rb") + else + error("File not found", 2) + end + elseif mode == "w" or mode == "wb" then + return getWriteHandle(path, mode == "wb", false) + elseif mode == "a" or mode == "ab" then + return getWriteHandle(path, mode == "ab", true) + elseif mode == "r+" or mode == "rb+" or mode == "r+b" then + if global.fs.exists(path) then + return getReadWriteHandle(path, mode == "rb+" or mode == "r+b", false) + else + error("File not found", 2) + end + elseif mode == "w+" or mode == "wb+" or mode == "w+b" then + return getReadWriteHandle(path, mode == "wb+" or mode == "w+b", true) + elseif mode == "a+" or mode == "ab+" or mode == "a+b" then + return getReadWriteHandle(path, mode == "ab+" or mode == "a+b", true) + else + error("Invalid mode", 2) + end + end + + function global.fs.move(srcPath, dstPath) + expect(1, srcPath, "string") + expect(2, dstPath, "string") + if not global.fs.exists(srcPath) then + error("Source does not exist", 2) + end + if global.fs.exists(dstPath) then + error("Destination already exists", 2) + end + local data = getDataAt(srcPath) + setDataAt(dstPath, data) + setDataAt(srcPath, nil) + end + + function global.fs.copy(srcPath, dstPath) + expect(1, srcPath, "string") + expect(2, dstPath, "string") + if not global.fs.exists(srcPath) then + error("Source does not exist", 2) + end + if global.fs.exists(dstPath) then + error("Destination already exists", 2) + end + local data = getDataAt(srcPath) + setDataAt(dstPath, data) + end + + local function find_aux(path, parts, i, out) + local part = parts[i] + if not part then + -- If we're at the end of the pattern, ensure our path exists and append it. + if global.fs.exists(path) then out[#out + 1] = path end + elseif part.exact then + -- If we're an exact match, just recurse into this directory. + return find_aux(global.fs.combine(path, part.contents), parts, i + 1, out) + else + -- Otherwise we're a pattern. Check we're a directory, then recurse into each + -- matching file. + if not global.fs.isDir(path) then return end + + local files = global.fs.list(path) + for j = 1, #files do + local file = files[j] + if file:find(part.contents) then find_aux(global.fs.combine(path, file), parts, i + 1, out) end + end + end + end + + local find_escape = { + -- Escape standard Lua pattern characters + ["^"] = "%^", ["$"] = "%$", ["("] = "%(", [")"] = "%)", ["%"] = "%%", + ["."] = "%.", ["["] = "%[", ["]"] = "%]", ["+"] = "%+", ["-"] = "%-", + -- Aside from our wildcards. + ["*"] = ".*", + ["?"] = ".", + } + + function global.fs.find(pattern) + expect(1, pattern, "string") + + pattern = global.fs.combine(pattern) -- Normalise the path, removing ".."s. + + -- If the pattern is trying to search outside the computer root, just abort. + -- This will fail later on anyway. + if pattern == ".." or pattern:sub(1, 3) == "../" then + error("/" .. pattern .. ": Invalid Path", 2) + end + + -- If we've no wildcards, just check the file exists. + if not pattern:find("[*?]") then + if global.fs.exists(pattern) then return { pattern } else return {} end + end + + local parts = {} + for part in pattern:gmatch("[^/]+") do + if part:find("[*?]") then + parts[#parts + 1] = { + exact = false, + contents = "^" .. part:gsub(".", find_escape) .. "$", + } + else + parts[#parts + 1] = { exact = true, contents = part } + end + end + + local out = {} + find_aux("", parts, 1, out) + return out + end + + function global.io.open(path, mode) + expect(1, path, "string") + expect(2, mode, "string", "nil") + if not mode then mode = "r" end + local handle + if mode == "r" or mode == "rb" then + if global.fs.exists(path) and not global.fs.isDir(path) then + handle = getReadHandle(path, mode == "rb") + elseif global.fs.isDir(path) then + return nil, "Attempt to open a directory" + else + return nil, "File not found" + end + elseif mode == "w" or mode == "wb" then + handle = getWriteHandle(path, mode == "wb", false) + elseif mode == "a" or mode == "ab" then + handle = getWriteHandle(path, mode == "ab", true) + elseif mode == "r+" or mode == "rb+" or mode == "r+b" then + if global.fs.exists(path) and not global.fs.isDir(path) then + handle = getReadWriteHandle(path, mode == "rb+" or mode == "r+b", false) + elseif global.fs.isDir(path) then + return nil, "Attempt to open a directory" + else + return nil, "File not found" + end + elseif mode == "w+" or mode == "wb+" or mode == "w+b" then + handle = getReadWriteHandle(path, mode == "wb+" or mode == "w+b", true) + elseif mode == "a+" or mode == "ab+" or mode == "a+b" then + handle = getReadWriteHandle(path, mode == "ab+" or mode == "a+b", true) + else + return nil, "Invalid mode" + end + return ioHandleWrapper(handle) + end + function global.io.lines(path,...) + local args = {...} + expect(1, path, "string") + local handle = global.io.open(path, table.unpack(args)) + local count = 0 + return function () + count = count + 1 + local line = handle:read(args[count%#args + 1] or "l") + if line == nil then + handle:close() + end + return line + end + end + function global.fs.delete(path) + expect(1, path, "string") + if not global.fs.exists(path) then + error("File not found", 2) + end + setDataAt(path, nil) + end + function global.fs.getSize(path) + expect(1, path, "string") + if not global.fs.exists(path) then + error("File not found", 2) + end + if global.fs.isDir(path) then + return 0 + else + return #getDataAt(path) + end + end + + function global.fs.makeDir(path) + expect(1, path, "string") + if global.fs.exists(path) then + return + end + setDataAt(path, {}) + end + + local tAPIsLoading = {} + + local bAPIError = false + + function global.loadfile(filename, mode, env) + -- Support the previous `loadfile(filename, env)` form instead. + if type(mode) == "table" and env == nil then + mode, env = nil, mode + end + + expect(1, filename, "string") + expect(2, mode, "string", "nil") + expect(3, env, "table", "nil") + + local file = global.fs.open(filename, "r") + if not file then return nil, "File not found" end + + local func, err = load(file.readAll(), "@/" .. fs.combine(filename), mode, env) + file.close() + return func, err + end + + function global.dofile(_sFile) + expect(1, _sFile, "string") + + local fnFile, e = global.loadfile(_sFile, nil, _G) + if fnFile then + return fnFile() + else + error(e, 2) + end + end + + function global.loadAPI(_sPath) + expect(1, _sPath, "string") + local sName = fs.getName(_sPath) + if sName:sub(-4) == ".lua" then + sName = sName:sub(1, -5) + end + if sName == "term" then + return true + end + if tAPIsLoading[sName] == true then + printError("API " .. sName .. " is already being loaded") + return false + end + tAPIsLoading[sName] = true + + local tEnv = {} + setmetatable(tEnv, { __index = global }) + local fnAPI, err = global.loadfile(_sPath, nil, tEnv) + if fnAPI then + local ok, err = pcall(fnAPI) + if not ok then + tAPIsLoading[sName] = nil + return error("Failed to load API " .. sName .. " due to " .. err, 1) + end + else + tAPIsLoading[sName] = nil + return error("Failed to load API " .. sName .. " due to " .. err, 1) + end + + local tAPI = {} + for k, v in pairs(tEnv) do + if k ~= "_ENV" then + tAPI[k] = v + end + end + global[sName] = tAPI + tAPIsLoading[sName] = nil + return true + end + local function load_apis(dir) + if not global.fs.isDir(dir) then return end + + for _, file in ipairs(global.fs.list(dir)) do + if file:sub(1, 1) ~= "." then + local path = fs.combine(dir, file) + if not fs.isDir(path) then + if not global.loadAPI(path) then + bAPIError = true + end + end + end + end + end + + function global.os.run(_tEnv, _sPath, ...) + expect(1, _tEnv, "table") + expect(2, _sPath, "string") + + local tEnv = _tEnv + setmetatable(tEnv, { __index = global }) + + if settings.get("bios.strict_globals", false) then + -- load will attempt to set _ENV on this environment, which + -- throws an error with this protection enabled. Thus we set it here first. + tEnv._ENV = tEnv + getmetatable(tEnv).__newindex = function(_, name) + error("Attempt to create global " .. tostring(name), 2) + end + end + + local fnFile, err = global.loadfile(_sPath, nil, tEnv) + if fnFile then + local ok, err = pcall(fnFile, ...) + if not ok then + if err and err ~= "" then + printError(err) + end + return false + end + return true + end + if err and err ~= "" then + printError(err) + end + return false + end + global.settings = settings + global._ENV = global + global._G = global + global.shell = nil + global.multishell = nil + load_apis("rom/apis") + if http and has_http then global.http = http load_apis("rom/apis/http") end + return global +end +function lib.start(env) + local func = setfenv(function () + settings.define("shell.allow_startup", { + default = true, + description = "Run startup files when the computer turns on.", + type = "boolean", + }) + settings.define("shell.allow_disk_startup", { + default = commands == nil, + description = "Run startup files from disk drives when the computer turns on.", + type = "boolean", + }) + + settings.define("shell.autocomplete", { + default = true, + description = "Autocomplete program and arguments in the shell.", + type = "boolean", + }) + settings.define("edit.autocomplete", { + default = true, + description = "Autocomplete API and function names in the editor.", + type = "boolean", + }) + settings.define("lua.autocomplete", { + default = true, + description = "Autocomplete API and function names in the Lua REPL.", + type = "boolean", + }) + + settings.define("edit.default_extension", { + default = "lua", + description = [[The file extension the editor will use if none is given. Set to "" to disable.]], + type = "string", + }) + settings.define("paint.default_extension", { + default = "nfp", + description = [[The file extension the paint program will use if none is given. Set to "" to disable.]], + type = "string", + }) + + settings.define("list.show_hidden", { + default = false, + description = [[Whether the list program show hidden files (those starting with ".").]], + type = "boolean", + }) + + settings.define("motd.enable", { + default = pocket == nil, + description = "Display a random message when the computer starts up.", + type = "boolean", + }) + settings.define("motd.path", { + default = "/rom/motd.txt:/motd.txt", + description = [[The path to load random messages from. Should be a colon (":") separated string of file paths.]], + type = "string", + }) + + settings.define("lua.warn_against_use_of_local", { + default = true, + description = [[Print a message when input in the Lua REPL starts with the word 'local'. Local variables defined in the Lua REPL are be inaccessible on the next input.]], + type = "boolean", + }) + settings.define("lua.function_args", { + default = true, + description = "Show function arguments when printing functions.", + type = "boolean", + }) + settings.define("lua.function_source", { + default = false, + description = "Show where a function was defined when printing functions.", + type = "boolean", + }) + settings.define("bios.strict_globals", { + default = false, + description = "Prevents assigning variables into a program's environment. Make sure you use the local keyword or assign to _G explicitly.", + type = "boolean", + }) + settings.define("shell.autocomplete_hidden", { + default = false, + description = [[Autocomplete hidden files and folders (those starting with ".").]], + type = "boolean", + }) + print("running container!") + local ok, err = pcall(parallel.waitForAny, + function() + local sShell + if term.isColour() and settings.get("bios.use_multishell") then + sShell = "rom/programs/advanced/multishell.lua" + else + sShell = "rom/programs/shell.lua" + end + os.run({}, sShell) + os.run({}, "rom/programs/shutdown.lua") + end, + rednet.run + ) + end,env) + func() +end +return lib \ No newline at end of file