/*--- formatted by Jindent 2.1, (www.c-lab.de/~jindent) ---*/ /** * *************************************************************** * The LEAP libraries, when combined with certain JADE platform components, * provide a run-time environment for enabling FIPA agents to execute on * lightweight devices running Java. LEAP and JADE teams have jointly * designed the API for ease of integration and hence to take advantage * of these dual developments and extensions so that users only see * one development platform and a * single homogeneous set of APIs. Enabling deployment to a wide range of * devices whilst still having access to the full development * environment and functionalities that JADE provides. * Copyright (C) 2001 Telecom Italia LAB S.p.A. * Copyright (C) 2001 Broadcom Eireann Research. * Copyright (C) 2001 Siemens AG. * * GNU Lesser General Public License * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * ************************************************************** */ package jade.imtp.leap.JICP; import java.io.ByteArrayOutputStream; /** * Class declaration * @author Dmitri Toropov - Siemens AG */ class JICPCompressor2 { /** * check if the symbol is separator * * @param sym - byte to check * @return true if sym is separator, false otherwise * */ public static boolean is_separator(byte sym) { return (sym <= 32) || (sym == '(') || (sym == ')') || (sym == '@') || (sym == ':') || (sym == '/') || (sym == '!'); } /** * operation +1 by modulo 253 */ private static int next(int val) { return (val==252)?(0):(val+1); } /** * subtraction by modulo 253 */ private static int back(int val, int num) { return (num>val)?(253+val-num):(val-num); } /** * sum by modulo 253 */ private static int sum(int val, int num) { return (num + val >= 253)?(val + num - 253):(val + num); } /** * normal mimimum function */ private static int min(int a, int b) { return (a > b)?(b):(a); } /** * Compress the byte array * * @param data the data to compress * @return compressed data * */ public static byte[] compress(byte[] data) { if (data == null) return null; int dataSize=data.length; byte[] result=null; try { int[] words = new int[min(dataSize+1,253)]; //words are interleaved with separators //minimal lenth of each word or separator is a 1 symbol //this way maximal number of words is lenghth/2 //(+ may be 1 if the lenght is odd) ByteArrayOutputStream stream = new ByteArrayOutputStream(); stream.write(dataSize/256); //first 2 bytes is the array length stream.write(dataSize%256); int numWords=0; int pos=0; boolean inWord=false; boolean dataEnded=false; while((pos < dataSize)&&(numWords < 126)) { if(is_separator(data[pos]) || !inWord) { inWord=!is_separator(data[pos]); words[numWords]=pos; numWords++; } pos++; } if (numWords < 126) //pos==dataSize { dataEnded = true; words[numWords]=pos; } int countWords=0; int charCounter=0; boolean startFlag = true; for(int i=0; i!=numWords; i=next(i)) //looking through the words; the first word is for sure not compressed { if (!dataEnded) { while((pos < dataSize)&&(!(is_separator(data[pos]) || !inWord))) pos++; if ((pos < dataSize)&&(is_separator(data[pos]) || !inWord)) { inWord = !is_separator(data[pos]); words[numWords]=pos; numWords = next(numWords); pos++; } else //pos == dataSize { words[numWords]=pos; dataEnded = true; } } int j; for(j=(startFlag && (i<126))?(0):(back(i,126)); j!=i; j=next(j)) //trying to find the occurance of the current word; the history lenght is 126 words { countWords=charCounter=0; while( (words[i]+charCounter < dataSize - 1) && //if the position with which we are comparing //is not yet achieved the end of the array (words[j]+charCounter < words[i]) && //and the search position not yet achieved //the current position (data[words[i]+charCounter]==data[words[j]+charCounter])) //and the characters are the same { charCounter++; if( (sum(j,countWords+1) != i) && (words[j]+charCounter >= words[sum(j,countWords+1)]) && (sum(i,countWords+1) != numWords) && (words[i]+charCounter >= words[sum(i,countWords+1)]) ) countWords++; //if we achieved the next word boundary //'+1' means that we count the word only when we //have aready check all of its symbols //(each space is one symbol word) } if(countWords > 0) //the correspondance was found { if((countWords == 1)&&(words[next(i)]-words[i]<=2)) { int k; for(k=0; k< words[next(i)]-words[i]; k++) { if(data[words[i]+k]>=0) stream.write(data[words[i]+k]); else { stream.write(-127); stream.write(data[words[i]+k]); } } } else { stream.write(-back(i,j)); //offset (backward) of the position where to find this word stream.write(-countWords); //if we have more then 1 word - write the number i=sum(i,countWords-1); } break; //exit the internal for() } } if (countWords == 0) { for(j=0; j< words[next(i)]-words[i]; j++) { if(data[words[i]+j]>=0) stream.write(data[words[i]+j]); else { stream.write(-127); stream.write(data[words[i]+j]); } } } if(i==252) startFlag=false; } result = stream.toByteArray(); /************************** System.out.print("Uncompressed: "); System.out.print(dataSize); System.out.print(" Compressed: "); System.out.println(result.length); System.out.flush(); //*************************/ // System.out.println("" + dataSize + "->" + result.length + " = " + (result.length*100)/dataSize+"%"); return result; } catch(Exception e) { System.out.println("Compression exception:"+e.toString()); e.printStackTrace(); } return null; } /** * Decompress the byte array * * @param data the data to compress * @return compressed data * */ public static byte[] decompress(byte[] data) { if (data == null) return null; int dataSize = data.length; int outputSize = ((data[0]>=0)?(data[0]):(256 + data[0]))*256 + ((data[1]>=0)?(data[1]):(256 + data[1])); //System.out.print("Data size "); //System.out.println(outputSize); byte[] output = new byte[outputSize]; //first byte is the array length int[] words = new int[min(outputSize,253)]; //words are interleaved with separators //minimal lenth of each word or separator is a 1 symbol //this way maximal number of words is lenghth/2 //(+ may be 1 if the lenght is odd) int numWords=0; int j=0; int i=2; //data[0] and data[1] are not a compressed data but a size try { i=2; while(i < dataSize) { if( (data[i] < 0) && (data[i] > -127) ) { int wordsCount = (((i+1 < dataSize)&&(data[i+1] < 0)&&(data[i+1] > -127))?(-data[i+1]):1); int symCount = words[sum(back(numWords,(-data[i])), wordsCount)] - words[back(numWords,(-data[i]))]; int k; for(k=0; k < symCount; k++) { output[j+k] = output[words[back(numWords,(-data[i]))] + k]; } for(k=0; k < wordsCount; k++) words[sum(numWords,k)] = words[sum(back(numWords, (-data[i])), k)] - words[back(numWords, (-data[i]))]+ j; j+=symCount; numWords=sum(numWords,wordsCount); i+=2; } else { if(!is_separator(data[i])) //not a separator { words[numWords]=j; numWords=next(numWords); output[j]=data[i]; i++; j++; } while( (i<dataSize)&&(!is_separator(data[i])) ) //limit ourself to the case where all the symbols have codes < 128 { output[j]=data[i]; i++; j++; } while( (i< dataSize) && (is_separator(data[i])) && ((data[i]>=0)||(data[i] == -127)) ) //copying the separators { if(data[i] == -127) i++; words[numWords]=j; numWords=next(numWords); output[j]=data[i]; i++; j++; } } } return output; } catch(Exception e) { System.out.println("Decompression exception:"+e.toString()); e.printStackTrace(); } return null; } }