DIRECTORY Basics, ImagerError, ImagerPixelArray, ImagerPixelArrayPrivate, ImagerSample, IO, PixelArrayCCITTG4, PixelArrayCCITTG4Private, RasterBasics, RasterOp, Rope, SafeStorage, SF; PixelArrayCCITTG4Impl: MONITOR LOCKS data USING data: Data IMPORTS Basics, ImagerError, ImagerPixelArrayPrivate, ImagerSample, IO, RasterOp, SafeStorage EXPORTS ImagerPixelArray, PixelArrayCCITTG4, PixelArrayCCITTG4Private ~ BEGIN OPEN PixelArrayCCITTG4Private; PixelArrayClassRep: PUBLIC TYPE ~ ImagerPixelArrayPrivate.PixelArrayClassRep; bpw: NAT = BITS[WORD]; maxNeed: NAT = bpw-BITS[BYTE]; BitCount: TYPE = [0..bpw); BytesPtr: TYPE = POINTER TO Basics.RawBytes; IntPtr: TYPE = POINTER TO RECORD [SEQUENCE COMPUTED CARD OF INT]; CardPtr: TYPE = POINTER TO RECORD [SEQUENCE COMPUTED CARD OF CARD]; WordsPtr: TYPE = POINTER TO Basics.RawWords; ROPE: TYPE ~ Rope.ROPE; keepCounts: BOOL = TRUE; useDebug: BOOL = TRUE; pureDebug: BOOL = TRUE; defaultFastScan: BOOL ฌ TRUE; useFastDebug: BOOL = FALSE; keepFastCounts: BOOL = FALSE; fastScanEntries: CARD ฌ 0; fastScanLoops: CARD ฌ 0; fastScanScans: CARD ฌ 0; fastScanPass: CARD ฌ 0; fastScanHoriz: CARD ฌ 0; makePureCalls: CARD ฌ 0; advanceCalls: CARD ฌ 0; resetCalls: CARD ฌ 0; orBltCalls: CARD ฌ 0; moveLineCalls: CARD ฌ 0; sparsity: NAT ฌ 16; colorNames: ARRAY BIT OF ROPE = ["white", "black"]; dummy: Data ~ NEW[DataRep]; -- Used as lock for BuildRoots, holder for scratch stream ClipZero: PROC [x: INTEGER] RETURNS [NAT] = INLINE { RETURN [LOOPHOLE[Basics.BITAND[LOOPHOLE[x, WORD], Basics.BITRSHIFT[LOOPHOLE[x, WORD], bpw-1]-1], NAT]] }; ColorFromState: PROC [state: State] RETURNS [[0..1]] ~ INLINE { RETURN [ORD[state] MOD 2]; }; GetRunEntry: PROC [color: BIT, x: WORD] RETURNS [RunTabEntry] ~ INLINE { RETURN [runTabRef[(color * (2*runTableMod) + x) MOD (RunTabIndex.LAST+1)]]; }; GetTransition: PROC [lineTransitions: REF IndexSequenceRep, i: CARDINAL] RETURNS [INTEGER] ~ TRUSTED INLINE { RETURN [(LOOPHOLE[lineTransitions, IntPtr]+SIZE[IndexSequenceRep[0]])[i]]; }; SetTransition: PROC [lineTransitions: REF IndexSequenceRep, i: CARDINAL, j: INT] ~ TRUSTED INLINE { (LOOPHOLE[lineTransitions, IntPtr]+SIZE[IndexSequenceRep[0]])[i] ฌ j; }; FromStream: PUBLIC SAFE PROC [st: IO.STREAM, bitsPerLine: CARDINAL] RETURNS [Data] = CHECKED { data: Data ฌ NEW[DataRep ฌ []]; data.scanLength ฌ bitsPerLine; data.stream ฌ st; data.initIndex ฌ -1; -- means not known! data.useFastScan ฌ defaultFastScan; RETURN [data]; }; FillLineBuffer: PUBLIC SAFE PROC [data: Data, s: INTEGER, invert: BOOL ฌ FALSE] = TRUSTED { lineBuffer: ImagerSample.RasterSampleMap ฌ data.lineBuffer; IF lineBuffer # NIL THEN { copyData: CopyData ฌ data.copyData; IF copyData # NIL THEN { IF s >= data.sSize THEN data.end ฌ TRUE; data.sCurrent ฌ s; data.lineBufferValid ฌ FALSE; } ELSE { IF data.roots = NIL OR data.sCurrent > s THEN Reset[data]; UNTIL data.end OR data.sCurrent = s DO Advance[data] ENDLOOP; }; IF NOT data.lineBufferValid THEN { scanLength: NAT ~ data.scanLength; base: ImagerSample.BitAddress; linePtr: POINTER TO Basics.RawBits; base ฌ ImagerSample.GetBase[lineBuffer]; linePtr ฌ LOOPHOLE[base.word]; IF data.copyData # NIL THEN WITH data.copyData[data.sCurrent] SELECT FROM literal: REF Basics.RawBits => { IF invert THEN RasterOp.forwardOp[null][complement] [ dst: base, src: [LOOPHOLE[literal], 0], dstBpl: scanLength, srcBpl: scanLength, sSize: 1, fSize: scanLength] ELSE Basics.MoveBits[ dstBase: linePtr, dstStart: base.bit, srcBase: LOOPHOLE[literal], srcStart: 0, count: scanLength]; GO TO nowValid; }; trans: REF IndexSequenceRep => data.referenceTransitions ฌ trans; ENDCASE => ERROR; MoveLine[data: data, dstBase: linePtr, dstBitIndex: base.bit, min: 0, max: scanLength, invert: invert]; GO TO nowValid; EXITS nowValid => data.lineBufferValid ฌ TRUE; }; }; }; Close: PUBLIC ENTRY SAFE PROC [data: Data] = TRUSTED { data.stream ฌ NIL; }; MakePure: PUBLIC ENTRY SAFE PROC [data: Data] = TRUSTED { ENABLE { IO.EndOfStream => { ErrorEOF[data]; CONTINUE }; UNWIND => NULL; }; InternalPure[data]; }; InternalPure: PROC [data: Data] = { copyData: CopyData ฌ data.copyData; IF copyData = NIL THEN { fSize: NAT = data.scanLength; untracedZone: ZONE ~ SafeStorage.GetUntracedZone[]; copyLen: NAT ฌ 0; lim: NAT = IF data.sSize < 0 THEN NAT.LAST ELSE data.sSize; nextS: NAT ฌ 0; makePureCalls ฌ makePureCalls + 1; IF pureDebug AND data.debug # NIL THEN IO.PutF1[data.debug, "InternalPure, fSize = %g\n", [integer[fSize]]]; FOR s: NAT IN [0..lim) WHILE NOT data.end DO line: REF ฌ NIL; end: CARDINAL ฌ 0; IF pureDebug AND data.debug # NIL THEN IO.PutF1[data.debug, "InternalPure, s = %g\n", [integer[s]]]; IF data.roots = NIL OR data.sCurrent > s THEN Reset[data]; UNTIL data.end OR data.sCurrent = s DO Advance[data] ENDLOOP; IF data.end THEN EXIT; IF data.referenceTransitions = NIL THEN ERROR; end ฌ data.referenceTransitions.end; IF BITS[IndexSequenceRep[end]] >= fSize THEN { line ฌ untracedZone.NEW[Basics.RawBits[fSize]]; IF pureDebug AND data.debug # NIL THEN IO.PutF1[data.debug, "InternalPure, bits %g\n", [integer[fSize]]]; MoveLine[data: data, dstBase: LOOPHOLE[line], dstBitIndex: 0, min: 0, max: fSize]; } ELSE { new: REF IndexSequenceRep ฌ untracedZone.NEW[IndexSequenceRep[end]]; IF pureDebug AND data.debug # NIL THEN IO.PutF1[data.debug, "InternalPure, runs %g\n", [integer[end]]]; Basics.MoveWords[ dst: LOOPHOLE[@new[0]], src: LOOPHOLE[@data.referenceTransitions[0]], count: WORDS[IndexSequenceRep[end]]-WORDS[IndexSequenceRep[0]]]; new.end ฌ end; line ฌ new; }; IF s > lim THEN ERROR; IF s >= copyLen THEN { rLen: NAT = IF lim < NAT.LAST THEN lim ELSE copyLen+copyLen/2+8; revised: CopyData ฌ NEW[CopyDataRep[rLen]]; IF copyLen # 0 THEN Basics.MoveWords[ dst: LOOPHOLE[@revised[0]], src: LOOPHOLE[@copyData[0]], count: WORDS[CopyDataRep[copyLen]]-WORDS[CopyDataRep[0]]]; copyLen ฌ rLen; copyData ฌ revised; }; copyData[s] ฌ line; nextS ฌ s+1; ENDLOOP; IF pureDebug AND data.debug # NIL THEN IO.PutF1[data.debug, "InternalPure, sSize = %g\n", [integer[nextS]]]; data.sSize ฌ nextS; data.copyData ฌ copyData; data.end ฌ FALSE; }; }; FormatErrorDesc: ENTRY PROC [data: Data] RETURNS [ImagerError.ErrorDesc] ~ { error: ATOM = data.error; errorIndex: CARD = data.errorIndex; IF error = NIL THEN RETURN [[ok, NIL, NIL]]; data.error ฌ NIL; data.errorIndex ฌ 0; data.errorCount ฌ data.errorCount + 1; RETURN [[ $invalidCompressedSequence, IO.PutFLR["Error in CCITT-G4 encoding %g near bit index %g", LIST[[atom[error]], [cardinal[errorIndex]]]], LIST[[$ccittg4error, error], [$bitIndex, NEW[CARD ฌ errorIndex]]] ]]; }; WithData: PROC [proc: PROC [data: Data], ref: REF] ~ { WITH ref SELECT FROM data: Data => { proc[data]; IF data.error # NIL THEN { desc: ImagerError.ErrorDesc ~ FormatErrorDesc[data]; IF desc.code # ok THEN { IF data.errorCount >= 20 THEN ERROR ImagerError.Error[desc]; SIGNAL ImagerError.Warning[desc]; }; }; }; ENDCASE => ERROR; -- can't happen }; G4PixelArrayFromStream: PUBLIC SAFE PROC [st: IO.STREAM, lines: CARDINAL, bitsPerLine: CARDINAL] RETURNS [ImagerPixelArray.PixelArray] ~ CHECKED { data: Data = FromStream[st, bitsPerLine]; RETURN [G4PixelArrayFromData[data, lines, bitsPerLine]]; }; G4PixelArrayFromData: PUBLIC SAFE PROC [data: Data, lines: CARDINAL, bitsPerLine: CARDINAL] RETURNS [ImagerPixelArray.PixelArray] ~ TRUSTED { pa: ImagerPixelArray.PixelArray ฌ NEW [ImagerPixelArray.PixelArrayRep ฌ [ immutable: FALSE, samplesPerPixel: 1, sSize: lines, fSize: bitsPerLine, m: NIL, -- caller fills this in class: classCCITT4PixelArray, data: data ]]; RETURN [pa]; }; classCCITT4PixelArray: ImagerPixelArrayPrivate.PixelArrayClass ~ ImagerPixelArrayPrivate.NewClass[ type: $XeroxCCITT4, MaxSampleValue: XeroxCCITT4MaxSampleValue, Get: NIL, GetSamples: XeroxCCITT4GetSamples, Transfer: XeroxCCITT4Transfer, Copy: XeroxCCITT4Copy ]; XeroxCCITT4MaxSampleValue: SAFE PROC [pa: ImagerPixelArray.PixelArray, i: NAT] RETURNS [ImagerPixelArray.Sample] ~ CHECKED {RETURN [1]}; XeroxCCITT4GetSamples: SAFE PROC [pa: ImagerPixelArray.PixelArray, i: NAT, s, f: INT, buffer: ImagerSample.SampleBuffer, start: NAT, count: NAT] ~ TRUSTED { Inner: ENTRY PROC [data: Data] ~ { ENABLE { IO.EndOfStream => { ErrorEOF[data]; CONTINUE }; UNWIND => NULL; }; FillLineBuffer[data, s]; ImagerSample.GetSamples[map: data.lineBuffer, initIndex: [0, f], buffer: buffer, start: start, count: count]; }; WithData[Inner, pa.data]; }; XeroxCCITT4Transfer: SAFE PROC [pa: ImagerPixelArray.PixelArray, i: NAT, s, f: INT, dst: ImagerSample.SampleMap, dstMin: SF.Vec, size: SF.Vec, function: ImagerSample.Function] ~ TRUSTED { Inner: ENTRY PROC [data: Data] ~ { ENABLE { IO.EndOfStream => { ErrorEOF[data]; CONTINUE }; UNWIND => NULL; }; dstRaster: ImagerSample.RasterSampleMap ~ WITH dst SELECT FROM d: ImagerSample.RasterSampleMap => d ENDCASE => NIL; sSize: NAT ~ size.s; fSize: NAT ~ size.f; copyData: CopyData = data.copyData; IF copyData # NIL THEN { IF s >= data.sSize THEN {data.end ฌ TRUE; GO TO endErr}; data.sCurrent ฌ s; data.lineBufferValid ฌ FALSE; } ELSE { IF data.roots = NIL OR data.sCurrent > s THEN Reset[data]; UNTIL data.end OR data.sCurrent = s DO Advance[data] ENDLOOP; }; IF (function = [or, null] OR function = [null, null]) AND dstRaster # NIL AND ImagerSample.GetBitsPerSample[dstRaster] = 1 THEN { box: SF.Box ~ ImagerSample.GetBox[dstRaster]; base: RasterBasics.BitAddress ~ ImagerSample.GetBase[dstRaster]; bpl: NAT ~ ImagerSample.GetBitsPerLine[dstRaster]; dstBase: POINTER TO Basics.RawBits ~ LOOPHOLE[base.word]; lineIndex: CARD ~ dstMin.s-box.min.s; pixelIndex: CARD ~ dstMin.f-box.min.f; dmaxs: INT ~ dstMin.s+sSize; sSpace: CARD ~ box.max.s-dmaxs; -- for bounds check below. dmaxf: INT ~ dstMin.f+fSize; fSpace: CARD ~ box.max.f-dmaxf; -- for bounds check below. endf: NAT = f+fSize; fSpaceSrc: CARD ~ data.scanLength - endf; -- for bounds check below. bitIndex: CARD ฌ lineIndex * bpl + pixelIndex + base.bit; IF Basics.BITOR[Basics.BITOR[Basics.BITOR[Basics.BITOR[Basics.BITOR[ lineIndex, pixelIndex], sSpace], fSpace], fSpaceSrc], f] > NAT.LAST THEN Basics.RaiseBoundsFault[]; IF copyData # NIL THEN { FOR sSrc: INT IN [s..s+size.s) DO WITH data.copyData[s] SELECT FROM literal: REF Basics.RawBits => RasterOp.forwardOp[function.dstFunc][null] [ dst: [LOOPHOLE[dstBase], bitIndex], src: [LOOPHOLE[literal], 0], dstBpl: BITS[WORD], srcBpl: BITS[WORD], sSize: 1, fSize: fSize]; trans: REF IndexSequenceRep => { data.referenceTransitions ฌ trans; IF function = [or, null] THEN OrBltLine[data: data, dstBase: dstBase, dstBitIndex: bitIndex, min: f, max: endf] ELSE MoveLine[data: data, dstBase: dstBase, dstBitIndex: bitIndex, min: f, max: endf]; }; ENDCASE => GO TO endErr; bitIndex ฌ bitIndex + bpl; ENDLOOP; GO TO free; }; FOR sSrc: INT IN [s..s+size.s) DO UNTIL data.end OR data.sCurrent = sSrc DO Advance[data] ENDLOOP; IF data.end THEN GO TO endErr; IF function = [or, null] THEN OrBltLine[data: data, dstBase: dstBase, dstBitIndex: bitIndex, min: f, max: endf] ELSE MoveLine[data: data, dstBase: dstBase, dstBitIndex: bitIndex, min: f, max: endf]; bitIndex ฌ bitIndex + bpl; ENDLOOP; } ELSE { IF data.lineBuffer = NIL THEN { data.lineBuffer ฌ ImagerSample.ObtainScratchMap[[max: [1, data.scanLength]]]; needFree ฌ TRUE; }; FOR sSrc: INT IN [s..s+size.s) DO FillLineBuffer[data, sSrc]; IF data.end THEN GO TO endErr; ImagerSample.BasicTransfer[dst: dst, src: data.lineBuffer, dstMin: [dstMin.s+(sSrc-s), dstMin.f], srcMin: [0, f], size: [1, size.f], function: function]; ENDLOOP; }; GO TO free; EXITS endErr => {LogError[data, $eoi, 0]; IF needFree THEN FreeLineBuffer[data]}; free => IF needFree THEN FreeLineBuffer[data]; }; needFree: BOOL ฌ FALSE; WithData[Inner, pa.data]; }; XeroxCCITT4Copy: ImagerPixelArrayPrivate.CopyProc = TRUSTED { WithData[MakePure, pa.data]; pa.immutable ฌ TRUE; RETURN [pa]; }; transitionCountEstimate: NAT ฌ 400; Reset: PUBLIC PROC [data: Data] ~ { scanLength: INT ~ data.scanLength; tSize: NAT ~ MIN[transitionCountEstimate, scanLength] + 3; untracedZone: ZONE ~ SafeStorage.GetUntracedZone[]; IF keepCounts THEN resetCalls ฌ resetCalls + 1; data.nextLineState ฌ white; data.bitBuffer ฌ 0; data.goodBits ฌ 0; data.end ฌ FALSE; IF data.copyData # NIL THEN RETURN; IF data.roots = NIL THEN data.roots ฌ BuildRoots[dummy]; data.sCurrent ฌ -1; data.lineBufferValid ฌ FALSE; IF data.referenceTransitions = NIL THEN data.referenceTransitions ฌ untracedZone.NEW[IndexSequenceRep[tSize]]; data.referenceTransitions[0] ฌ -1; data.referenceTransitions[1] ฌ scanLength; data.referenceTransitions[2] ฌ scanLength; data.referenceTransitions.end ฌ 3; IF data.lineTransitions = NIL THEN data.lineTransitions ฌ untracedZone.NEW[IndexSequenceRep[tSize]]; IF data.stream = NIL THEN {data.end ฌ TRUE; RETURN}; IF data.initIndex < 0 THEN data.initIndex ฌ IO.GetIndex[data.stream ! IO.Error => CONTINUE] ELSE IO.SetIndex[data.stream, data.initIndex]; }; OrBltLine: PROC [data: Data, dstBase: POINTER TO Basics.RawBits, dstBitIndex: CARD, min: CARD, max: CARD] ~ { IF keepCounts THEN orBltCalls ฌ orBltCalls + 1; IF min < max THEN { rp: CardPtr ฌ LOOPHOLE[data.referenceTransitions, CardPtr] + SIZE[IndexSequenceRep[1]]; start: CARDINAL; fill: WORD ฌ WORD.LAST; p0: WordsPtr ฌ LOOPHOLE[dstBase, WordsPtr] + (dstBitIndex / bpw)*SIZE[WORD]; c0: BitCount ฌ dstBitIndex MOD bpw; WHILE rp[1] <= min DO rp ฌ rp + SIZE[WORD]*2; ENDLOOP; -- toss leading runs start ฌ MAX[rp[0], min]; -- clip leading visible run WHILE start < max DO lim: CARDINAL ฌ MIN[rp[1], max]; IF lim > start THEN { dstStart: CARD = (start-min) + c0; p: WordsPtr ฌ p0 + (dstStart / bpw)*SIZE[WORD]; dstMod: BitCount = dstStart MOD bpw; dstLim: CARD = dstMod + (lim - start); w: WORD ฌ Basics.BITRSHIFT[fill, dstMod]; words: CARDINAL ฌ dstLim / bpw; IF words # 0 THEN { p[0] ฌ Basics.BITOR[p[0], w]; p ฌ p + SIZE[WORD]; w ฌ fill; IF words > 1 THEN { words ฌ words - 1; WHILE words >= 4 DO p[0] ฌ w; p[1] ฌ w; p[2] ฌ w; p[3] ฌ w; p ฌ p + SIZE[WORD]*4; words ฌ words - 4; ENDLOOP; IF words = 0 THEN GO TO wordless; p[0] ฌ w; p ฌ p + SIZE[WORD]; IF words = 1 THEN GO TO wordless; p[0] ฌ w; p ฌ p + SIZE[WORD]; IF words = 2 THEN GO TO wordless; p[0] ฌ w; p ฌ p + SIZE[WORD]; EXITS wordless => {}; }; IF (dstLim MOD bpw) = 0 THEN GO TO noRem; }; w ฌ w - Basics.BITRSHIFT[fill, dstLim MOD bpw]; p[0] ฌ Basics.BITOR[p[0], w]; EXITS noRem => {}; }; rp ฌ rp + SIZE[WORD]*2; start ฌ rp[0]; ENDLOOP; }; }; altOrBltLine: PROC [data: Data, dstBase: POINTER TO Basics.RawBits, dstBitIndex: CARD, min: CARD, max: CARD] ~ { IF keepCounts THEN orBltCalls ฌ orBltCalls + 1; IF min < max THEN { rp: CardPtr ฌ LOOPHOLE[data.referenceTransitions, CardPtr] + SIZE[IndexSequenceRep[1]]; shift: BitCount ฌ dstBitIndex MOD bpw; p: WordsPtr ฌ LOOPHOLE[dstBase, WordsPtr] + (dstBitIndex/bpw)*SIZE[WORD]; w: WORD ฌ 0; fill: WORD ฌ 0; WHILE rp[0] <= min DO rp ฌ rp+SIZE[WORD]; fill ฌ Basics.BITNOT[fill]; ENDLOOP; WHILE min < max DO newMin: CARD = MIN[max, rp[0]]; outLim: CARD = (newMin - min) + shift; words: CARDINAL ฌ outLim / bpw; IF fill = 0 THEN { IF words # 0 THEN { IF w # 0 THEN {p[0] ฌ Basics.BITOR[p[0], w]; w ฌ 0}; p ฌ p + SIZE[WORD]*words; }; shift ฌ outLim MOD bpw; } ELSE { w ฌ w + Basics.BITRSHIFT[fill, shift]; IF words # 0 THEN { p[0] ฌ Basics.BITOR[p[0], w]; p ฌ p + SIZE[WORD]; w ฌ fill; IF words > 1 THEN { words ฌ words - 1; WHILE words >= 4 DO p[0] ฌ w; p[1] ฌ w; p[2] ฌ w; p[3] ฌ w; p ฌ p + SIZE[WORD]*4; words ฌ words - 4; ENDLOOP; IF words = 0 THEN GO TO wordless; p[0] ฌ w; p ฌ p + SIZE[WORD]; IF words = 1 THEN GO TO wordless; p[0] ฌ w; p ฌ p + SIZE[WORD]; IF words = 2 THEN GO TO wordless; p[0] ฌ w; p ฌ p + SIZE[WORD]; EXITS wordless => {}; }; }; shift ฌ outLim MOD bpw; w ฌ w - Basics.BITRSHIFT[fill, shift]; }; rp ฌ rp+SIZE[WORD]; min ฌ newMin; fill ฌ Basics.BITNOT[fill]; ENDLOOP; IF w # 0 AND shift # 0 THEN { mask: WORD = Basics.BITRSHIFT[WORD.LAST, shift]; w ฌ w - Basics.BITAND[w, mask]; p[0] ฌ Basics.BITOR[w, p[0]]; }; }; }; MoveLine: PROC [data: Data, dstBase: POINTER TO Basics.RawBits, dstBitIndex: CARD, min: CARD, max: CARD, invert: BOOL ฌ FALSE] ~ { IF keepCounts THEN moveLineCalls ฌ moveLineCalls + 1; IF min < max THEN { rp: CardPtr ฌ LOOPHOLE[data.referenceTransitions, CardPtr] + SIZE[IndexSequenceRep[1]]; shift: BitCount ฌ dstBitIndex MOD bpw; p: WordsPtr ฌ LOOPHOLE[dstBase, WordsPtr] + (dstBitIndex/bpw)*SIZE[WORD]; w: WORD ฌ 0; fill: WORD ฌ IF invert THEN WORD.LAST ELSE 0; WHILE rp[0] <= min DO rp ฌ rp+SIZE[WORD]; fill ฌ Basics.BITNOT[fill]; ENDLOOP; IF shift # 0 THEN { w ฌ p[0]; w ฌ w - Basics.BITRSHIFT[Basics.BITLSHIFT[w, shift], shift]; }; WHILE min < max DO newMin: CARD = MIN[max, rp[0]]; outLim: CARD = (newMin - min) + shift; words: CARDINAL ฌ outLim / bpw; w ฌ w + Basics.BITRSHIFT[fill, shift]; IF words # 0 THEN { p[0] ฌ w; p ฌ p + SIZE[WORD]; w ฌ fill; IF words > 1 THEN { words ฌ words - 1; WHILE words >= 4 DO p[0] ฌ w; p[1] ฌ w; p[2] ฌ w; p[3] ฌ w; p ฌ p + SIZE[WORD]*4; words ฌ words - 4; ENDLOOP; IF words = 0 THEN GO TO wordless; p[0] ฌ w; p ฌ p + SIZE[WORD]; IF words = 1 THEN GO TO wordless; p[0] ฌ w; p ฌ p + SIZE[WORD]; IF words = 2 THEN GO TO wordless; p[0] ฌ w; p ฌ p + SIZE[WORD]; EXITS wordless => {}; }; }; shift ฌ outLim MOD bpw; w ฌ w - Basics.BITRSHIFT[fill, shift]; rp ฌ rp+SIZE[WORD]; min ฌ newMin; fill ฌ Basics.BITNOT[fill]; ENDLOOP; IF shift # 0 THEN { mask: WORD = Basics.BITRSHIFT[WORD.LAST, shift]; w ฌ w - Basics.BITAND[w, mask]; p[0] ฌ w + Basics.BITAND[p[0], mask]; }; }; }; FreeLineBuffer: PROC [data: Data] ~ { lineBuffer: ImagerSample.RasterSampleMap ฌ data.lineBuffer; data.lineBufferValid ฌ FALSE; data.lineBuffer ฌ NIL; IF lineBuffer # NIL THEN ImagerSample.ReleaseScratchMap[lineBuffer]; }; ErrorEOF: PROC [data: Data] ~ { IF data.error = NIL THEN { data.error ฌ $eof }; data.end ฌ TRUE; data.errorIndex ฌ GetBitIndex[data]; }; GetBitIndex: PROC [data: Data] RETURNS [INT] = { init: INT = MAX[0, data.initIndex]; RETURN [(IO.GetIndex[data.stream]-init) * 8]; }; ByteArray: TYPE = PACKED ARRAY BYTE OF BYTE; reverseBitsTab: REF ByteArray = InitReverseBits[]; InitReverseBits: PROC RETURNS [REF ByteArray] = { new: REF ByteArray = NEW[ByteArray]; FOR b: BYTE IN BYTE DO w: WORD ฌ Basics.BITAND[b, 0AAH]/2 + Basics.BITAND[b, 055H]*2; w ฌ Basics.BITAND[w, 0CCH]/4 + Basics.BITAND[w, 033H]*4; w ฌ Basics.BITAND[w, 0F0H]/10H + Basics.BITAND[w, 00FH]*10H; new[b] ฌ w MOD 100H; ENDLOOP; RETURN [new]; }; Scan: PROC [j: INT, bit: [0..1], data: Data] RETURNS [INT] ~ TRUSTED { ref: REF IndexSequenceRep ~ data.referenceTransitions; min: INT ฌ MIN[j+1, LOOPHOLE[data.scanLength, NAT]]; i: CARDINAL ฌ data.referenceIndex; refi: INT ฌ 0; WHILE ref[i] > min DO i ฌ i - 1; ENDLOOP; IF bit # (i MOD 2) THEN i ฌ i + 1; WHILE (refi ฌ ref[i]) < min DO i ฌ i + 2 ENDLOOP; i ฌ MIN[i, ref.end-2]; data.referenceIndex ฌ i; IF useDebug AND data.debug # NIL THEN IO.PutF1[data.debug, "scan: %g\n", [integer[refi]]]; RETURN [refi-ClipZero[j]] }; LogError: PROC [data: Data, error: ATOM, bufferedBits: NAT] ~ { IF data.error = NIL THEN { data.error ฌ error; data.errorIndex ฌ GetBitIndex[data] - bufferedBits; IF data.debug # NIL THEN IO.PutF[data.debug, "LogError: %g, near bit index %g\n", [atom[error]], [integer[data.errorIndex]] ]; }; }; ExpandLineTransitions: PROC [data: Data] RETURNS [REF IndexSequenceRep] ~ { old: REF IndexSequenceRep ~ data.lineTransitions; oldSize: CARDINAL = old.size; newSize: CARDINAL = oldSize+oldSize/2+32; new: REF IndexSequenceRep ~ SafeStorage.GetUntracedZone[].NEW[IndexSequenceRep[newSize]]; FOR i: CARDINAL IN [0..oldSize) DO new[i] ฌ old[i]; ENDLOOP; new.end ฌ old.end; data.lineTransitions ฌ new; RETURN [new]; }; Advance: PUBLIC PROC [data: Data] ~ { scanLength: INT ~ data.scanLength; bitBuffer: CARD ฌ data.bitBuffer; -- buffered input bits goodBits: BitCount ฌ data.goodBits; -- number of good bits, left justified in bitBuffer Peek: PROC [n: BitCount] RETURNS [CARD] ~ INLINE { RETURN [Basics.BITRSHIFT[bitBuffer, LOOPHOLE[bpw-n, BitCount]]] }; EatBits: PROC [n: BitCount] ~ INLINE { goodBits ฌ LOOPHOLE[goodBits - n, BitCount]; bitBuffer ฌ Basics.BITLSHIFT[bitBuffer, n]; }; state: State ฌ data.nextLineState; current: Node ฌ data.roots[state]; val: INT ฌ 0; j: INT ฌ -1; lineTransitions: REF IndexSequenceRep ฌ data.lineTransitions; Fill: PROC [j0: INT, count: INT, bit: [0..1]] RETURNS [INT] ~ INLINE { j: INT = ClipZero[j0]; nj: INT ฌ j + count; IF nj > scanLength THEN { LogError[data, $longscan, goodBits]; nj ฌ scanLength; }; IF nj > j THEN { end: CARDINAL = lineTransitions.end; IF bit = (end MOD 2) THEN { IF useDebug AND debug # NIL THEN IO.PutF[debug, "fill: %g, bit: %g\n", [integer[j]], [rope[colorNames[bit]]] ]; IF end >= lineTransitions.size THEN lineTransitions ฌ ExpandLineTransitions[data]; SetTransition[lineTransitions, end, j]; lineTransitions.end ฌ end+1; }; }; RETURN [nj]; }; PullBits: PROC [needBits: [0..maxNeed] ฌ maxNeed] ~ INLINE { IF goodBits < needBits THEN { bitBuffer ฌ bitBuffer + MyGetBytes[data, goodBits]; goodBits ฌ data.goodBits; }; }; debug: IO.STREAM = data.debug; IF keepCounts THEN advanceCalls ฌ advanceCalls + 1; IF useDebug AND debug # NIL THEN { IF data.sCurrent < 0 THEN { IO.PutF1[debug, "Advance, [k: %g, ", [integer[data.k]] ]; IO.PutF1[debug, "sSize: %g, ", [integer[data.sSize]] ]; IO.PutF1[debug, "useFastScan: %g, ", [boolean[data.useFastScan]] ]; IO.PutF1[debug, "bitBuffer: %g, ", [cardinal[data.bitBuffer]] ]; IO.PutF1[debug, "goodBits: %g]\n", [cardinal[data.goodBits]] ]; }; IO.PutF[debug, "(begin: %g, bitindex: %g\n", [cardinal[data.sCurrent+1]], [cardinal[ClipZero[GetBitIndex[data] - goodBits]]]]; }; data.nextLineState ฌ white; data.referenceIndex ฌ 0; IF data.end THEN RETURN; SetTransition[lineTransitions, 0, -1]; lineTransitions.end ฌ 1; PullBits[]; IF bitBuffer = 0 AND IO.InlineEndOf[data.stream] THEN { IF useDebug AND debug # NIL THEN IO.PutRope[debug, "eod(0):\n"]; data.end ฌ TRUE; RETURN; }; SELECT TRUE FROM Basics.BITRSHIFT[bitBuffer, bpw-6] = 0 => {}; state NOT IN [white..black] => {}; ENDCASE => { SELECT TRUE FROM data.oneDimTag => j ฌ OneDimScan[data, j, bitBuffer, goodBits, 0]; data.useFastScan => j ฌ FastScan[data, j, bitBuffer, goodBits, 0]; ENDCASE => GO TO noChange; lineTransitions ฌ data.lineTransitions; goodBits ฌ data.goodBits; bitBuffer ฌ data.bitBuffer; state ฌ data.nextScanState; current ฌ data.roots[state]; EXITS noChange => {}; }; DO IF j >= scanLength THEN IF state NOT IN [hhwhite..unc] THEN EXIT; WITH current SELECT FROM tree: TreeNode => { needBits: BitCount ฌ tree.bitCount; branch: Branch; IF keepCounts THEN tree.count ฌ tree.count + 1; PullBits[needBits]; branch ฌ tree[Peek[needBits]]; needBits ฌ needBits - branch.reserveBits; IF useDebug AND debug # NIL THEN { IO.PutRope[debug, "tree: "]; PutB[debug, Peek[needBits], needBits, TRUE]; }; EatBits[needBits]; current ฌ branch.node; }; leaf: LeafNode => { val ฌ val + leaf.length; IF keepCounts THEN leaf.count ฌ leaf.count + 1; IF useDebug THEN { st: IO.STREAM = debug; IF st # NIL THEN { IO.PutRope[st, "action: "]; PutAction[st, leaf.action]; IO.PutF1[st, ", j: %g, state: ", [integer[j]] ]; PutState[st, state]; IO.PutF1[st, ", val: %g\n", [integer[val]] ]; }; }; SELECT leaf.action FROM null => NULL; utest => { PullBits[6]; SELECT TRUE FROM Peek[6] = 1 => { SetTag: PROC = INLINE { SELECT data.k FROM < 0 => {}; 0 => data.oneDimTag ฌ TRUE; ENDCASE => { PullBits[1]; data.oneDimTag ฌ VAL[Peek[1]]; EatBits[1]; }; }; EatBits[6]; SetTag[]; IF useDebug THEN { st: IO.STREAM = debug; IF st # NIL THEN { IO.PutRope[st, "eol: 000001"]; IF data.k > 0 THEN IO.PutRope[st, IF data.oneDimTag THEN "+1-D" ELSE "+2-D"]; IO.PutChar[st, '\n]; }; }; PullBits[12]; IF j > 0 AND data.k < 0 THEN LogError[data, $truncatedline, goodBits]; IF Basics.BITRSHIFT[bitBuffer, bpw-12] = 1 THEN { repeat: INTEGER ฌ IF data.k >= 0 THEN 6 ELSE 2; DO EatBits[12]; SetTag[]; repeat ฌ repeat - 1; IF repeat <= 1 THEN EXIT; PullBits[12]; IF Basics.BITRSHIFT[bitBuffer, bpw-12] # 1 THEN { LogError[data, $coding, goodBits]; EXIT; }; ENDLOOP; IF useDebug AND debug # NIL THEN IO.PutRope[debug, "eod:\n"]; data.end ฌ TRUE; RETURN; }; state ฌ white; SELECT TRUE FROM j >= 0 => EXIT; data.oneDimTag => j ฌ OneDimScan[data, j, bitBuffer, goodBits, 0]; data.useFastScan => j ฌ FastScan[data, j, bitBuffer, goodBits, 0]; ENDCASE => GO TO getCurrent; GO TO refresh; }; NOT data.oneDimTag AND Peek[4] = 15 => { EatBits[4]; state ฌ unc; }; data.oneDimTag AND Peek[6] = 15 => { EatBits[6]; state ฌ unc; }; ENDCASE => { LogError[data, $coding, goodBits]; EXIT }; GO TO getCurrent; }; emit => { j ฌ Fill[j, val, ColorFromState[state]]; val ฌ 0; }; scan => { bit: BIT ฌ ColorFromState[state]; scan: INT ฌ Scan[j, 1-bit, data] + val; IF scan < 0 THEN { LogError[data, $backup, goodBits]; scan ฌ 0; }; j ฌ Fill[j, scan, bit]; IF data.useFastScan AND NOT data.oneDimTag AND j < scanLength THEN { j ฌ FastScan[data, j, bitBuffer, goodBits, 1-bit]; GO TO refresh; }; val ฌ 0; }; pass => { bit: BIT ~ ColorFromState[state]; j ฌ Fill[j, Scan[j, 1-bit, data], bit]; j ฌ Fill[j, Scan[j, bit, data], bit]; val ฌ 0; }; one => { IF (j + val) > scanLength THEN { leftover: INT ~ val - (scanLength-j); j ฌ Fill[j, (scanLength-j), 0]; data.nextLineState ฌ VAL[ORD[State.uncb1]+leftover-1]; EXIT; } ELSE { j ฌ Fill[j, val-1, 0]; j ฌ Fill[j, 1, 1]; }; val ฌ 0; }; zeros => { IF (j + val) > scanLength THEN { leftover: INT ~ val - (scanLength-j); j ฌ Fill[j, (scanLength-j), 0]; data.nextLineState ฌ VAL[ORD[State.uncw1]+leftover-1]; EXIT; } ELSE { j ฌ Fill[j, val, 0]; }; val ฌ 0; }; ENDCASE; state ฌ leaf.new; IF data.oneDimTag THEN { state ฌ leaf.new; SELECT state FROM white => state ฌ hwhite; black => state ฌ hblack; ENDCASE; }; GO TO getCurrent; EXITS getCurrent => current ฌ data.roots[state]; refresh => { lineTransitions ฌ data.lineTransitions; goodBits ฌ data.goodBits; bitBuffer ฌ data.bitBuffer; state ฌ data.nextScanState; current ฌ data.roots[state]; data.nextLineState ฌ white; val ฌ 0; }; }; ENDCASE => { LogError[data, $coding, goodBits]; EXIT }; ENDLOOP; data.bitBuffer ฌ bitBuffer; data.goodBits ฌ goodBits; data.sCurrent ฌ data.sCurrent + 1; data.lineBufferValid ฌ FALSE; { end: CARDINAL = lineTransitions.end; IF end+1 >= lineTransitions.size THEN lineTransitions ฌ ExpandLineTransitions[data]; SetTransition[lineTransitions, end, scanLength]; SetTransition[lineTransitions, end+1, scanLength]; lineTransitions.end ฌ end + 2; }; IF useDebug AND debug # NIL THEN { IO.PutF1[debug, "end: %g transitions:", [cardinal[data.sCurrent]]]; FOR i: NAT IN [1..lineTransitions.end-1) DO IO.PutF1[debug, " %g", [integer[lineTransitions[i]]]]; ENDLOOP; IO.PutRope[debug, ")\n"]; }; data.lineTransitions ฌ data.referenceTransitions; data.referenceTransitions ฌ lineTransitions; }; runTabRef: REF RunTab ฌ InitRunTab[]; RunTab: TYPE = PACKED ARRAY RunTabIndex OF RunTabEntry; RunTabIndex: TYPE = [0..4*runTableMod); RunTabEntry: TYPE = MACHINE DEPENDENT RECORD [ val (0: 0..11): RunTabLen, bits (0: 12..15): RunTabBitCount ]; RunTabLen: TYPE = [0..4096); RunTabBitCount: TYPE = [0..runTableBits]; runTableBits: NAT = 13; runTableZeros: NAT = 4; runTableMod: NAT = 2**(runTableBits-runTableZeros); runTableDiv: NAT = 2**runTableZeros; runTableSplit: NAT = 64; InitRunTab: PROC RETURNS [REF RunTab] = { entries: NAT = 4*runTableMod; untracedZone: ZONE ~ SafeStorage.GetUntracedZone[]; tab: REF RunTab ฌ untracedZone.NEW[RunTab ฌ ALL [[0, 0]] ]; each: TransitionTableEntryProc ~ { base: CARDINAL ฌ 0; SELECT old FROM hwhite, hhwhite => {}; hblack, hhblack => base ฌ 2*runTableMod; ENDCASE => RETURN; { bits: RunTabBitCount = BitstringSize[bitstring]; e: RunTabEntry = [val: length, bits: bits]; shift: BitCount = runTableBits-bits; bv: WORD = Basics.BITLSHIFT[BitstringVal[bitstring], shift]; nx: CARDINAL ฌ Basics.BITLSHIFT[1, shift]; x: WORD ฌ bv; IF bv >= runTableMod THEN { nx ฌ nx / runTableDiv; x ฌ x / runTableDiv; base ฌ base + runTableMod; }; FOR i: CARDINAL IN [0..nx) DO tab[base+x+i] ฌ e; ENDLOOP; }; }; EnumerateTransitions[each]; RETURN [tab]; }; fastScanTab: REF FastScanTab = BuildFastScanTab[]; FastScanTab: TYPE = PACKED ARRAY FastScanTabIndex OF FastScanEntry; fastScanBits: NAT = 7; FastScanTabIndex: TYPE = [0..2**fastScanBits); FastScanEntry: TYPE = MACHINE DEPENDENT RECORD [ gb (0: 0..2): [0..fastScanBits] ฌ 0, delta (0: 3..5): [-3..3] ฌ 0, kind (0: 6..7): FastScanKind ฌ other]; FastScanKind: TYPE = {scan, pass, horiz, other}; BuildFastScanTab: PROC RETURNS [REF FastScanTab] = { untracedZone: ZONE ~ SafeStorage.GetUntracedZone[]; new: REF FastScanTab ฌ untracedZone.NEW[FastScanTab ฌ ALL[ [] ]]; FOR i: FastScanTabIndex IN FastScanTabIndex DO e: FastScanEntry ฌ [0, 0, other]; SELECT i FROM >= 64 => e ฌ [1, 0, scan]; >= 48 => e ฌ [3, 1, scan]; >= 32 => e ฌ [3, -1, scan]; >= 16 => e ฌ [3, 0, horiz]; >= 8 => e ฌ [4, 0, pass]; 6, 7 => e ฌ [6, 2, scan]; 4, 5 => e ฌ [6, -2, scan]; 3 => e ฌ [7, 3, scan]; 2 => e ฌ [7, -3, scan]; ENDCASE; new[i] ฌ e; ENDLOOP; RETURN [new]; }; MyGetBytes: SAFE PROC [data: Data, gb: BitCount] RETURNS [WORD] = TRUSTED <> { st: IO.STREAM = data.stream; w: WORD ฌ 0; tab: REF ByteArray = IF data.reverseBits THEN NIL ELSE reverseBitsTab; i: NAT ฌ st.bufferIndex; len: NAT ฌ st.bufferInputLength; WHILE gb < maxNeed DO b: BYTE; SELECT TRUE FROM i < len => {b ฌ st.buffer[i].ORD; st.bufferIndex ฌ i ฌ i+1}; IO.InlineEndOf[st] => b ฌ 0; ENDCASE => {b ฌ IO.InlineGetByte[st]; i ฌ st.bufferIndex; len ฌ st.bufferInputLength}; IF tab # NIL THEN b ฌ tab[b]; gb ฌ gb + BITS[BYTE]; w ฌ w + Basics.BITLSHIFT[b, bpw-gb]; ENDLOOP; data.goodBits ฌ gb; RETURN [w]; }; PutGoodBits: PROC [st: IO.STREAM, w: WORD, bits: NAT] = { THROUGH [0..MIN[bits, bpw]) DO IO.PutChar[st, '0+Basics.BITRSHIFT[w, bpw-1]]; w ฌ w + w; ENDLOOP; }; OneDimScan: PROC [data: Data, j: INT, bitBuffer: CARD, goodBits: BitCount, color: BIT] RETURNS [INT] ~ { nj: INT ฌ 0; i: CARDINAL ฌ data.referenceIndex; needBits: [0..maxNeed] ฌ maxNeed; scanLength: INTEGER = data.scanLength; EatBits: PROC ~ INLINE { IF useFastDebug AND data.debug # NIL THEN { IO.PutF1[data.debug, "Fast scan eat bits: %g, ", [integer[j]] ]; PutGoodBits[data.debug, bitBuffer, needBits]; IO.PutChar[data.debug, '\n]; }; goodBits ฌ LOOPHOLE[goodBits - needBits, BitCount]; bitBuffer ฌ Basics.BITLSHIFT[bitBuffer, needBits]; }; PullBits: PROC ~ INLINE { st: IO.STREAM = data.stream; index: CARDINAL ฌ st.bufferIndex; IF (index+3) < st.bufferInputLength AND data.reverseBits THEN { bp: BytesPtr = LOOPHOLE[st.buffer, BytesPtr] + SIZE[TEXT[0]]; DO goodBits ฌ LOOPHOLE[goodBits + 8, BitCount]; bitBuffer ฌ bitBuffer + Basics.BITLSHIFT[bp[index], LOOPHOLE[bpw-goodBits, BitCount]]; index ฌ index + 1; IF goodBits >= maxNeed THEN {st.bufferIndex ฌ index; GO TO done}; ENDLOOP; }; bitBuffer ฌ bitBuffer + MyGetBytes[data, goodBits]; goodBits ฌ data.goodBits; EXITS done => {}; }; Fill: PROC ~ INLINE { jb: NAT = ClipZero[j]; lineTransitions: REF IndexSequenceRep ฌ data.lineTransitions; end: CARDINAL = lineTransitions.end; IF nj > jb AND color = (end MOD 2) THEN { IF end >= lineTransitions.size THEN lineTransitions ฌ ExpandLineTransitions[data]; IF useFastDebug AND data.debug # NIL THEN { IO.PutF1[data.debug, "Fast scan emit transition: %g, ", [integer[jb]] ]; IO.PutRope[data.debug, colorNames[color]]; IO.PutChar[data.debug, '\n]; }; SetTransition[lineTransitions, end, jb]; lineTransitions.end ฌ end+1; }; j ฌ nj; }; IF data.debug # NIL THEN { IO.PutRope[data.debug, "OneDimScan entry\n"]; }; WHILE j < scanLength DO IF goodBits < runTableBits THEN PullBits[]; IF Basics.BITRSHIFT[bitBuffer, bpw-8] = 0 THEN EXIT; nj ฌ ClipZero[j]; DO x: WORD ฌ Basics.BITRSHIFT[bitBuffer, bpw-runTableBits]; IF x >= runTableMod THEN x ฌ runTableMod + x / runTableDiv; { e: RunTabEntry = GetRunEntry[color, x]; v: INT = e.val; needBits ฌ e.bits; IF needBits = 0 THEN EXIT; EatBits[]; nj ฌ nj + v; IF v < runTableSplit THEN EXIT; }; IF goodBits < runTableBits THEN PullBits[]; ENDLOOP; IF nj > scanLength THEN { LogError[data, $longscan, goodBits]; nj ฌ scanLength; }; IF data.debug # NIL THEN { IO.PutF1[data.debug, "OneDimScan fill: %g, ", [integer[nj]] ]; IO.PutRope[data.debug, colorNames[color]]; IO.PutChar[data.debug, '\n]; }; Fill[]; -- nj, color; j ฌ nj color ฌ 1 - color; ENDLOOP; IF j > scanLength THEN { LogError[data, $longscan, goodBits]; j ฌ scanLength; }; data.nextScanState ฌ VAL[color]; IF data.debug # NIL THEN { IO.PutF1[data.debug, "OneDimScan exit: %g, ", [integer[j]] ]; PutGoodBits[data.debug, bitBuffer, goodBits]; IO.PutChar[data.debug, '\n]; }; data.referenceIndex ฌ i; data.bitBuffer ฌ bitBuffer; data.goodBits ฌ goodBits; RETURN [j]; }; FastScan: PROC [data: Data, j: INT, bitBuffer: CARD, goodBits: BitCount, color: BIT] RETURNS [INT] ~ { nj: INT ฌ 0; i: CARDINAL ฌ data.referenceIndex; needBits: [0..maxNeed] ฌ maxNeed; scanLength: INTEGER = LOOPHOLE[data.scanLength, INTEGER]; EatBits: PROC ~ INLINE { IF useFastDebug AND data.debug # NIL THEN { IO.PutF1[data.debug, "Fast scan eat bits: %g, ", [integer[j]] ]; PutGoodBits[data.debug, bitBuffer, needBits]; IO.PutChar[data.debug, '\n]; }; goodBits ฌ LOOPHOLE[goodBits - needBits, BitCount]; bitBuffer ฌ Basics.BITLSHIFT[bitBuffer, needBits]; }; PullBits: PROC ~ INLINE { st: IO.STREAM = data.stream; index: CARDINAL ฌ st.bufferIndex; IF (index+3) < st.bufferInputLength AND data.reverseBits THEN { bp: BytesPtr = LOOPHOLE[st.buffer, BytesPtr] + SIZE[TEXT[0]]; DO goodBits ฌ LOOPHOLE[goodBits + 8, BitCount]; bitBuffer ฌ bitBuffer + Basics.BITLSHIFT[bp[index], LOOPHOLE[bpw-goodBits, BitCount]]; index ฌ index + 1; IF goodBits >= maxNeed THEN {st.bufferIndex ฌ LOOPHOLE[index, INT]; GO TO done}; ENDLOOP; }; bitBuffer ฌ bitBuffer + MyGetBytes[data, goodBits]; goodBits ฌ data.goodBits; EXITS done => {}; }; Fill: PROC ~ INLINE { jb: NAT = ClipZero[j]; lineTransitions: REF IndexSequenceRep ฌ data.lineTransitions; end: CARDINAL = lineTransitions.end; IF nj > jb AND color = (end MOD 2) THEN { IF end >= lineTransitions.size THEN lineTransitions ฌ ExpandLineTransitions[data]; IF useFastDebug AND data.debug # NIL THEN { IO.PutF1[data.debug, "Fast scan emit transition: %g, ", [integer[jb]] ]; IO.PutRope[data.debug, colorNames[color]]; IO.PutChar[data.debug, '\n]; }; SetTransition[lineTransitions, end, jb]; lineTransitions.end ฌ end+1; }; j ฌ nj; }; IF keepFastCounts THEN fastScanEntries ฌ fastScanEntries + 1; IF useFastDebug AND data.debug # NIL THEN IO.PutF1[data.debug, "Fast scan entry: %g\n", [integer[j]] ]; WHILE j < scanLength DO IF keepFastCounts THEN fastScanLoops ฌ fastScanLoops + 1; IF goodBits < fastScanBits THEN PullBits[]; { b: FastScanTabIndex = LOOPHOLE[ Basics.BITRSHIFT[bitBuffer, bpw-fastScanBits], FastScanTabIndex]; e: FastScanEntry = fastScanTab[b]; SELECT e.kind FROM scan => { ref: REF IndexSequenceRep ~ data.referenceTransitions; WHILE GetTransition[ref, i] > j+1 DO i ฌ i - 1; ENDLOOP; i ฌ i + (1 + color + i) MOD 2; WHILE (nj ฌ GetTransition[ref, i]) <= j DO i ฌ i + 2; ENDLOOP; nj ฌ e.delta + nj; { end: CARDINAL = ref.end-2; IF i > end THEN i ฌ end}; IF nj < j THEN GO TO backup; IF keepFastCounts THEN fastScanScans ฌ fastScanScans + 1; needBits ฌ e.gb; EatBits[]; Fill[]; -- nj, color; j ฌ nj color ฌ 1 - color; }; horiz => { IF keepFastCounts THEN fastScanHoriz ฌ fastScanHoriz + 1; needBits ฌ 3; EatBits[]; -- 001 is the horizontal code THROUGH [0..1] DO nj ฌ ClipZero[j]; DO IF goodBits < runTableBits THEN PullBits[]; { x: WORD ฌ Basics.BITRSHIFT[bitBuffer, bpw-runTableBits]; IF x >= runTableMod THEN x ฌ runTableMod + x / runTableDiv; { e: RunTabEntry = GetRunEntry[color, x]; v: INT = e.val; needBits ฌ e.bits; IF needBits = 0 THEN GO TO coding; EatBits[]; nj ฌ nj + v; IF v < runTableSplit THEN EXIT; }; }; ENDLOOP; IF nj > scanLength THEN { LogError[data, $longscan, goodBits]; nj ฌ scanLength; }; Fill[]; -- nj, color; j ฌ nj color ฌ 1 - color; ENDLOOP; }; pass => { ref: REF IndexSequenceRep ~ data.referenceTransitions; WHILE GetTransition[ref, i] > j+1 DO i ฌ i - 1; ENDLOOP; i ฌ i + (1 + color + i) MOD 2; WHILE (nj ฌ GetTransition[ref, i]) <= j DO i ฌ i + 2; ENDLOOP; i ฌ i + 1; { end: CARDINAL = ref.end-2; IF i > end THEN i ฌ end}; nj ฌ GetTransition[ref, i]; IF keepFastCounts THEN fastScanPass ฌ fastScanPass + 1; needBits ฌ 4; EatBits[]; -- 0001 Fill[]; -- nj, color; j ฌ nj }; ENDCASE => EXIT; EXITS backup => {LogError[data, $backup, goodBits]; EXIT}; coding => {LogError[data, $coding, goodBits]; EXIT}; }; ENDLOOP; IF j > scanLength THEN { LogError[data, $longscan, goodBits]; j ฌ scanLength; }; data.nextScanState ฌ VAL[color]; IF useFastDebug AND data.debug # NIL THEN { IO.PutF1[data.debug, "Fast scan exit: %g, ", [integer[j]] ]; PutGoodBits[data.debug, bitBuffer, goodBits]; IO.PutChar[data.debug, '\n]; }; data.referenceIndex ฌ i; data.bitBuffer ฌ bitBuffer; data.goodBits ฌ goodBits; RETURN [j]; }; Bitstring: TYPE ~ PACKED ARRAY BitCount OF BIT; L: PROC [a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24: BIT ฌ 0] RETURNS [Bitstring] ~ INLINE { RETURN [[ a0,a1,a2,a3,a4,a5,a6,a7,a8,a9, a10,a11,a12,a13,a14,a15,a16,a17,a18,a19, a20,a21,a22,a23,a24,0,0,0,0,0,0,0 ]] }; Z: BIT ~ 1; -- terminator for Bitstring data BitstringSize: PROC [b: Bitstring] RETURNS [BitCount] ~ { FOR i: NAT DECREASING IN BitCount DO IF b[i] = Z THEN RETURN [i] ENDLOOP; ERROR; }; BitstringFetch: PROC [b: Bitstring, i: INT] RETURNS [BIT] ~ { RETURN[b[i]]; }; BitstringVal: PROC [b: Bitstring] RETURNS [CARDINAL] ~ { c: CARDINAL ฌ LOOPHOLE[b]; IF c # 0 THEN WHILE c MOD 2 # Z DO c ฌ c / 2; ENDLOOP; RETURN [c / 2]; }; TransitionTableEntryProc: TYPE ~ PROC [ old: State, bitstring: Bitstring, new: State, action: Action, length: INT ]; NewTreeNode: PROC [bitCount: BitCount ฌ 1] RETURNS [TreeNode] ~ { new: TreeNode ~ NEW[NodeRep.internal[2**bitCount]]; new.bitCount ฌ bitCount; RETURN [new] }; MakeBranch: PROC [reserveBits: BitCount, node: Node] RETURNS [Branch] ~ { RETURN[[reserveBits, node]]; }; DumpRoots: PUBLIC SAFE PROC [st: IO.STREAM, clear: BOOL] ~ TRUSTED { IF st # NIL THEN { roots: REF ARRAY State OF Node ฌ BuildRoots[dummy]; IF makePureCalls # 0 THEN IO.PutF1[st, "makePureCalls: %g\n", [cardinal[makePureCalls]] ]; IF (advanceCalls + resetCalls + orBltCalls + moveLineCalls) # 0 THEN { IO.PutF1[st, "advanceCalls: %g\n", [cardinal[advanceCalls]] ]; IO.PutF1[st, "resetCalls: %g\n", [cardinal[resetCalls]] ]; IO.PutF1[st, "orBltCalls: %g\n", [cardinal[orBltCalls]] ]; IO.PutF1[st, "moveLineCalls: %g\n", [cardinal[moveLineCalls]] ]; IF clear THEN advanceCalls ฌ resetCalls ฌ orBltCalls ฌ moveLineCalls ฌ 0; }; IF fastScanEntries # 0 THEN { IO.PutF1[st, "fastScanEntries: %g\n", [cardinal[fastScanEntries]] ]; IO.PutF1[st, "fastScanLoops: %g\n", [cardinal[fastScanLoops]] ]; IO.PutF1[st, "fastScanScans: %g\n", [cardinal[fastScanScans]] ]; IO.PutF1[st, "fastScanPass: %g\n", [cardinal[fastScanPass]] ]; IO.PutF1[st, "fastScanHoriz: %g\n", [cardinal[fastScanHoriz]] ]; IF clear THEN fastScanEntries ฌ fastScanLoops ฌ fastScanScans ฌ fastScanPass ฌ fastScanHoriz ฌ 0; }; IO.PutRope[st, "\n(case state"]; FOR s: State IN State DO n: Node = roots[s]; IF n # NIL THEN { IO.PutRope[st, "\n (("]; PutState[st, s]; IO.PutRope[st, ") "]; DumpTree[st, n, 2, clear]; IO.PutRope[st, ")"]; }; ENDLOOP; IO.PutRope[st, ")\n"]; }; }; BuildRoots: ENTRY PROC [data: Data] RETURNS [REF ARRAY State OF Node] ~ { IF data.roots = NIL THEN { data.roots ฌ BuildTrees[] }; RETURN [data.roots] }; BuildTrees: PROC RETURNS [REF ARRAY State OF Node] ~ { roots: REF ARRAY State OF Node ฌ NEW[ARRAY State OF Node]; Each: TransitionTableEntryProc ~ { size: INT ~ BitstringSize[bitstring]; IF size = 0 THEN { roots[old] ฌ NEW[NodeRep.leaf ฌ [0, leaf[new, action, length]]]; } ELSE { s: TreeNode ฌ NARROW[roots[old]]; FOR i: INT IN [0..size-1) DO c: BIT ~ BitstringFetch[bitstring, i]; IF s.d[c].node = NIL THEN s.d[c] ฌ MakeBranch[0, NewTreeNode[]]; s ฌ NARROW[s.d[c].node]; ENDLOOP; s.d[BitstringFetch[bitstring, size-1]] ฌ MakeBranch[0, NEW[NodeRep.leaf ฌ [0, leaf[new, action, length]]]]; }; }; FOR s: State IN State DO roots[s] ฌ NewTreeNode[]; ENDLOOP; EnumerateTransitions[Each]; FOR s: State IN State DO roots[s] ฌ OptimizeTree[roots[s]]; ENDLOOP; RETURN [roots] }; PutB: PROC [st: IO.STREAM, i: CARD, bitCount: NAT, nl: BOOL ฌ FALSE] ~ { IF st # NIL THEN { FOR k: CARD ฌ 2**(bitCount-1), k/2 UNTIL k=0 DO IO.PutChar[st, IF Basics.BITAND[i, k] = 0 THEN '0 ELSE '1]; ENDLOOP; IF nl THEN IO.PutChar[st, '\n]; }; }; Indent: PROC [st: IO.STREAM, i: NAT] ~ { IF st # NIL THEN { IO.PutRope[st, "\n"]; THROUGH [0..i) DO IO.PutRope[st, " "] ENDLOOP; }; }; PutAction: PROC [st: IO.STREAM, action: Action] ~ { IF st # NIL THEN IO.PutRope[st, SELECT action FROM null=>"null", utest=>"utest", emit=>"emit", scan=>"scan", pass=>"pass", one=>"one", zeros=>"zeros" ENDCASE=>"??"]; }; PutState: PROC [st: IO.STREAM, state: State] ~ { IF st # NIL THEN { IO.PutRope[st, SELECT state FROM white=>"white", black=>"black", hwhite=>"hwhite", hblack=>"hblack", hhwhite=>"hhwhite", hhblack=>"hhblack", unc=>"unc", uncb1=>"uncb1", uncb2=>"uncb2", uncb3=>"uncb3", uncb4=>"uncb4", uncb5=>"uncb5", uncw1=>"uncw1", uncw2=>"uncw2", uncw3=>"uncw3", uncw4=>"uncw4", uncw5=>"uncw5", eoi=>"eoi" ENDCASE=>"??"]; }; }; DumpTree: PROC [st: IO.STREAM, node: Node, nest: NAT, clear: BOOL] ~ { IF node = NIL THEN {IO.PutRope[st, "(NIL)"]; RETURN}; WITH node SELECT FROM tree: TreeNode => { i: NAT ฌ 0; size: NAT = tree.size; Indent[st, nest]; IF tree.count # 0 THEN IO.PutF1[st, "[%g] ", [cardinal[tree.count]]]; tree.count ฌ 0; IO.PutF1[st, "(case (peek %g)", [integer[tree.bitCount]]]; WHILE i < size DO sep: ROPE ฌ NIL; elem: Branch ฌ tree[i]; i0: NAT = i; Indent[st, nest+1]; IO.PutRope[st, "((#b"]; PutB[st, i, tree.bitCount]; WHILE i+1 < size AND tree[i+1] = elem DO i ฌ i+1; elem ฌ tree[i]; ENDLOOP; IF i # i0 THEN { IO.PutRope[st, "..#b"]; PutB[st, i, tree.bitCount]; }; IO.PutRope[st, ") "]; IF elem.node = NIL THEN IO.PutRope[st, "NIL"] ELSE { IO.PutF1[st, "(accept %g) ", [integer[tree.bitCount-elem.reserveBits]]]; DumpTree[st, elem.node, nest+2, clear]; }; IO.PutRope[st, ")"]; i ฌ i + 1; ENDLOOP; IO.PutRope[st, ")"]; }; leaf: LeafNode => { IF leaf.count # 0 THEN IO.PutF1[st, "[%g] ", [cardinal[leaf.count]]]; leaf.count ฌ 0; IO.PutRope[st, "("]; PutAction[st, leaf.action]; IO.PutF1[st, " %g ", [integer[leaf.length]]]; PutState[st, leaf.new]; IO.PutRope[st, ")"]; }; ENDCASE => ERROR; }; Punt: ERROR ~ CODE; -- prevent optimizer from looking beyond eoi. CountLive: PROC [node: Node, depth: NAT] RETURNS [NAT] ~ { IF node = NIL THEN RETURN [0]; IF depth = 0 THEN RETURN [1]; WITH node SELECT FROM tree: TreeNode => { count: NAT ฌ 0; FOR i: NAT IN [0..tree.size) DO branch: Branch ~ tree[i]; child: Node ~ branch.node; IF child # NIL THEN count ฌ count + CountLive[child, depth-1]; ENDLOOP; RETURN [count] }; leaf: LeafNode => { IF leaf.new = eoi THEN ERROR Punt[]; RETURN [1]; }; ENDCASE => RETURN [1]; }; EnumerateLive: PROC [node: Node, depth: NAT, index: CARD, visit: PROC [CARD, Branch]] ~ { IF depth = 0 THEN { visit[index, MakeBranch[depth, OptimizeTree[node]]] } ELSE { WITH node SELECT FROM tree: TreeNode => { IF tree.size # 2 THEN ERROR; FOR i: NAT IN [0..2) DO branch: Branch ~ tree[i]; child: Node ~ branch.node; IF child # NIL THEN EnumerateLive[child, depth-1, index*2+i, visit]; ENDLOOP; }; ENDCASE => { ix: CARD ~ index*2**depth; branch: Branch ~ MakeBranch[depth, OptimizeTree[node]]; FOR j: CARD IN [0..2**depth) DO visit[ix + j, branch]; ENDLOOP; }; }; }; SetSparsityInner: ENTRY PROC [data: Data, new: NAT] RETURNS [old: NAT] ~ { old ฌ sparsity; sparsity ฌ new; data.roots ฌ NIL; }; SetSparsity: PROC [new: CARD] RETURNS [CARD] ~ { IF new IN [1..256] THEN RETURN [SetSparsityInner[dummy, new]] ELSE RETURN [0]; }; OptimizeTree: PROC [node: Node] RETURNS [Node] ~ { WITH node SELECT FROM tree: TreeNode => { bitCount: CARD ฌ 1; { ENABLE Punt => GO TO punt; DO trialCount: CARD ฌ bitCount+1; x: NAT ฌ CountLive[tree, trialCount]; -- number of distinct paths at trial fanout IF sparsity*x >= 2**trialCount THEN { bitCount ฌ trialCount } ELSE EXIT; ENDLOOP; EXITS punt => {}; }; IF bitCount = tree.bitCount THEN RETURN [tree] ELSE { new: TreeNode ~ NewTreeNode[bitCount]; Plug: PROC [i: CARD, branch: Branch] ~ { new[i] ฌ branch }; EnumerateLive[tree, bitCount, 0, Plug]; RETURN [new]; }; }; ENDCASE => RETURN [node]; }; EnumerateTransitions: PROC [T: TransitionTableEntryProc] ~ { {V: PROC [length: INT, bitstring: Bitstring] ~ { T[white, bitstring, black, scan, length]; T[black, bitstring, white, scan, length]}; V[0, L[1,Z]]; V[1, L[0,1,1,Z]]; V[2, L[0,0,0,0,1,1,Z]]; V[3, L[0,0,0,0,0,1,1,Z]]; V[-1, L[0,1,0,Z]]; V[-2, L[0,0,0,0,1,0,Z]]; V[-3, L[0,0,0,0,0,1,0,Z]]; }; T[white, L[0,0,1,Z], hwhite, null, 0]; T[black, L[0,0,1,Z], hblack, null, 0]; FOR s: State IN [white..black] DO T[s, L[0,0,0,1,Z], s, pass, 0]; T[s, L[0,0,0,0,0,0,Z], unc, utest, 0]; ENDLOOP; {W: PROC [length: INT, bitstring: Bitstring] ~ { T[hwhite, bitstring, hhblack, emit, length]; T[hhwhite, bitstring, black, emit, length]}; W[00, L[0,0,1,1,0,1,0,1,Z]]; W[01, L[0,0,0,1,1,1,Z]]; W[02, L[0,1,1,1,Z]]; W[03, L[1,0,0,0,Z]]; W[04, L[1,0,1,1,Z]]; W[05, L[1,1,0,0,Z]]; W[06, L[1,1,1,0,Z]]; W[07, L[1,1,1,1,Z]]; W[08, L[1,0,0,1,1,Z]]; W[09, L[1,0,1,0,0,Z]]; W[10, L[0,0,1,1,1,Z]]; W[11, L[0,1,0,0,0,Z]]; W[12, L[0,0,1,0,0,0,Z]]; W[13, L[0,0,0,0,1,1,Z]]; W[14, L[1,1,0,1,0,0,Z]]; W[15, L[1,1,0,1,0,1,Z]]; W[16, L[1,0,1,0,1,0,Z]]; W[17, L[1,0,1,0,1,1,Z]]; W[18, L[0,1,0,0,1,1,1,Z]]; W[19, L[0,0,0,1,1,0,0,Z]]; W[20, L[0,0,0,1,0,0,0,Z]]; W[21, L[0,0,1,0,1,1,1,Z]]; W[22, L[0,0,0,0,0,1,1,Z]]; W[23, L[0,0,0,0,1,0,0,Z]]; W[24, L[0,1,0,1,0,0,0,Z]]; W[25, L[0,1,0,1,0,1,1,Z]]; W[26, L[0,0,1,0,0,1,1,Z]]; W[27, L[0,1,0,0,1,0,0,Z]]; W[28, L[0,0,1,1,0,0,0,Z]]; W[29, L[0,0,0,0,0,0,1,0,Z]]; W[30, L[0,0,0,0,0,0,1,1,Z]]; W[31, L[0,0,0,1,1,0,1,0,Z]]; W[32, L[0,0,0,1,1,0,1,1,Z]]; W[33, L[0,0,0,1,0,0,1,0,Z]]; W[34, L[0,0,0,1,0,0,1,1,Z]]; W[35, L[0,0,0,1,0,1,0,0,Z]]; W[36, L[0,0,0,1,0,1,0,1,Z]]; W[37, L[0,0,0,1,0,1,1,0,Z]]; W[38, L[0,0,0,1,0,1,1,1,Z]]; W[39, L[0,0,1,0,1,0,0,0,Z]]; W[40, L[0,0,1,0,1,0,0,1,Z]]; W[41, L[0,0,1,0,1,0,1,0,Z]]; W[42, L[0,0,1,0,1,0,1,1,Z]]; W[43, L[0,0,1,0,1,1,0,0,Z]]; W[44, L[0,0,1,0,1,1,0,1,Z]]; W[45, L[0,0,0,0,0,1,0,0,Z]]; W[46, L[0,0,0,0,0,1,0,1,Z]]; W[47, L[0,0,0,0,1,0,1,0,Z]]; W[48, L[0,0,0,0,1,0,1,1,Z]]; W[49, L[0,1,0,1,0,0,1,0,Z]]; W[50, L[0,1,0,1,0,0,1,1,Z]]; W[51, L[0,1,0,1,0,1,0,0,Z]]; W[52, L[0,1,0,1,0,1,0,1,Z]]; W[53, L[0,0,1,0,0,1,0,0,Z]]; W[54, L[0,0,1,0,0,1,0,1,Z]]; W[55, L[0,1,0,1,1,0,0,0,Z]]; W[56, L[0,1,0,1,1,0,0,1,Z]]; W[57, L[0,1,0,1,1,0,1,0,Z]]; W[58, L[0,1,0,1,1,0,1,1,Z]]; W[59, L[0,1,0,0,1,0,1,0,Z]]; W[60, L[0,1,0,0,1,0,1,1,Z]]; W[61, L[0,0,1,1,0,0,1,0,Z]]; W[62, L[0,0,1,1,0,0,1,1,Z]]; W[63, L[0,0,1,1,0,1,0,0,Z]]; }; {B: PROC [length: INT, bitstring: Bitstring] ~ { T[hhblack, bitstring, white, emit, length]; T[hblack, bitstring, hhwhite, emit, length]}; B[00, L[0,0,0,0,1,1,0,1,1,1,Z]]; B[01, L[0,1,0,Z]]; B[02, L[1,1,Z]]; B[03, L[1,0,Z]]; B[04, L[0,1,1,Z]]; B[05, L[0,0,1,1,Z]]; B[06, L[0,0,1,0,Z]]; B[07, L[0,0,0,1,1,Z]]; B[08, L[0,0,0,1,0,1,Z]]; B[09, L[0,0,0,1,0,0,Z]]; B[10, L[0,0,0,0,1,0,0,Z]]; B[11, L[0,0,0,0,1,0,1,Z]]; B[12, L[0,0,0,0,1,1,1,Z]]; B[13, L[0,0,0,0,0,1,0,0,Z]]; B[14, L[0,0,0,0,0,1,1,1,Z]]; B[15, L[0,0,0,0,1,1,0,0,0,Z]]; B[16, L[0,0,0,0,0,1,0,1,1,1,Z]]; B[17, L[0,0,0,0,0,1,1,0,0,0,Z]]; B[18, L[0,0,0,0,0,0,1,0,0,0,Z]]; B[19, L[0,0,0,0,1,1,0,0,1,1,1,Z]]; B[20, L[0,0,0,0,1,1,0,1,0,0,0,Z]]; B[21, L[0,0,0,0,1,1,0,1,1,0,0,Z]]; B[22, L[0,0,0,0,0,1,1,0,1,1,1,Z]]; B[23, L[0,0,0,0,0,1,0,1,0,0,0,Z]]; B[24, L[0,0,0,0,0,0,1,0,1,1,1,Z]]; B[25, L[0,0,0,0,0,0,1,1,0,0,0,Z]]; B[26, L[0,0,0,0,1,1,0,0,1,0,1,0,Z]]; B[27, L[0,0,0,0,1,1,0,0,1,0,1,1,Z]]; B[28, L[0,0,0,0,1,1,0,0,1,1,0,0,Z]]; B[29, L[0,0,0,0,1,1,0,0,1,1,0,1,Z]]; B[30, L[0,0,0,0,0,1,1,0,1,0,0,0,Z]]; B[31, L[0,0,0,0,0,1,1,0,1,0,0,1,Z]]; B[32, L[0,0,0,0,0,1,1,0,1,0,1,0,Z]]; B[33, L[0,0,0,0,0,1,1,0,1,0,1,1,Z]]; B[34, L[0,0,0,0,1,1,0,1,0,0,1,0,Z]]; B[35, L[0,0,0,0,1,1,0,1,0,0,1,1,Z]]; B[36, L[0,0,0,0,1,1,0,1,0,1,0,0,Z]]; B[37, L[0,0,0,0,1,1,0,1,0,1,0,1,Z]]; B[38, L[0,0,0,0,1,1,0,1,0,1,1,0,Z]]; B[39, L[0,0,0,0,1,1,0,1,0,1,1,1,Z]]; B[40, L[0,0,0,0,0,1,1,0,1,1,0,0,Z]]; B[41, L[0,0,0,0,0,1,1,0,1,1,0,1,Z]]; B[42, L[0,0,0,0,1,1,0,1,1,0,1,0,Z]]; B[43, L[0,0,0,0,1,1,0,1,1,0,1,1,Z]]; B[44, L[0,0,0,0,0,1,0,1,0,1,0,0,Z]]; B[45, L[0,0,0,0,0,1,0,1,0,1,0,1,Z]]; B[46, L[0,0,0,0,0,1,0,1,0,1,1,0,Z]]; B[47, L[0,0,0,0,0,1,0,1,0,1,1,1,Z]]; B[48, L[0,0,0,0,0,1,1,0,0,1,0,0,Z]]; B[49, L[0,0,0,0,0,1,1,0,0,1,0,1,Z]]; B[50, L[0,0,0,0,0,1,0,1,0,0,1,0,Z]]; B[51, L[0,0,0,0,0,1,0,1,0,0,1,1,Z]]; B[52, L[0,0,0,0,0,0,1,0,0,1,0,0,Z]]; B[53, L[0,0,0,0,0,0,1,1,0,1,1,1,Z]]; B[54, L[0,0,0,0,0,0,1,1,1,0,0,0,Z]]; B[55, L[0,0,0,0,0,0,1,0,0,1,1,1,Z]]; B[56, L[0,0,0,0,0,0,1,0,1,0,0,0,Z]]; B[57, L[0,0,0,0,0,1,0,1,1,0,0,0,Z]]; B[58, L[0,0,0,0,0,1,0,1,1,0,0,1,Z]]; B[59, L[0,0,0,0,0,0,1,0,1,0,1,1,Z]]; B[60, L[0,0,0,0,0,0,1,0,1,1,0,0,Z]]; B[61, L[0,0,0,0,0,1,0,1,1,0,1,0,Z]]; B[62, L[0,0,0,0,0,1,1,0,0,1,1,0,Z]]; B[63, L[0,0,0,0,0,1,1,0,0,1,1,1,Z]]; }; {MW: PROC [length: INT, bitstring: Bitstring] ~ { T[hwhite, bitstring, hwhite, null, length]; T[hhwhite, bitstring, hhwhite, null, length]}; MW[0064, L[1,1,0,1,1,Z]]; MW[0128, L[1,0,0,1,0,Z]]; MW[0192, L[0,1,0,1,1,1,Z]]; MW[0256, L[0,1,1,0,1,1,1,Z]]; MW[0320, L[0,0,1,1,0,1,1,0,Z]]; MW[0384, L[0,0,1,1,0,1,1,1,Z]]; MW[0448, L[0,1,1,0,0,1,0,0,Z]]; MW[0512, L[0,1,1,0,0,1,0,1,Z]]; MW[0576, L[0,1,1,0,1,0,0,0,Z]]; MW[0640, L[0,1,1,0,0,1,1,1,Z]]; MW[0704, L[0,1,1,0,0,1,1,0,0,Z]]; MW[0768, L[0,1,1,0,0,1,1,0,1,Z]]; MW[0832, L[0,1,1,0,1,0,0,1,0,Z]]; MW[0896, L[0,1,1,0,1,0,0,1,1,Z]]; MW[0960, L[0,1,1,0,1,0,1,0,0,Z]]; MW[1024, L[0,1,1,0,1,0,1,0,1,Z]]; MW[1088, L[0,1,1,0,1,0,1,1,0,Z]]; MW[1152, L[0,1,1,0,1,0,1,1,1,Z]]; MW[1216, L[0,1,1,0,1,1,0,0,0,Z]]; MW[1280, L[0,1,1,0,1,1,0,0,1,Z]]; MW[1344, L[0,1,1,0,1,1,0,1,0,Z]]; MW[1408, L[0,1,1,0,1,1,0,1,1,Z]]; MW[1472, L[0,1,0,0,1,1,0,0,0,Z]]; MW[1536, L[0,1,0,0,1,1,0,0,1,Z]]; MW[1600, L[0,1,0,0,1,1,0,1,0,Z]]; MW[1664, L[0,1,1,0,0,0,Z]]; MW[1728, L[0,1,0,0,1,1,0,1,1,Z]]; }; {MB: PROC [length: INT, bitstring: Bitstring] ~ { T[hblack, bitstring, hblack, null, length]; T[hhblack, bitstring, hhblack, null, length]}; MB[0064, L[0,0,0,0,0,0,1,1,1,1,Z]]; MB[0128, L[0,0,0,0,1,1,0,0,1,0,0,0,Z]]; MB[0192, L[0,0,0,0,1,1,0,0,1,0,0,1,Z]]; MB[0256, L[0,0,0,0,0,1,0,1,1,0,1,1,Z]]; MB[0320, L[0,0,0,0,0,0,1,1,0,0,1,1,Z]]; MB[0384, L[0,0,0,0,0,0,1,1,0,1,0,0,Z]]; MB[0448, L[0,0,0,0,0,0,1,1,0,1,0,1,Z]]; MB[0512, L[0,0,0,0,0,0,1,1,0,1,1,0,0,Z]]; MB[0576, L[0,0,0,0,0,0,1,1,0,1,1,0,1,Z]]; MB[0640, L[0,0,0,0,0,0,1,0,0,1,0,1,0,Z]]; MB[0704, L[0,0,0,0,0,0,1,0,0,1,0,1,1,Z]]; MB[0768, L[0,0,0,0,0,0,1,0,0,1,1,0,0,Z]]; MB[0832, L[0,0,0,0,0,0,1,0,0,1,1,0,1,Z]]; MB[0896, L[0,0,0,0,0,0,1,1,1,0,0,1,0,Z]]; MB[0960, L[0,0,0,0,0,0,1,1,1,0,0,1,1,Z]]; MB[1024, L[0,0,0,0,0,0,1,1,1,0,1,0,0,Z]]; MB[1088, L[0,0,0,0,0,0,1,1,1,0,1,0,1,Z]]; MB[1152, L[0,0,0,0,0,0,1,1,1,0,1,1,0,Z]]; MB[1216, L[0,0,0,0,0,0,1,1,1,0,1,1,1,Z]]; MB[1280, L[0,0,0,0,0,0,1,0,1,0,0,1,0,Z]]; MB[1344, L[0,0,0,0,0,0,1,0,1,0,0,1,1,Z]]; MB[1408, L[0,0,0,0,0,0,1,0,1,0,1,0,0,Z]]; MB[1472, L[0,0,0,0,0,0,1,0,1,0,1,0,1,Z]]; MB[1536, L[0,0,0,0,0,0,1,0,1,1,0,1,0,Z]]; MB[1600, L[0,0,0,0,0,0,1,0,1,1,0,1,1,Z]]; MB[1664, L[0,0,0,0,0,0,1,1,0,0,1,0,0,Z]]; MB[1728, L[0,0,0,0,0,0,1,1,0,0,1,0,1,Z]]; }; {M: PROC [length: INT, bitstring: Bitstring] ~ { T[hwhite, bitstring, hwhite, null, length]; T[hhwhite, bitstring, hhwhite, null, length]; T[hblack, bitstring, hblack, null, length]; T[hhblack, bitstring, hhblack, null, length]}; M[1792, L[0,0,0,0,0,0,0,1,0,0,0,Z]]; M[1856, L[0,0,0,0,0,0,0,1,1,0,0,Z]]; M[1920, L[0,0,0,0,0,0,0,1,1,0,1,Z]]; M[1984, L[0,0,0,0,0,0,0,1,0,0,1,0,Z]]; M[2048, L[0,0,0,0,0,0,0,1,0,0,1,1,Z]]; M[2112, L[0,0,0,0,0,0,0,1,0,1,0,0,Z]]; M[2176, L[0,0,0,0,0,0,0,1,0,1,0,1,Z]]; M[2240, L[0,0,0,0,0,0,0,1,0,1,1,0,Z]]; M[2304, L[0,0,0,0,0,0,0,1,0,1,1,1,Z]]; M[2368, L[0,0,0,0,0,0,0,1,1,1,0,0,Z]]; M[2432, L[0,0,0,0,0,0,0,1,1,1,0,1,Z]]; M[2496, L[0,0,0,0,0,0,0,1,1,1,1,0,Z]]; M[2560, L[0,0,0,0,0,0,0,1,1,1,1,1,Z]]; }; {U: PROC [length: INT, bitstring: Bitstring] ~ { T[unc, bitstring, unc, one, length]}; U[1, L[1,Z]]; U[2, L[0,1,Z]]; U[3, L[0,0,1,Z]]; U[4, L[0,0,0,1,Z]]; U[5, L[0,0,0,0,1,Z]]; T[unc, L[0,0,0,0,0,1,Z], unc, zeros, 5]; }; FOR length: [0..4] IN [0..4] DO -- Patterns like 060n1T b: Bitstring ฌ ALL[0]; b[length+6] ฌ 1; b[length+7] ฌ 0; b[length+8] ฌ Z; T[unc, b, white, zeros, length]; b[length+7] ฌ 1; T[unc, b, black, zeros, length]; ENDLOOP; { T[uncb1, L[Z], unc, one, 1]; T[uncb2, L[Z], unc, one, 2]; T[uncb3, L[Z], unc, one, 3]; T[uncb4, L[Z], unc, one, 4]; T[uncb5, L[Z], unc, one, 5]; T[uncw1, L[Z], unc, zeros, 1]; T[uncw2, L[Z], unc, zeros, 2]; T[uncw3, L[Z], unc, zeros, 3]; T[uncw4, L[Z], unc, zeros, 4]; T[uncw5, L[Z], unc, zeros, 5]; }; }; END. ˆ PixelArrayCCITTG4Impl.mesa Copyright ำ 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Michael Plass, November 9, 1992 2:07 pm PST Russ Atkinson (RRA) May 31, 1993 1:16 pm PDT Only fetch if we have less than this amount, so the resulting count will fit in a BitCount variable. Hackery Equivalent to MAX[x, 0] PixelArrayCCITTG4Private support NOTE: this entry is NOT MONITORED This is a literal run of bits We have a stored transition array, so use it Need to make this pixel array into an immutable form It is best to turn this line into a literal We can save away the transitions simply by copying them over General support PixelArray support This is the fastest case; we can move the bits directly into the destination buffer without having to go through an intermediate scan-line buffer. Explicit bounds check, so we can be compiled with bounds checks turned off and still be trustworthy. This is a bit special This is a literal run of bits We have a stored transition array, so use it To copy the pixel array we first make the data pure, then we can set the immutable bit Basic Decompression Start out with a smallish buffer; expand to maximum possible size (based on scanLength) if this is exceeded. Take care of the trailing bits Load w with the initial bits Take care of the trailing bits Called on end-of-stream, which should never happen with valid data. goodBitsIn: REF ARRAY [0..32] OF INT ฌ NEW[ARRAY [0..32] OF INT]; -- Stat goodBitsOut: REF ARRAY [0..32] OF INT ฌ NEW[ARRAY [0..32] OF INT]; -- Stat NOTE: Reset must be called before the first call to Advance This is an indication that we have fetched off the end of the world Refresh everything that might have changed Special cases for uncompressed and eoi eoi, test for end-of-line vs. end-of-data For G3 data with K > 0 there is an extra bit 0 => 2-D mode 1 => 1-D mode 2 EOL => EODF; for G3, eat 4 more EOL+b codes We got an end-of-line code here, so exit if we are not at the start of a line (since we can see EOL codes at the start). uncompressed, defaults already set uncompressed, defaults already set Refresh everything that might have changed In this case the uncompressed data spans the scan line boundary; the original draft CCITT standard was ambiguous about whether this was legal, so the RES standard specified it as illegal. However, the final CCITT standard says it's OK, so we should handle it despite what the RES standard says. Continue uncompressed data to next scan line. When examining x, the value of the current 13 leading bits, if the leading 4 bits are zeros (=> x >= 512) then we use the index directly into the "long" table. Otherwise we divide by 2**4 (= 16), add the mod, and index the short table. Less than this length is a terminal node Greater than or equal to this length is a makeup code Scan 0 Scan +/- 1 Horizontal, 001 Pass, 0001 Scan +/- 2 Scan +/- 3 Other non-simple cases Returns the next n bytes from the stream, LEFT-justified in the word Note: "reversed" means reversed from normal PC world order. Adobe behavior is reverseBits = true! firstBitLowOrder means that the first bit is the low-order bit in the byte. Assert: data.useFastScan AND j # scanLength Fast Case, can pull the bits quickly without lots of checking Check for a non-run Assert: data.useFastScan AND j # scanLength Fast Case, can pull the bits quickly without lots of checking This is a very common case, so we code it carefully. There is a specialized version of Scan at the front which takes advantage of some predicates (like j < scanLength). IF color = (i MOD 2) THEN i ฌ i + 1; A specialized version of Scan that goes forward 2 transitions is here. We do a Fill but leave the assumed color the same. IF color = (i MOD 2) THEN i ฌ i + 1; Table Building Call with data~dummy. Builds trees the first time they are needed. This builds trees with a fanout of two, i.e., all TreeNodes have bitCount=1, and then Optimizes them. Call with data~dummy. For experimenting with differently optimized tables. Vertical mode codes White run terminating codes Black run terminating codes White makeup codes Black makeup codes Common makeup codes These states are used to pick up when uncompressed data spans a scanline boundary. สEF•NewlineDelimiter –(cedarcode) style™code™Kšœ ฯeœ=™HK™+K™,K™šฯk œOžœZžœ˜ทK˜——šฯnœžœžœžœ ˜:Kšžœ=žœ˜]Kšžœ>˜EKšœžœžœ˜&K˜šœžœžœ.˜MK˜—Kšœžœžœžœ˜šœ žœžœžœ˜K™d—Kšœ žœ ˜Kšœ žœžœžœ˜,Kšœžœžœžœžœžœžœžœžœžœ˜AKšœ žœžœžœžœžœžœžœžœžœ˜CKšœ žœžœžœ˜,Kšžœžœžœ˜K˜Kšœ žœžœ˜Kšœ žœžœ˜Kšœ žœžœ˜K˜Kšœžœžœ˜Kšœžœžœ˜Kšœžœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜K˜Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜K˜Kšœ žœ˜K˜š œ žœžœžœžœ˜3K˜—Kšœžœ ฯc9˜U—head™š Ÿœžœžœžœžœžœ˜4K™Kšžœžœžœžœžœ ž œžœžœžœ˜fK˜K˜—šŸœžœžœ žœ˜?Kšžœžœžœ˜K˜K˜—š Ÿ œžœ žœžœžœžœ˜HKšžœ*žœžœ˜KK˜K˜—šŸ œžœžœžœžœžœžœžœ˜mKšžœžœžœ˜JK˜K˜—šŸ œžœžœžœžœžœžœ˜cKšœžœžœ˜EK˜K˜——™ šŸ œžœžœžœžœžœžœžœ žœ˜^Kšœ žœ˜K˜K˜Kšœ ˜)K˜#Kšžœ˜K˜K˜—šŸœžœžœžœžœ žœžœžœ˜[K™!J˜;šžœžœžœ˜K˜#šžœ ž˜šžœ˜Kšžœžœ žœ˜(K˜Kšœžœ˜K˜—šžœ˜Kšžœžœžœžœ ˜:Kšžœ žœžœžœ˜=K˜——šžœžœžœ˜"Kšœ žœ˜"K˜Kšœ žœžœ˜#K˜(Kšœ žœ ˜šžœžœž˜šžœžœž˜-šœ žœ˜ K™šžœ˜ šž˜Kšœ8žœS˜“—šž˜Kšœ@žœ+˜s——Kšžœžœ ˜K˜—šœžœ7˜AK™,—Kšžœžœ˜——K˜gKšžœžœ ˜Kšžœ$žœ˜.K˜—K˜—K˜K˜—š Ÿœžœžœžœžœžœ˜6Kšœžœ˜K˜K˜—š Ÿœžœžœžœžœžœ˜9šžœ˜Kšžœ"žœ˜/Kšžœžœ˜K˜—K˜K˜K˜—šŸ œžœ˜#K˜#šžœ žœžœ˜K™4Kšœžœ˜Kšœžœ!˜3Kšœ žœ˜Kš œžœžœžœžœžœžœ ˜;Kšœžœ˜K˜"šžœ žœžœž˜&KšžœC˜E—š žœžœžœ žœžœ ž˜,Kšœžœžœ˜Kšœžœ˜šžœ žœžœž˜&Kšžœ;˜=—Kšžœžœžœžœ ˜:Kšžœ žœžœžœ˜=Kšžœ žœžœ˜Kšžœžœžœžœ˜.K˜$šžœžœ ˜'šžœ˜K™+Kšœžœ˜/šžœ žœžœž˜&Kšžœ@˜B—Kšœžœ,˜RK˜—šžœ˜K™˜@—Kš œžœžœ(žœžœ˜˜K˜K˜ K˜——Kšžœ žœžœ˜šžœžœ˜Kš œžœžœžœžœžœžœ˜@Kšœžœ˜+šžœ ž˜Kš œžœžœžœžœ˜…—K˜K˜K˜—K˜K˜ Kšžœ˜—šžœ žœžœž˜&KšžœC˜E—K˜K˜Kšœ žœ˜K˜—K˜——™šŸœžœžœžœ˜LKšœžœ˜Kšœ žœ˜#Kš žœ žœžœžœžœžœ˜,Kšœ žœ˜Kšœ˜K˜&šžœ˜ K˜Kš žœ;žœ)žœ%žœžœ˜ฌKšœ˜—K˜K˜—šŸœžœžœžœ˜6šžœžœž˜šœ˜Kšœ ˜ šžœžœžœ˜Kšœ4˜4šžœžœ˜Kšžœžœžœ˜Kšœ žœžœ ˜8Kšœ žœžœ˜˜@Kšžœ=˜?K˜—Kšžœ|˜~K˜—K˜Kšœ˜Kšžœ žœžœ˜K˜&K˜K˜ šžœžœžœžœ˜7K™Cšžœ žœ žœž˜ Kšžœ˜—Kšœ žœ˜Kšžœ˜K˜—K˜šžœžœž˜Kšœž œ˜-Kšœžœžœ˜"šžœ˜ šžœžœž˜K˜BK˜BKšžœžœžœ ˜—K™*K˜'K˜K˜K˜K˜Kšžœ˜K˜——K˜šž˜šžœž˜Kš žœžœžœžœžœ˜)—šžœ žœž˜šœ˜Kšœฯt ˜#K˜Kšžœ žœ˜/K˜Kšœ˜K˜)šžœ žœ žœžœ˜"Kšžœ˜Kšœ&žœ˜,K˜—K˜K˜Kšœ˜—šœ˜K˜Kšžœ žœ˜/šžœ žœ˜Kšœžœžœ ˜šžœžœžœ˜Kšžœ˜K˜Kšžœ.˜0K˜Kšžœ+˜-K˜—K˜—šžœ ž˜Kšœžœ˜ ˜ K™&K˜ šžœžœž˜˜K™)šŸœžœžœ˜šžœž˜K˜ Kšœžœ˜šžœ˜ ™,K™ K™ —K˜ Kšœžœ ˜K˜ K˜——K˜—K˜ K˜ šžœ žœ˜Kšœžœžœ ˜šžœžœžœ˜Kšžœ˜šžœ ž˜Kšžœ žœžœžœ ˜:—Kšžœ˜K˜—K˜—K˜ Kšžœžœ žœ*˜Fšžœž œžœ˜1K™-Kš œžœžœ žœžœ˜/šž˜K˜ K˜ K˜Kšžœ žœžœ˜K˜ šžœž œžœ˜1K˜"Kšžœ˜K˜—Kšžœ˜—šžœ žœ žœž˜ Kšžœ˜—Kšœ žœ˜Kšžœ˜K˜—K™xK˜šžœžœž˜Kšœ žœ˜K˜BK˜BKšžœžœžœ ˜—Kšžœžœ ˜K˜—šžœžœ˜(Kš "™"K˜ K˜ K˜—šœžœ˜$Kš "™"K˜ K˜ K˜—Kšžœ)žœ˜7—Kšžœžœ ˜K˜—šœ ˜ K˜(K˜K˜—˜ Kšœžœ˜!Kšœžœ˜'šžœ žœ˜Kšœ"˜"Kšœ ˜ K˜—K˜š žœžœžœžœžœ˜DK˜2K™*Kšžœžœ ˜K˜—K˜K˜—šœ ˜ Kšœžœ˜!K˜'K˜%K˜Kšœ˜—šœ˜šžœ˜šžœ˜J™งKšœ žœ˜%K˜Jšœžœžœ˜6Kšžœ˜K˜—šžœ˜K˜K˜Kšœ˜——K˜Kšœ˜—šœ ˜ šžœ˜šžœ˜J™-Kšœ žœ˜%K˜Jšœžœžœ˜6Kšžœ˜K˜—šžœ˜K˜Kšœ˜——K˜Kšœ˜—Kšžœ˜—K˜šžœžœ˜K˜šžœž˜K˜K˜Kšžœ˜—K˜—Kšžœžœ ˜šž˜˜ K˜—˜ K˜'K˜K˜K˜K˜K˜K˜K˜——K˜—Kšžœ)žœ˜7—Kšžœ˜—K˜K˜Kšœ"˜"Kšœžœ˜˜Kšœžœ˜$šžœž˜%K˜.—K˜0K˜2K˜K˜—šžœ žœ žœžœ˜"KšžœA˜Cšžœžœžœž˜+Kšžœ4˜6Kšžœ˜—Kšžœ˜K˜—K˜1K˜,Kšœ˜K˜—Kšœ žœ˜%š œžœžœžœ žœ ˜7Kšœ žœ˜'K˜—š œ žœžœž œžœ˜.K˜K˜ K˜—Kšœ žœ ˜šœžœ˜)Kšœžœ˜šœžœ˜K™์——Kšœ žœ#˜3Kšœ žœ˜$šœžœ˜K™(K™5K˜—šŸ œžœžœžœ ˜)Kšœ žœ˜Kšœžœ!˜3Kšœžœžœ žœ ˜;˜"Kšœžœ˜šžœž˜K˜K˜(Kšžœžœ˜—˜K˜0K˜+K˜$Kšœžœ ž œ!˜˜@K˜-Kšžœ˜K˜—Kšœ žœ ˜3Kšœž œ˜2Kšœ˜—šŸœžœžœ˜Kšœžœžœ˜Kšœžœ˜!šžœ"žœžœ˜?K™=Kšœžœžœžœ˜=šž˜Kšœ žœ˜,Kšœž œ žœ˜VK˜Kšžœžœžœžœ˜AKšžœ˜—K˜—K˜3K˜Kšžœ ˜Kšœ˜—šŸœžœžœ˜Kšœžœ˜Kšœžœ*˜>Kšœžœ˜$šžœ žœžœžœ˜)šžœž˜#K˜.—šžœžœžœžœ˜+KšžœF˜HKšžœ(˜*Kšžœ˜K˜—K˜(K˜K˜—K˜Kšœ˜—šžœžœžœ˜Kšžœ+˜-K˜—šžœž˜Kšžœžœ ˜+šžœž œžœžœ˜4K™—K˜šž˜Kšœžœ ž œ˜8Kšžœžœ#˜;˜K˜'Kšœžœ ˜K˜Kšžœžœžœ˜K˜ K˜ Kšžœžœžœ˜K˜—Kšžœžœ ˜+Kšžœ˜—šžœžœ˜K˜$K˜Kšœ˜—šžœžœžœ˜Kšžœ<˜>Kšžœ(˜*Kšžœ˜K˜—Kšœ ˜K˜Kšžœ˜—šžœžœ˜K˜$K˜Kšœ˜—Kšœžœ˜ šžœžœžœ˜Kšžœ;˜=K˜-Kšžœ˜K˜—K˜K˜K˜Kšžœ˜ K˜K˜—šŸœžœžœ žœžœžœžœ˜fKšœžœ™+Kšœžœ˜ Kšœžœ˜"K˜!Kšœ žœžœžœ˜9šŸœžœžœ˜šžœžœžœžœ˜+Kšžœ>˜@K˜-Kšžœ˜K˜—Kšœ žœ ˜3Kšœž œ˜2Kšœ˜—šŸœžœžœ˜Kšœžœžœ˜Kšœžœ˜!šžœ"žœžœ˜?K™=Kšœžœžœžœ˜=šž˜Kšœ žœ˜,Kšœž œ žœ˜VK˜Kš žœžœžœžœžœžœ˜PKšžœ˜—K˜—K˜3K˜Kšžœ ˜Kšœ˜—šŸœžœžœ˜Kšœžœ˜Kšœžœ*˜>Kšœžœ˜$šžœ žœžœžœ˜)šžœž˜#K˜.—šžœžœžœžœ˜+KšžœF˜HKšžœ(˜*Kšžœ˜K˜—K˜(K˜K˜—K˜Kšœ˜—Kšžœžœ'˜=šžœžœžœž˜)Kšžœ;˜=—šžœž˜Kšžœžœ#˜9Kšžœžœ ˜+˜Kšœžœ ž œ1˜aK˜"šžœž˜˜ K™ฉKšœžœ.˜6Kšžœžœ žœ˜8šœžœ˜Kšžœ žœžœ ™$—Kšžœ#žœ žœ˜>K˜Kšœžœžœ žœ ˜6Kšžœžœžœžœ˜Kšžœžœ#˜9K˜K˜ Kšœ ˜K˜K˜—˜ Kšžœžœ#˜9K˜ Kšœ  ˜(šžœž˜K˜šž˜Kšžœžœ ˜+˜Kšœžœ ž œ˜8Kšžœžœ#˜;˜K˜'Kšœžœ ˜K˜Kšžœžœžœžœ˜"K˜ K˜ Kšžœžœžœ˜K˜—K˜—Kšžœ˜—šžœžœ˜K˜$K˜Kšœ˜—Kšœ ˜K˜Kšžœ˜—K˜—˜ K™zKšœžœ.˜6Kšžœžœ žœ˜8šœžœ˜Kšžœ žœžœ ™$—Kšžœ#žœ žœ˜>K˜ Kšœžœžœ žœ ˜6K˜Kšžœžœ!˜7K˜ Kšœ  ˜Kšœ ˜K˜—Kšžœžœ˜—šž˜Kšœ.žœ˜4Kšœ.žœ˜4—K˜—Kšžœ˜—šžœžœ˜K˜$K˜Kšœ˜—Kšœžœ˜ šžœžœžœžœ˜+Kšžœ:˜˜@—šžœ>žœ˜FKšžœ<˜>Kšžœ8˜:Kšžœ8˜:Kšžœ>˜@šžœž˜ K˜;—K˜—šžœžœ˜KšžœB˜DKšžœ>˜@Kšžœ>˜@Kšžœ<˜>Kšžœ>˜@šžœž˜ K˜S—K˜—Kšžœ˜ šžœ žœž˜K˜šžœžœžœ˜Kšžœ˜K˜Kšžœ˜K˜Kšžœ˜K˜—Kšžœ˜—Kšžœ˜K˜—Kšœ˜K˜—šŸ œžœžœžœžœžœžœ ˜IKšœC™CKšžœžœžœ˜7Kšžœ ˜Kšœ˜K˜—š Ÿ œžœžœžœžœžœ ˜6K™eKš œžœžœžœžœžœžœ˜:šŸœ˜"Kšœžœ˜%šžœ ˜ šžœ˜Kšœ žœ0˜@K˜—šžœ˜Kšœžœ ˜!šžœžœžœ ž˜Kšœžœ ˜&šžœžœž˜Kšœ&˜&—Kšœžœ˜Kšžœ˜—Kšœ7žœ1˜kKšœ˜——K˜—šžœ žœž˜Kšœ˜Kšžœ˜—Kšœ˜šžœ žœž˜K˜"Kšžœ˜—Kšžœ˜Kšœ˜K˜—šŸœžœžœžœžœ žœžœžœ˜Hšžœžœžœ˜šžœžœžœž˜/Kš žœ žœžœ žœžœ˜;Kšžœ˜—Kšžœžœžœ˜Kšœ˜—Kšœ˜—K˜š Ÿœžœžœžœžœ˜(šžœžœžœ˜Kšžœ˜Kšžœžœžœžœ˜/Kšœ˜—Kšœ˜K˜—šŸ œžœžœžœ˜3šžœžœž˜Kšžœ žœžœdžœ˜”—Kšœ˜K˜—šŸœžœžœžœ˜0šžœžœžœ˜Kšžœ žœžœคžœ˜ำKšœ˜—Kšœ˜K˜—š Ÿœžœžœžœžœ žœ˜FKš žœžœžœžœžœ˜5šžœžœž˜˜Kšœžœ˜ Kšœžœ ˜K˜Kšžœžœžœ,˜EK˜Kšžœ8˜:šžœ ž˜Kšœžœžœ˜K˜Kšœžœ˜ K˜Kšžœ˜K˜šžœ žœž˜(K˜K˜Kšžœ˜—šžœžœ˜Kšžœ˜K˜K˜—Kšžœ˜šžœ ž˜Kšžœžœ˜šžœ˜KšžœF˜HK˜'K˜——Kšžœ˜K˜ Kšžœ˜—Kšžœ˜K˜—šœ˜Kšžœžœžœ,˜EK˜Kšžœ˜K˜Kšžœ+˜-K˜Kšžœ˜Kšœ˜—Kšžœžœ˜—Kšœ˜—K˜KšŸœžœžœ -˜Aš Ÿ œžœžœžœžœ˜:Kšžœžœžœžœ˜Kšžœ žœžœ˜šžœžœž˜˜Kšœžœ˜šžœžœžœž˜Kšœ˜K˜šžœ žœž˜K˜*—Kšžœ˜—Kšžœ˜K˜—šœ˜Jšžœžœžœ˜$Kšžœ˜ K˜—Kšžœžœ˜—Kšœ˜K˜—š Ÿ œžœžœ žœ žœžœ˜Yšžœ žœ9žœ˜Pšžœžœž˜˜Kšžœžœžœ˜šžœžœžœž˜Kšœ˜K˜Kšžœ žœžœ1˜DKšžœ˜—K˜—šžœ˜ Kšœžœ˜Kšœ7˜7šžœžœžœž˜Kšœ˜Kšžœ˜—K˜——Kšœ˜—Kšœ˜—K˜š Ÿœžœžœžœžœžœ˜JK™K˜K˜Kšœ žœ˜Kšœ˜K˜—š Ÿ œžœžœžœžœ˜0K™4šžœžœ ˜Kšžœžœ˜*Kšžœžœ˜—Kšœ˜K˜—šŸ œžœžœ ˜2šžœžœž˜˜Kšœ žœ˜˜Kšžœ žœžœ˜šž˜Kšœ žœ˜Kšœžœ  +˜QKšžœžœžœžœ˜HKšžœ˜—Kšžœ ˜K˜—šžœ˜Kšžœžœ˜šžœ˜K˜&KšŸœžœžœ(˜;Kšœ'˜'Kšžœ˜ Kšœ˜——K˜—Kšžœžœ˜—Kšœ˜K˜—šŸœžœŸœ˜<šœŸœžœ žœ˜0Kšœ)˜)Kšœ*˜*K™Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—Kšœ&˜&Kšœ&˜&šžœ žœž˜!Kšœ˜K˜&Kšžœ˜—šœŸœžœ žœ˜0Kšœ,˜,Kšœ,˜,K™Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—šœŸœžœ žœ˜0Kšœ+˜+Kšœ-˜-K™Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ"˜"Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ$˜$K˜—šœžœžœ žœ˜1Kšœ+˜+Kšœ.˜.K™Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜!Kšžœ˜Kšžœ˜!K˜—šœžœžœ žœ˜1Kšœ+˜+Kšœ.˜.K™Kšžœ!˜#Kšžœ%˜'Kšžœ%˜'Kšžœ%˜'Kšžœ%˜'Kšžœ%˜'Kšžœ%˜'Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)Kšžœ'˜)K˜—šœŸœžœ žœ˜0Kšœ+˜+Kšœ-˜-Kšœ+˜+Kšœ.˜.K™Kšœ$˜$Kšœ$˜$Kšœ$˜$Kšœ&˜&Kšœ&˜&Kšœ&˜&Kšœ&˜&Kšœ&˜&Kšœ&˜&Kšœ&˜&Kšœ&˜&Kšœ&˜&Kšœ&˜&K˜—šœŸœžœ žœ˜0Kšœ%˜%Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ(˜(K˜—š žœžœžœ ะcu ข ˜7Kšœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšžœ˜—˜K™RK˜K˜K˜K˜K˜K˜K˜K˜K˜K˜Kšœ˜—K˜K˜K˜——Kšžœ˜J˜J˜—…—ฮ #ฺ