Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/yaftp/utils/PackedDecimal.java


1    /**
2    *
3    * CopyRights Jean-Yves MENGANT 1999,2000,2001,2002
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18   */
19  
20  package com.yaftp.utils ;
21  
22  /**
23  Copyright Jean-Yves MENGANT 1998,1999,2000
24  
25  
26     The class bellow deals with PACKED DECIMAL
27     conversions A portable conversions
28  
29     Only the final PackedDecimal class should be used
30     other class are for internal usage only
31  
32     NumberFormatException may be Thrown by this class on
33     invalid packed decimal format
34  
35    // Construct using an existing byte array(Supose to point on
36    // a valid packed decimal format or to be translated later
37    // with toPackedDecimal method
38    public PackedDecimal( byte Packed_Origin[] ,
39                          int  Offset          ,
40                          int  IntSize          ,
41                          int  DecSize
42                        )
43  
44    // Build a packed decimal from a string number
45    public void toPackedDecimal( String Number )
46  
47    // Translate current Packed into a String representation
48    public String toString()
49  
50    @author Jean-Yves MENGANT
51  
52  */
53  
54  /* Object used for increment / decrement passed to methods  */
55  
56  class Decimal_Increment {
57  
58    private int _Inc ;
59  
60    // Public methods
61    public void SetValue( int Value ) { _Inc = Value ; }
62    public int Increment()
63    {
64      _Inc++         ;
65      return(_Inc-1) ; // Return value before increment
66    }
67  
68    public int Decrement()
69    {
70      _Inc--         ;
71      return(_Inc+1) ; // Return value after increment
72    }
73    public int GetValue() { return _Inc ; }
74  }
75  
76  class DecimalString {
77  
78    private final static byte MAX_DECIMAL_SIZE = 20 ; // Max size of a decimal num
79  
80    private char    _IntPart[]  ;
81    private int     _IntSize    ;
82    private boolean _Negative_Number ;
83    private char    _DecPart[]  ;
84    private int     _DecSize    ;
85  
86    /* Public method on WORK decimal class starts here */
87  
88  
89    public DecimalString( String DecString )
90    throws NumberFormatException
91    {
92    boolean  Decimal_Part = false ;
93    byte     Ii           = 0     ;
94    int      Len          = DecString.length() ;
95    int      Decimal_Pos  = 0     ;
96  
97      _DecPart = new char[MAX_DECIMAL_SIZE] ;
98      _IntPart = new char[MAX_DECIMAL_SIZE] ;
99      _Negative_Number = false ;
100 
101     while ( Ii < Len )
102     {
103     char CurChar = DecString.charAt(Ii) ;
104 
105       switch( CurChar )
106       {
107         case '+' :
108           if ( Ii != 0 )
109             throw new NumberFormatException("Invalid + sign position");
110       break ;
111 
112         case '-' :
113           if ( Ii != 0 )
114             throw new NumberFormatException("Invalid - sign position");
115           else
116             _Negative_Number = true ;
117           break ;
118 
119     case '.' :
120           Decimal_Part = true ;
121           Decimal_Pos  = 0    ;
122           break  ;
123 
124         case '0' :
125         case '1' :
126         case '2' :
127         case '3' :
128         case '4' :
129         case '5' :
130         case '6' :
131         case '7' :
132         case '8' :
133         case '9' :
134           if ( Decimal_Part  )
135           {
136             _DecPart[Decimal_Pos++] = CurChar ;
137             _DecSize++ ;
138           }
139           else
140           {
141             _IntPart[_IntSize] = CurChar ;
142             _IntSize++  ;
143           }
144           break ;
145 
146         default  :
147           throw new NumberFormatException(
148             "PackedDecimal.DecimalString : unexpected character received");
149       }
150       Ii++ ;
151   }
152 
153   }
154 
155   // Accessors
156   public boolean IsNegative()
157   { return _Negative_Number ;  }
158 
159   public int GiveIntSize() { return _IntSize ; }
160 
161   /**
162      Returns Digit corresponding to Pos and decrement Pos
163   */
164   public byte DecDigit( Decimal_Increment Pos )
165   {
166     if ( Pos.GetValue() > _DecSize )
167     {
168       Pos.Decrement() ;
169       return 0 ;
170     }
171     else
172     {
173       Pos.Decrement() ;
174       return BYTEFX.MAKEBYTE (
175                    BYTEFX.LOWNIBBLE( (byte)(_DecPart[Pos.GetValue()]) ),
176                    (byte)(0)
177                             ) ;
178     }
179   }
180 
181   /**
182     @return Digit corresponding to Pos in integer part
183   */
184   public byte IntDigit ( Decimal_Increment Pos )
185   {
186     Pos.Decrement() ;
187     return BYTEFX.MAKEBYTE(
188              BYTEFX.LOWNIBBLE( (byte)(_IntPart[Pos.GetValue()]) ) ,
189              BYTEFX.LOWNIBBLE( (byte)(0) )
190                          ) ;
191   }
192 } ;
193 
194 public class PackedDecimal extends DataStructure {
195 
196   private static final byte DEFAULT_NEGATIVE       =  0x0d ;
197   private static final byte DEFAULT_POSITIVE       =  0x0c ;
198 
199   private static final byte ASCII_HIGH_CHAR_NIBBLE = (byte)(0x30) ;
200   private static final int MAX_DECIMAL_STRING_SIZE = 100 ;
201   private static final byte CBL_SIGN_POS1 = (byte)(0x0A) ;
202   private static final byte CBL_SIGN_POS2 = (byte)(0x0C) ;
203   private static final byte CBL_SIGN_POS3 = (byte)(0x0E) ;
204   private static final byte CBL_SIGN_POS4 = (byte)(0x0F) ;
205                             /* Consider unsigned as positive !!!! */
206 
207   private byte _PackedWk[] ; // Use this as private internal work
208   private int  _IntSize    ; // Total number of non decimal digits
209   private int  _DecSize    ; // total number of decimal digits
210   private int  _Logical_Dest_Size ; // Total logical size
211 
212   // Public access starts here
213 
214   /**
215     giving int Size + dec size returns physical size
216     necessary to store the packed decimal data
217   */
218   public static int getPackedSize( int intSize , int decSize )
219   {
220   int Logical_Dest_Size = intSize + decSize ;
221 
222     if ( Logical_Dest_Size % 2 == 0 )
223       return  ( Logical_Dest_Size / 2 ) + 1 ;
224     else
225       return ( Logical_Dest_Size + 1 ) / 2 ;
226   }
227 
228   /**
229     Construct using an existing byte array(Supose to point on
230     a valid packed decimal format or to be translated later
231     with toPackedDecimal method
232 
233     @param Packed_Origin byte array containing COBOL packed decimal data
234     @param Offset offset of packed decimal data in array
235     @param IntSize non decimal part size
236     @param DecSize decimal part size
237 
238   */
239   public PackedDecimal( byte Packed_Origin[] ,
240                         int  Offset          ,
241                         int  IntSize         ,
242                         int  DecSize
243                       )
244   {
245     super( Packed_Origin , Offset , 0 ) ;
246 
247     _IntSize = IntSize ;
248     _DecSize = DecSize ;
249     _Logical_Dest_Size = IntSize + DecSize ;
250     _Size = getPackedSize( IntSize , DecSize ) ;
251   }
252 
253   /**
254      Build a packed decimal from a string number
255 
256      Convert the in String  +-99999.99 in an packed decimal IBM data
257      Flow -> Each digit is a 0..9 Numerical value last digit is the sign
258      digit : A|C|E|F => + ; B|D => - ; the decimal point is virtual
259      its position is defined in the second byte of dec_len
260 
261      @param Number decimal String representation to be converted
262   */
263   public void toPackedDecimal( String Number )
264   throws NumberFormatException
265   {
266   Decimal_Increment Ii = new Decimal_Increment() ;
267   Decimal_Increment Jj = new Decimal_Increment() ;
268 
269   boolean  Decimal_Part = false ;
270   int      Physical_Dest_Size ;
271   byte     Digit ;
272   int      OutPos ;
273   boolean  High = true ;
274   int      CurIntSize = 0 ;
275 
276   // Build Local Wk Decimal String
277   DecimalString Wk = new DecimalString( Number ) ;
278   _PackedWk        = new byte[_Size] ; // Allocate working
279 
280     OutPos = _Size -1 ;
281 
282     if ( Wk.IsNegative() )
283       _PackedWk[OutPos] = DEFAULT_NEGATIVE ;
284     else
285       _PackedWk[OutPos] = DEFAULT_POSITIVE ;
286 
287     Ii.SetValue(_DecSize)                 ;
288     Jj.SetValue(Wk.GiveIntSize())         ;
289 
290     if ( Ii.GetValue() != 0 )
291       Decimal_Part = true ;
292 
293   while ( ( OutPos != -1 ) &&
294             ( Jj.GetValue() != 0  )
295           )
296     {
297       if ( Decimal_Part )
298      {
299        Digit = Wk.DecDigit(Ii) ;
300 
301        if ( Ii.GetValue() == 0 )
302           Decimal_Part = false ;
303       }
304       else
305         Digit = Wk.IntDigit(Jj) ;
306 
307     if ( High )
308       {
309         _PackedWk[OutPos] =
310              BYTEFX.MAKEBYTE ( BYTEFX.LOWNIBBLE( _PackedWk[OutPos] ) ,
311                                BYTEFX.LOWNIBBLE( Digit )
312                               ) ;
313         OutPos-- ;
314     }
315       else
316         _PackedWk[OutPos] =
317              BYTEFX.MAKEBYTE ( BYTEFX.LOWNIBBLE( Digit )          ,
318                                BYTEFX.LOWNIBBLE( _PackedWk[OutPos] )
319                               ) ;
320 
321       High = !High ; // Switch to Next Digit
322   }
323 
324     // Move Working to super Data Structure
325     System.arraycopy( _PackedWk , 0 , _Struct , _Offset , _Size ) ;
326   }
327 
328 
329   /**
330     Translate current Packed into a String representation
331 
332     @return String representation of packed decimal
333   */
334   public String toString()
335   {
336   int  Ii = 0 ;
337   int  Sign_Location   ;
338   int  Logical_Length  ;
339   int  IOut  = 0 ;    /* position  OutStrDecimal */
340   int  IIn   = 0 ;    /* Position in InDecimal     */
341   boolean  _End  = false ;/* =TRUE  when number has been proceed             */
342                           /* =FALSE else                                     */
343   boolean  High  = false ;/* =TRUE when on high nibble                       */
344                           /* =FALSE when on low nibble                       */
345                           /* of pIndecimal PACKED STRING                     */
346   boolean  Significant = false ; /* Bypass leading non significant 0         */
347   byte     Digit;         /* extracted pIndecimal[IIn]                       */
348   int      NbDigit ; /* number of proceed digit                         */
349   boolean  EvenNbDigits ; /* True if number of digits in Dec number is even */
350   boolean  InDecimalPart = false   ;
351   String   Sign = new String("")   ;
352 
353   /* Logical Data Length */
354   Logical_Length = _IntSize + _DecSize ; /* Len = Number of digits + Sign */
355   EvenNbDigits   = ( ( Logical_Length % 2 ) == 0 ) ;
356   Logical_Length++ ;
357   Logical_Length += 2 ;   /* Reserve space for '0.' if needed */
358 
359   if ( _DecSize != 0 )
360     InDecimalPart = true ;
361 
362   Sign_Location = IOut;           /* Save Sign Position */
363   IOut++;
364 
365   char OutStrDecimal[] = new char[MAX_DECIMAL_STRING_SIZE] ;
366 
367   if ( _IntSize == 0 )
368   {
369      OutStrDecimal[IOut++]='0';
370      OutStrDecimal[IOut++]= '.';
371   }
372 
373   NbDigit=0;
374 
375   if ( EvenNbDigits )
376      High = true ; /* BYPASS High padding nibble */
377 
378   while ( ! _End )
379   {
380      High =  ! High ;
381 
382      if ( High )
383      {
384        Digit=  BYTEFX.HINIBBLE( _Struct[IIn]);
385      }
386      else
387      {
388        Digit=  BYTEFX.LOWNIBBLE(_Struct[IIn]);
389        IIn++;
390      }
391 
392      NbDigit++;
393      switch (Digit)
394      {
395         case CBL_SIGN_POS1 :
396         case CBL_SIGN_POS2 :
397         case CBL_SIGN_POS3 :
398         case CBL_SIGN_POS4 :
399           // Starting a positive number by '+' leads to
400           // number format exceptions when building BigDecimal from
401           // decimal string number so no leading sign is implicit '+'
402           _End = true ;
403           break;
404 
405   case 0 :
406   case 1 :
407         case 2 :
408         case 3 :
409         case 4 :
410         case 5 :
411         case 6 :
412         case 7 :
413         case 8 :
414         case 9 :
415           if ( ( Digit != 0 ) || ( Significant ) )
416           {
417             Significant = true ; /* Anyway all incoming 0 will be significant */
418             OutStrDecimal[IOut++] = (char)(
419                                      BYTEFX.MAKEBYTE( Digit ,
420                                      BYTEFX.HINIBBLE(ASCII_HIGH_CHAR_NIBBLE)
421                                                     )
422                                           ) ;
423             if (  (  NbDigit == _IntSize  ) &&
424                   ( _DecSize != 0 )
425                )
426       {
427               OutStrDecimal[IOut++] = '.';
428               InDecimalPart = false ;
429        }
430           }
431           break ;
432 
433         default   :
434           Sign = new String("-") ;  /* Set Negative */
435           _End = true ;
436           break ;
437 
438 
439      } /* switch */
440   } /* while */
441 
442   // A ZERO VALUE packed Decimal
443   if ( ! Significant )
444     return( new String("0") ) ;
445 
446   if ( InDecimalPart ) // 0.9999 case with non null integer part defined
447                        // in cobol pic 9(9)V99
448     return(  Sign +  (new String("0.")) + (new String(OutStrDecimal)).trim() ) ;
449   else
450   {
451     if ( Sign.length() != 0 )
452     { // Should be a negative number with leading '-'
453       OutStrDecimal[Sign_Location] = Sign.charAt(0) ;
454       return( new String(OutStrDecimal) ) ;
455     }
456     else // Positive number with leading blank
457       return (new String(OutStrDecimal)).trim() ;
458   }
459 }
460 
461 
462 /**
463   Just use the main method for Class unit testing
464 */
465 public static void main ( String Argv[] )
466 {
467 
468   try
469   {
470     PackedDecimal MyPacked = new PackedDecimal( new byte[10] , 0 , 10 ,2 ) ;
471     MyPacked.toPackedDecimal("0.3542") ;
472     System.out.println(  " Decimal value is : "  + MyPacked.toString() ) ;
473 
474     PackedDecimal MyPacked1 = new PackedDecimal( new byte[10] , 0 , 3 , 3 ) ;
475     MyPacked1.toPackedDecimal("1543.2545") ;
476     System.out.println(  " Decimal value is : "  + MyPacked1.toString() ) ;
477 
478     PackedDecimal MyPacked2 = new PackedDecimal( new byte[10] , 0 , 10 ,2 ) ;
479     MyPacked2.toPackedDecimal("3.2") ;
480     System.out.println(  " Decimal value is : "  + MyPacked2.toString() ) ;
481 
482     long StartTime = System.currentTimeMillis() ;
483 
484     for ( int Ii = 0 ; Ii < 1000 ; Ii++ ) ;
485     {
486       MyPacked = new PackedDecimal( new byte[10] , 0 , 10 ,2 ) ;
487       MyPacked.toPackedDecimal("412") ;
488     }
489     long Elapsed = System.currentTimeMillis() - StartTime ;
490 
491     System.out.println(  " Decimal value is : "  + MyPacked.toString() ) ;
492 
493     System.out.println( "Loop Elapsed in : " + Elapsed ) ;
494 
495   }  catch ( NumberFormatException e )
496   { System.out.println(" Error : " + e ) ; }
497 
498 }
499 
500 }