@@ -5,46 +5,39 @@ This Source Code Form is subject to the terms of the
55at http://mozilla.org/MPL/2.0/.
66----------------------------------------------------------*/
77
8- using System ;
9- using System . IO ;
10- using System . Security . Cryptography ;
11- using System . Text ;
128using OneScript . Contexts ;
139using OneScript . Exceptions ;
1410using OneScript . StandardLibrary . Binary ;
1511using OneScript . Values ;
1612using ScriptEngine . Machine ;
1713using ScriptEngine . Machine . Contexts ;
14+ using System ;
15+ using System . IO ;
16+ using System . Security . Cryptography ;
17+ using System . Text ;
1818
1919namespace OneScript . StandardLibrary . Hash
20- {
20+ {
2121 [ ContextClass ( "ХешированиеДанных" , "DataHashing" ) ]
22- public class HashImpl : AutoContext < HashImpl > , IDisposable
23- {
24- private HashAlgorithm _provider ;
25- private HashFunctionEnum _enumValue ;
26- private CombinedStream _toCalculate = new CombinedStream ( ) ;
22+ public class HashImpl : AutoContext < HashImpl >
23+ {
24+ private const int BUFFER_SIZE = ( 1024 * 32 ) ;
25+
26+ private readonly Crc32 _crc32 ;
27+ private readonly IncrementalHash _provider ;
28+ private readonly HashFunctionEnum _enumValue ;
2729 private bool _calculated ;
2830 private byte [ ] _hash ;
2931
30- public HashImpl ( HashAlgorithm provider , HashFunctionEnum enumValue )
32+ public HashImpl ( IncrementalHash provider , HashFunctionEnum enumValue )
3133 {
3234 _provider = provider ;
3335 _enumValue = enumValue ;
3436 _calculated = false ;
35- }
36-
37- public byte [ ] InternalHash
38- {
39- get
40- {
41- if ( ! _calculated )
42- {
43- _hash = _provider . ComputeHash ( _toCalculate ) ;
44- _calculated = true ;
45- }
46- return _hash ;
47- }
37+ if ( enumValue == HashFunctionEnum . CRC32 || provider == null )
38+ {
39+ _crc32 = new Crc32 ( ) ;
40+ }
4841 }
4942
5043 [ ContextProperty ( "ХешФункция" , "HashFunction" ) ]
@@ -55,52 +48,100 @@ public IValue Hash
5548 {
5649 get
5750 {
58- if ( _provider is Crc32 )
59- {
60- var buffer = new byte [ 4 ] ;
61- Array . Copy ( InternalHash , buffer , 4 ) ;
62- if ( BitConverter . IsLittleEndian )
63- Array . Reverse ( buffer ) ;
64- var ret = BitConverter . ToUInt32 ( buffer , 0 ) ;
65- return ValueFactory . Create ( ( decimal ) ret ) ;
66- }
67- return new BinaryDataContext ( InternalHash ) ;
51+ if ( ! _calculated )
52+ return ValueFactory . Create ( 0 ) ;
53+
54+ if ( _crc32 != null )
55+ return ValueFactory . Create ( _crc32 . GetCurrentHashAsUInt32 ( ) ) ;
56+
57+ return new BinaryDataContext ( _hash ) ;
6858 }
6959 }
7060
7161 [ ContextProperty ( "ХешСуммаСтрокой" , "HashSumOfString" ) ]
7262 public string HashString
7363 {
7464 get
75- {
65+ {
66+ if ( _crc32 != null )
67+ return _crc32 . GetCurrentHashAsUInt32 ( ) . ToString ( "X8" ) ;
68+
7669 var sb = new StringBuilder ( ) ;
77- for ( int i = 0 ; i < InternalHash . Length ; i ++ )
78- sb . Append ( InternalHash [ i ] . ToString ( "X2" ) ) ;
70+ for ( int i = 0 ; i < _hash . Length ; i ++ )
71+ sb . Append ( _hash [ i ] . ToString ( "X2" ) ) ;
7972 return sb . ToString ( ) ;
8073 }
8174 }
8275
76+ private void AppendData ( byte [ ] data )
77+ {
78+ AppendData ( data , data . Length ) ;
79+ }
80+
81+ private void AppendData ( byte [ ] data , int count )
82+ {
83+ if ( _crc32 != null )
84+ {
85+ _crc32 . AppendData ( data , 0 , count ) ;
86+ }
87+ else
88+ {
89+ _provider . AppendData ( data , 0 , count ) ;
90+ _hash = _provider . GetCurrentHash ( ) ;
91+ }
92+
93+ _calculated = true ;
94+ }
95+
96+ private void AppendStream ( Stream stream )
97+ {
98+ var buffer = new byte [ BUFFER_SIZE ] ;
99+ while ( true )
100+ {
101+ var read = stream . Read ( buffer , 0 , BUFFER_SIZE ) ;
102+ if ( read == 0 )
103+ break ;
104+
105+ AppendData ( buffer , read ) ;
106+ }
107+ }
108+
109+ private void AppendStream ( Stream stream , int count )
110+ {
111+ int bufSize = Math . Min ( BUFFER_SIZE , count ) ;
112+ var buffer = new byte [ bufSize ] ;
113+ int toRead = count ;
114+ while ( toRead > 0 )
115+ {
116+ var read = stream . Read ( buffer , 0 , Math . Min ( toRead , bufSize ) ) ;
117+ if ( read == 0 )
118+ break ;
119+
120+ AppendData ( buffer , read ) ;
121+ toRead -= read ;
122+ }
123+ }
83124
84125 [ ContextMethod ( "Добавить" , "Append" ) ]
85- public void Append ( BslValue toAdd , uint count = 0 )
126+ public void Append ( BslValue toAdd , int count = 0 )
86127 {
87128 switch ( toAdd )
88129 {
89130 case BslStringValue s :
90- AddStream ( new MemoryStream ( Encoding . UTF8 . GetBytes ( ( string ) s ) ) ) ;
131+ AppendData ( Encoding . UTF8 . GetBytes ( ( string ) s ) ) ;
91132 break ;
92- case BslObjectValue obj when obj is IStreamWrapper wrapper :
133+ case IStreamWrapper wrapper :
93134 var stream = wrapper . GetUnderlyingStream ( ) ;
94- var readByte = ( int ) Math . Min ( count == 0 ? stream . Length : count , stream . Length - stream . Position ) ;
95- var buffer = new byte [ readByte ] ;
96- stream . Read ( buffer , 0 , readByte ) ;
97- AddStream ( new MemoryStream ( buffer ) ) ;
135+ if ( count == 0 )
136+ AppendStream ( stream ) ;
137+ else
138+ AppendStream ( stream , count ) ;
98139 break ;
99- case BslObjectValue obj when obj is BinaryDataContext binaryData :
100- AddStream ( binaryData . GetStream ( ) ) ;
140+ case BinaryDataContext binaryData :
141+ AppendStream ( binaryData . GetStream ( ) ) ;
101142 break ;
102143 default :
103- throw RuntimeException . InvalidArgumentType ( nameof ( toAdd ) ) ;
144+ throw RuntimeException . InvalidNthArgumentType ( 1 ) ;
104145 }
105146 }
106147
@@ -109,52 +150,33 @@ public void AppendFile(string path)
109150 {
110151 if ( ! File . Exists ( path ) )
111152 throw RuntimeException . InvalidArgumentType ( ) ;
112- AddStream ( new FileStream ( path , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) ) ;
153+ var stream = new FileStream ( path , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) ;
154+ AppendStream ( stream ) ;
155+ stream . Close ( ) ;
113156 }
114157
115- [ ContextMethod ( "Очистить" , "Clear" ) ]
116- public void Clear ( )
117- {
118- _toCalculate . Close ( ) ;
119- _toCalculate . Dispose ( ) ;
120- _toCalculate = new CombinedStream ( ) ;
121- _calculated = false ;
122- }
123-
124-
125158 [ ScriptConstructor ( Name = "По указанной хеш-функции" ) ]
126159 public static HashImpl Constructor ( HashFunctionEnum providerEnum )
127- {
128- var objectProvider = GetProvider ( providerEnum ) ;
160+ {
161+ if ( providerEnum == HashFunctionEnum . CRC32 )
162+ return new HashImpl ( null , providerEnum ) ;
163+
164+ var objectProvider = IncrementalHash . CreateHash ( GetAlgorithmName ( providerEnum ) ) ;
129165 return new HashImpl ( objectProvider , providerEnum ) ;
130166 }
131167
132- private static HashAlgorithm GetProvider ( HashFunctionEnum algo )
168+ private static HashAlgorithmName GetAlgorithmName ( HashFunctionEnum algo )
133169 {
134- switch ( algo )
135- {
136- case HashFunctionEnum . CRC32 :
137- return new Crc32 ( ) ;
138- default :
139- var ret = HashAlgorithm . Create ( algo . ToString ( ) ) ;
140- if ( ret == null )
141- throw RuntimeException . InvalidArgumentType ( ) ;
142- return ret ;
143- }
170+ return algo switch
171+ {
172+ HashFunctionEnum . MD5 => HashAlgorithmName . MD5 ,
173+ HashFunctionEnum . SHA1 => HashAlgorithmName . SHA1 ,
174+ HashFunctionEnum . SHA256 => HashAlgorithmName . SHA256 ,
175+ HashFunctionEnum . SHA384 => HashAlgorithmName . SHA384 ,
176+ HashFunctionEnum . SHA512 => HashAlgorithmName . SHA512 ,
177+ _ => throw RuntimeException . InvalidArgumentValue ( )
178+ } ;
144179 }
145180
146- public void Dispose ( )
147- {
148- _toCalculate . Close ( ) ;
149- _toCalculate . Dispose ( ) ;
150- }
151-
152- private void AddStream ( Stream stream )
153- {
154- _toCalculate . AddStream ( stream ) ;
155- _toCalculate . Seek ( 0 , SeekOrigin . Begin ) ;
156- _calculated = false ;
157-
158- }
159181 }
160182}
0 commit comments