package LZW import LinkedList import public BigString import public SeqWorker import ErrorHandling import Encoder import HashMap /** Lempel Ziv Welch Compression */ constant maxDictSize = 5000 constant string DICT_INIT = "_0123456789abcdefghijklmnopqrstuvwxyz-[]" constant string ALLOWED_PLAYER_CHARS = "0aUb1GLwR2kHvP3CQIM4npFs5iSW6tzAr7TNxo8JXVjy9OcdEfBKgqeuYDhmlZ" constant HashMap dictionary = new HashMap() int dictSize = 0 function putDict(string s) dictionary.put(s, dictSize) dictionary.saveString(dictSize, s) dictSize++ function initDict() dictSize = 0 dictionary.flush() for c in DICT_INIT putDict(c) function encodePositions(LinkedList intList, int dictSize, PayloadCallback onFinish) if dictSize > maxDictSize error("dictionary size exceeds max size") if DEBUG_LEVEL == Loglevel.TRACE var st = "" for s in intList st+= s.toString() + "," printLog(Loglevel.TRACE, "encoding positions: " + st) let encoder = new Encoder(ALLOWED_PLAYER_CHARS) // let max = intList.getSize() let itr = intList.staticItr() doSeq() cb -> var continue = true if itr.hasNext() encoder.encode(itr.next(), dictSize) else continue = false encoder.encode(dictSize, maxDictSize) destroy intList encoder.save(new BigString()) pc -> onFinish.customData = pc.customData destroy encoder onFinish.doStep() return continue function decodePositions(BigString input, PayloadCallback onFinish) let encoder = new Encoder(ALLOWED_PLAYER_CHARS) input.debugPrint() encoder.load(input) cb -> if cb.customData == 1 nullTimer() -> Log.debug("file valid2") let dictSize = encoder.decode(maxDictSize) Log.debug("dictSize: " + dictSize.toString()) let positions = new LinkedList() Log.debug("start decoding pos") doSeq() cb1 -> var continue = true if not encoder.bignum.isZero() let dec = encoder.decode(dictSize) positions.addtoStart(dec) else continue = false if DEBUG_LEVEL == Loglevel.TRACE var st = "" for s in positions st+= s.toString() + "," printLog(Loglevel.TRACE,"decoded positions: " + st) onFinish.customData = positions castTo int onFinish.doStep() return continue else error("loaded input is invalid") destroy cb public function compress(BigString data, PayloadCallback onFinish) Log.debug("Compressing:") data.debugPrint() // List let intList = new LinkedList() initDict() int inc = 0 BigSubString A = null BigSubString B = null doSeq() cb -> var continue = true if (inc < data.getLength() - 1) if A != null destroy A A = data.charAt(inc) inc++ if B != null destroy B B = data.charAt(inc) //Z is next character A.concat(B) while true //Loop until the sequence of if not dictionary.has(A.getCombined()) break let sng = A.getSingle() if A != null destroy A A = new BigSubString(sng + B.getSingle()) inc++ if (inc < data.getLength()) if B != null destroy B B = data.charAt(inc) A.concat(B) else break //Write index to output intList.add(dictionary.get(A.getSingle())) putDict(A.getCombined()) // output += (dictionary.indexOf(Z) + " "); else Log.debug("Compressed") continue = false if B != null and A.getSingle().charAt(A.getSingleLength()-1) != B.getSingle() intList.add(dictionary.get(B.getSingle())) encodePositions(intList, dictSize) cb2 -> Log.debug("positions encoded") let encoded = cb2.customData castTo BigString encoded.debugPrint() onFinish.customData = encoded castTo int onFinish.doStep() return continue /** * @return boolean - true if successful, false otherwise. */ public function decompress(BigString input, PayloadCallback onFinish) Log.debug("Start decompress") let output = new BigString() initDict() decodePositions(input) cb1 -> let positions = cb1.customData castTo LinkedList let itr = positions.staticItr() string A = "" string B = "" doSeq() cb2 -> var continue = true if itr.hasNext() let idx = itr.next() A = dictionary.loadString(idx) if (itr.hasNext() and itr.lookahead() < dictSize) B = dictionary.loadString(itr.lookahead()) B = B.charAt(0) //Add first letter of next String else if (not itr.hasNext()) //Reached end of input B = null else //Dictionary does not have next index B = A.charAt(0) //must be first letter of current String if (B != null and B.length() > 0) putDict(A + B) output.addString(A) else continue = false Log.debug("decompressed") output.debugPrint() onFinish.customData = output castTo int onFinish.doStep() return continue