Ascii85 Algorithm

Ascii85 use five ASCII characters to represent four bytes of binary data (encoded size 25% larger), it is more efficient than Base64, which use four characters to represent three bytes of data (33% increase). This encode method is suitable for posting small blocks of binary data to BBS or forum as plain text. It is also used in Portable Document Format. I implemented this algoritm in C# when doing my PDF processor project. You can find more description about ASCII85 in Wikipedia.

 

The code
     ///   <summary>
    
///  Adobe ASCII85 for encoding binary data in ASCII base-85
    
///   </summary>
     public   class  ASCII85
    {
        
///   <summary>
        
///  Maximum line length for encoded ASCII85 string; 
        
///  set to zero for one unbroken line.
        
///   </summary>
         public   static   int  LineLength  =   75 ;

        
static   uint [] pow85  =  {  85   *   85   *   85   *   85 85   *   85   *   85 85   *   85 85 1  };

        
///   <summary>
        
///  Encodes binary data into a plaintext ASCII85 format string
        
///   </summary>
        
///   <param name="data"> binary data to encode </param>
        
///   <returns> ASCII85 encoded string </returns>
         public   static   string  Encode( byte [] data)
        {
            MemoryStream input 
=   new  MemoryStream(data);
            MemoryStream output 
=   new  MemoryStream();
            Encode(input, output);
            output.Position 
=   0 ;
            StreamReader reader 
=   new  StreamReader(output, Encoding.ASCII);
            
return  reader.ReadToEnd();
        }

        
///   <summary>
        
///  Decodes an ASCII85 encoded string into the original binary data
        
///   </summary>
        
///   <param name="code"> ASCII85 encoded string </param>
        
///   <returns> byte array of decoded binary data </returns>
         public   static   byte [] Decode( string  code)
        {
            MemoryStream input 
=   new  MemoryStream(Encoding.ASCII.GetBytes(code));
            MemoryStream output 
=   new  MemoryStream();
            Decode(input, output);
            
return  output.ToArray();
        }

        
///   <summary>
        
///  Encodes the specified input.
        
///   </summary>
        
///   <param name="input"> The input. </param>
        
///   <param name="output"> The output. </param>
         public   static   void  Encode(Stream input, Stream output)
        {
            StreamWriter writer 
=   new  StreamWriter(output, Encoding.ASCII);
            
uint  word  =   0 ;
            
int  count  =   0 ;
            
int  linepos  =   0 ;
            
int  code  =  input.ReadByte();
            
while  (code  !=   - 1 )
            {
                word 
|=  ( uint )(code  <<  ( 24   -  (count  *   8 )));
                count
++ ;
                
if  (count  ==   4 )
                {
                    
if  (word  ==   0 )
                    {
                        writer.Write(
' z ' );
                        linepos
++ ;
                    }
                    
else
                    {
                        writer.Write(Encode(word));
                        linepos 
+=   5 ;
                    }
                    word 
=   0 ;
                    count 
=   0 ;
                }
                
if  (linepos  >=  LineLength)
                {
                    writer.WriteLine();
                    linepos 
=   0 ;
                }
                code 
=  input.ReadByte();
            }
            
if  (count  >   0 )
            {
                writer.Write(Encode(word), 
0 , count  +   1 );
            }
            writer.Write(
" ~> " );
            writer.Flush();
        }

        
private   static   char [] Encode( uint  word)
        {
            
char [] group  =   new   char [ 5 ];
            
for  ( int  i  =  group.Length  -   1 ; i  >=   0 ; i -- )
            {
                group[i] 
=  ( char )(word  %   85   +   33 );
                word 
/=   85 ;
            }
            
return  group;
        }

        
///   <summary>
        
///  Decodes the specified input.
        
///   </summary>
        
///   <param name="input"> The input. </param>
        
///   <param name="output"> The output. </param>
         public   static   void  Decode(Stream input, Stream output)
        {
            BinaryWriter writer 
=   new  BinaryWriter(output);
            
uint  word  =   0 ;
            
int  count  =   0 ;
            
int  code  =  input.ReadByte();
            
while  (code  !=   - 1 )
            {
                
if  (code  ==   122 //  'z'
                {
                    
if  (count  ==   0 )
                    {
                        writer.Write((
uint ) 0 );
                    }
                    
else
                    {
                        
throw   new  Exception( " A z character occurs in the middle of a group. " );
                    }
                }
                
else   if  (code  >=   33   &&  code  <=   117 )
                {
                    word 
+=  ( uint )((code  -   33 *  pow85[count]);
                    count
++ ;
                    
if  (count  ==   5 )
                    {
                        writer.Write(Word2Bytes(word));
                        word 
=   0 ;
                        count 
=   0 ;
                    }
                }
                
else
                {
                    
switch  (code)
                    {
                        
case   0 :
                        
case   9 :   //  HT
                         case   10 //  LF
                         case   11 //  VT
                         case   12 //  FF
                         case   13 //  CR
                         case   32 //  SP
                             break ;
                        
case   126 //  ~>
                             goto  end;
                        
default :
                            
throw   new  Exception( " Invalid character in ASCII85Decode: "   +  code);
                    }
                }
                code 
=  input.ReadByte();
            }
        end:
            
if  (count  >   0 )
            {
                count
-- ;
                word 
+=  pow85[count];  //  add maximum remained value
                writer.Write(Word2Bytes(word),  0 , count);
            }
            writer.Flush();
        }

        
///   <summary>
        
///  split uint32 into bytes by big-endian order
        
///   </summary>
        
///   <param name="word"></param>
        
///   <returns></returns>
         static   byte [] Word2Bytes( uint  word)
        {
            
byte [] bytes  =   new   byte [ 4 ];
            bytes[
0 =  ( byte )((word  &   0xFF000000 >>   24 );
            bytes[
1 =  ( byte )((word  &   0x00FF0000 >>   16 );
            bytes[
2 =  ( byte )((word  &   0x0000FF00 >>   8 );
            bytes[
3 =  ( byte )(word  &   0x000000FF );
            
return  bytes;
        }
    }

 

 

 

你可能感兴趣的:(Algorithm)